{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"*references*\n- [https://www.kaggle.com/ayuraj/train-covid-19-detection-using-yolov5](https://www.kaggle.com/ayuraj/train-covid-19-detection-using-yolov5)","metadata":{}},{"cell_type":"markdown","source":"- input 이미지의 bbox 영역을 사용해서 chest의 opacity 영역을 찾아내는 것.","metadata":{}},{"cell_type":"markdown","source":"## Import and setup\n- YOLOv5는 확실한 directory structure을 필요로함.\n\n*references*\n- [https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)","metadata":{}},{"cell_type":"markdown","source":"```\n/parent_folder\n    /dataset\n         /images\n         /labels\n    /yolov5\n```","metadata":{}},{"cell_type":"code","source":"%cd ../\n!mkdir tmp1\n%cd tmp1","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:25:46.465399Z","iopub.execute_input":"2021-06-15T03:25:46.4658Z","iopub.status.idle":"2021-06-15T03:25:47.126874Z","shell.execute_reply.started":"2021-06-15T03:25:46.465685Z","shell.execute_reply":"2021-06-15T03:25:47.125962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# download YOLOv5\n!git clone https://github.com/ultralytics/yolov5\n%cd yolov5\n\n# install dependencies\n%pip install -qr requirements.txt\n\n%cd ../\nimport torch\nprint(f\"setup complete. Using torch {torch.__version__}({torch.cuda.get_device_properties(0).name if torch.cuda.is_available() else 'CPU'})\")","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:25:48.371998Z","iopub.execute_input":"2021-06-15T03:25:48.372349Z","iopub.status.idle":"2021-06-15T03:25:58.714461Z","shell.execute_reply.started":"2021-06-15T03:25:48.372314Z","shell.execute_reply":"2021-06-15T03:25:58.713536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# install wandb\n!pip install -q --upgrade wandb\n\n#login\nimport wandb\nfrom kaggle_secrets import UserSecretsClient\nuser_secrets = UserSecretsClient()\nsecret_value_0 = user_secrets.get_secret(\"mysecret\")\n\nwandb.login(key=secret_value_0)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:25:58.716269Z","iopub.execute_input":"2021-06-15T03:25:58.716608Z","iopub.status.idle":"2021-06-15T03:26:08.861507Z","shell.execute_reply.started":"2021-06-15T03:25:58.716566Z","shell.execute_reply":"2021-06-15T03:26:08.860659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport gc\nimport cv2\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom shutil import copyfile # src인 파일의 내용을(메타 데이터 없이) 이름이 dst인 파일에 복사하고 dst를 반환함\n# src, dst는 경로류 객체나 문자열로 지정된 경로 이름\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\n\n# iPython writefile Customize\nfrom IPython.core.magic import register_line_cell_magic\n\n@register_line_cell_magic\ndef writetemplate(line, cell):\n    with open(line, 'w') as f:\n        f.write(cell.format(**globals()))","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:26:08.8634Z","iopub.execute_input":"2021-06-15T03:26:08.86383Z","iopub.status.idle":"2021-06-15T03:26:09.833055Z","shell.execute_reply.started":"2021-06-15T03:26:08.863781Z","shell.execute_reply":"2021-06-15T03:26:09.83223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# hyper params\nTRAIN_PATH = 'input/siim-covid19-resized-to-256px-jpg/train/'\nIMG_SIZE = 256\nBATCH_SIZE = 16\nEPOCHS = 10","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:26:09.834449Z","iopub.execute_input":"2021-06-15T03:26:09.834868Z","iopub.status.idle":"2021-06-15T03:26:09.843145Z","shell.execute_reply.started":"2021-06-15T03:26:09.834828Z","shell.execute_reply":"2021-06-15T03:26:09.842223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare Dataset\n- train-valid split \n- /dataset folder 생성\n- 모델 훈련을 위한 data.yaml 파일 생성\n- yolo format에 요구되는 bbox 생성","metadata":{}},{"cell_type":"code","source":"#everything is done from /kaggle directory\n%cd ../\n\n#load image level csv file\ndf = pd.read_csv('input/siim-covid19-detection/train_image_level.csv')\n\n#modify values in the id column\ndf['id'] = df.apply(lambda row: row.id.split('_')[0], axis=1)\n# add absolute path\ndf['path']= df.apply(lambda row: TRAIN_PATH+row.id+'.jpg', axis=1)\n# get image level labels\ndf['image_level'] = df.apply(lambda row: row.label.split(' ')[0], axis=1)\n\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:27:51.830906Z","iopub.execute_input":"2021-06-15T03:27:51.831271Z","iopub.status.idle":"2021-06-15T03:27:52.155806Z","shell.execute_reply.started":"2021-06-15T03:27:51.831235Z","shell.execute_reply":"2021-06-15T03:27:52.154952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# load meta.csv file\n# ori dimentions are required to scale the bbox coordinates appropriately.\nmeta_df = pd.read_csv('input/siim-covid19-resized-to-256px-jpg/meta.csv')\nmeta_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:27:54.44303Z","iopub.execute_input":"2021-06-15T03:27:54.443409Z","iopub.status.idle":"2021-06-15T03:27:54.471466Z","shell.execute_reply.started":"2021-06-15T03:27:54.443376Z","shell.execute_reply":"2021-06-15T03:27:54.470579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_meta_df = meta_df.loc[meta_df.split=='train'] #split에서 test, train있는데 train인 것만 추출\ntrain_meta_df = train_meta_df.drop('split', axis=1)\ntrain_meta_df.columns=['id','dim0','dim1']\n\ntrain_meta_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:27:56.200659Z","iopub.execute_input":"2021-06-15T03:27:56.201027Z","iopub.status.idle":"2021-06-15T03:27:56.217406Z","shell.execute_reply.started":"2021-06-15T03:27:56.200994Z","shell.execute_reply":"2021-06-15T03:27:56.215996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# merge both the df\ndf = df.merge(train_meta_df, on='id', how='left') # 같은 id 기준으로 meta.df와 merge하는데 기존의 df는 다 포함\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:27:58.140216Z","iopub.execute_input":"2021-06-15T03:27:58.140556Z","iopub.status.idle":"2021-06-15T03:27:58.168368Z","shell.execute_reply.started":"2021-06-15T03:27:58.140523Z","shell.execute_reply":"2021-06-15T03:27:58.167598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train-validation split","metadata":{}},{"cell_type":"code","source":"#create train and validation split\n# stratify를 image_level로 함으로써 class 비율을 유지시킴 즉, 한쪽에 쏠려서 분배되는 것을 방지함 (성능차이나는 것을 방지)\ntrain_df, valid_df = train_test_split(df, test_size=0.2, random_state=42, stratify= df.image_level.values)\n\ntrain_df.loc[:, 'split'] = 'train'\nvalid_df.loc[:, 'split'] = 'valid'\n\ndf = pd.concat([train_df, valid_df])\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:27:59.844294Z","iopub.execute_input":"2021-06-15T03:27:59.844648Z","iopub.status.idle":"2021-06-15T03:27:59.885669Z","shell.execute_reply.started":"2021-06-15T03:27:59.844617Z","shell.execute_reply":"2021-06-15T03:27:59.884699Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.concat([train_df, valid_df]).reset_index(drop=True)\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:02.972649Z","iopub.execute_input":"2021-06-15T03:28:02.973006Z","iopub.status.idle":"2021-06-15T03:28:02.996621Z","shell.execute_reply.started":"2021-06-15T03:28:02.972973Z","shell.execute_reply":"2021-06-15T03:28:02.995859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Size of dataset: {len(df)}, training images: {len(train_df)}. validation images: {len(valid_df)}')","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:04.173418Z","iopub.execute_input":"2021-06-15T03:28:04.173768Z","iopub.status.idle":"2021-06-15T03:28:04.181283Z","shell.execute_reply.started":"2021-06-15T03:28:04.173729Z","shell.execute_reply":"2021-06-15T03:28:04.180401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare Required Folder Structure","metadata":{}},{"cell_type":"markdown","source":"```\n/parent_folder\n    /dataset\n         /images\n             /train\n             /val\n         /labels\n             /train\n             /val\n    /yolov5\n```","metadata":{}},{"cell_type":"code","source":"os.makedirs('tmp1/covid19/images/train', exist_ok=True)\nos.makedirs('tmp1/covid19/images/valid', exist_ok=True)\n\nos.makedirs('tmp1/covid19/labels/train', exist_ok=True)\nos.makedirs('tmp1/covid19/labels/valid', exist_ok=True)\n\n! ls tmp1/covid19/images","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:06.071512Z","iopub.execute_input":"2021-06-15T03:28:06.071853Z","iopub.status.idle":"2021-06-15T03:28:06.736573Z","shell.execute_reply.started":"2021-06-15T03:28:06.071819Z","shell.execute_reply":"2021-06-15T03:28:06.735663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 이미지들을 관련된 폴더로 split함\n# tqdm을 사용함으로써 반복문이 어디까지 진행되었는지 알 수 있음\nfor i in tqdm(range(len(df))):\n    row= df.loc[i]\n    if row.split == 'train':\n        copyfile(row.path, f'tmp1/covid19/images/train/{row.id}.jpg')\n    else:\n        copyfile(row.path, f'tmp1/covid19/images/valid/{row.id}.jpg')\n    ","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:08.190177Z","iopub.execute_input":"2021-06-15T03:28:08.190528Z","iopub.status.idle":"2021-06-15T03:28:32.876669Z","shell.execute_reply.started":"2021-06-15T03:28:08.190494Z","shell.execute_reply":"2021-06-15T03:28:32.875771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create .YAML file\n- 중요한 점\n- 각 이미지의 image-level은 opacity or none이다. 따라서 number of classes는 2로 한다. => nc =2\n- YOLOv5는 자동적으로 어떠한 bbox 좌표없이 이미지를 핸들링함\n- NOTE: data.yaml은 yolov5/data directory에 생성됨","metadata":{}},{"cell_type":"code","source":"# create .yaml file\nimport yaml\n\ndata_yaml= dict(\n    # 'optional'download command/URL\n    train='../covid19/images/train', # training image경로\n    val= '../covid19/images/valid',# validation image경로\n    nc=2, # image_level\n    names=['none','opacity']\n)\n\n# yolov5/data/directory에 만듬\nwith open('tmp1/yolov5/data/data.yaml','w') as outfile:\n    yaml.dump(data_yaml, outfile, default_flow_style=True)\n\n# cat이란 linux 명령어로 두개이상의 파일을 연결해서 출력할 때 사용 혹은 연결할 파일을 설정하지 않은 경우에는 쉽게 말해서 \"이 파일에 무슨 내용이 있는지 보여줘\"라는 뜻이다. \n%cat tmp1/yolov5/data/data.yaml","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:35.267967Z","iopub.execute_input":"2021-06-15T03:28:35.26834Z","iopub.status.idle":"2021-06-15T03:28:35.914273Z","shell.execute_reply.started":"2021-06-15T03:28:35.268306Z","shell.execute_reply":"2021-06-15T03:28:35.913299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare bbox coordinated for YOLOv5\n- 1개의 object 당 한개의 row\n- 각 row는 class (x_center, y_center, width, height) format이다.\n- box 좌표는 반드시 normalize된 xywh format이다(0-1). image width에서 x_center, width 그리고 image height에서 y_center, height를 나눔으로써 normalize된거 구함\n- class number은 0부터 ","metadata":{}},{"cell_type":"code","source":"df","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:39.072357Z","iopub.execute_input":"2021-06-15T03:28:39.072724Z","iopub.status.idle":"2021-06-15T03:28:39.096597Z","shell.execute_reply.started":"2021-06-15T03:28:39.07267Z","shell.execute_reply":"2021-06-15T03:28:39.095762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# label col의 row value를 분석하여 raw bbox를 가져옴\n# Ref: https://www.kaggle.com/yujiariyasu/plot-3positive-classes\n\n# label format \n# EX) opacity 1 139.94981 1345.84148 1541.7312000000002 2694.97368 opacity 1 2098.93353 1089.17739 3270.37518 2699.36111\ndef get_bbox(row):\n    bboxes=[]\n    bbox=[]\n    for i,l in enumerate(row.label.split(' ')):\n        if(i%6 ==0)|(i%6==1):\n            continue\n        bbox.append(float(l)) # 좌표가 존재하면 bbox에 float 형식으로 넣음\n        if i%6==5:\n            bboxes.append(bbox) \n            bbox=[]\n            \n    return bboxes\n\n# resized image의 사이즈에 따라 bbox scale 뜸\ndef scale_bbox(row, bboxes):\n    # get scaling factor\n    scale_x = IMG_SIZE/row.dim1 # 256을 orginal dimension x로 나눈 값 -> 즉 얼만큼의 비율로 감소or 증가되었는지 확인 가능! \n    scale_y = IMG_SIZE/row.dim0 # 256을 orginal dimension y로 나눈 값을 scale_x에 저장 \n    \n    scaled_bboxes=[]\n    for bbox in bboxes:\n        x= int(np.round(bbox[0]*scale_x, 4))\n        y = int(np.round(bbox[1]*scale_y, 4))\n        x1 = int(np.round(bbox[2]*(scale_x), 4))\n        y1= int(np.round(bbox[3]*scale_y, 4))\n        \n        scaled_bboxes.append([x,y,x1,y1]) # xmin, ymin, xmax, ymax\n    return scaled_bboxes\n\n# YOLO format에 bbox들을 변환\ndef get_yolo_format_bbox(img_w, img_h, bboxes):\n    yolo_boxes=[]\n    for bbox in bboxes:\n        w= bbox[2]-bbox[0] # xmax-xmin = 넓이\n        h= bbox[3]-bbox[1] # ymaz-ymin = 높이\n        xc= bbox[0] + int(np.round(w/2)) # xmin + width/2 = x_center\n        yc = bbox[1] + int(np.round(h/2)) # ymin + height/2\n        \n        yolo_boxes.append([xc/img_w, yc/img_h, w/img_w, h/img_h]) # yolo format인 x-center, y-center, width, height로!\n        \n    return yolo_boxes\n         ","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:39.702431Z","iopub.execute_input":"2021-06-15T03:28:39.702782Z","iopub.status.idle":"2021-06-15T03:28:39.713727Z","shell.execute_reply.started":"2021-06-15T03:28:39.702745Z","shell.execute_reply":"2021-06-15T03:28:39.712542Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# bbox를 위한 txt 파일 준비\nfor i in tqdm(range(len(df))):\n    row= df.loc[i]\n    # get image id\n    img_id= row.id\n    #get split\n    split= row.split\n    # get image-level label\n    label= row.image_level\n    \n    if row.split == 'train':\n        file_name=f'tmp1/covid19/labels/train/{row.id}.txt'\n    else:\n        file_name=f'tmp1/covid19/labels/valid/{row.id}.txt'\n    \n    if label=='opacity':\n        #get bboxes\n        bboxes= get_bbox(row)\n        scale_bboxes= scale_bbox(row, bboxes)\n        #format for yolov5\n        yolo_bboxes= get_yolo_format_bbox(IMG_SIZE, IMG_SIZE, scale_bboxes) # 256,256, scale_bboxes\n        \n        with open(file_name, 'w') as f:\n            for bbox in yolo_bboxes:\n                bbox= [1]+bbox\n                bbox = [str(i) for i in bbox]\n                bbox=' '.join(bbox)\n                f.write(bbox)\n                f.write('\\n')","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:40.598017Z","iopub.execute_input":"2021-06-15T03:28:40.598385Z","iopub.status.idle":"2021-06-15T03:28:43.262182Z","shell.execute_reply.started":"2021-06-15T03:28:40.59835Z","shell.execute_reply":"2021-06-15T03:28:43.261186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## train with wandb","metadata":{}},{"cell_type":"code","source":"%cd tmp1/yolov5/","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:45.173381Z","iopub.execute_input":"2021-06-15T03:28:45.173798Z","iopub.status.idle":"2021-06-15T03:28:45.186977Z","shell.execute_reply.started":"2021-06-15T03:28:45.173761Z","shell.execute_reply":"2021-06-15T03:28:45.18609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"```\n--img {IMG_SIZE} \\ # Input image size.\n--batch {BATCH_SIZE} \\ # Batch size\n--epochs {EPOCHS} \\ # Number of epochs\n--data data.yaml \\ # Configuration file\n--weights yolov5s.pt \\ # Model name\n--save_period 1\\ # Save model after interval\n--project kaggle-siim-covid # W&B project name\n```","metadata":{}},{"cell_type":"code","source":"!python train.py --img {IMG_SIZE} \\\n                 --batch {BATCH_SIZE} \\\n                 --epochs {EPOCHS} \\\n                 --data data.yaml \\\n                 --weights yolov5s.pt \\\n                 --save_period 1\\\n                 --project kaggle-siim-covid","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:28:47.141186Z","iopub.execute_input":"2021-06-15T03:28:47.141522Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_PATH = '/kaggle/input/siim-covid19-resized-to-256px-jpg/test/' # absolute path","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MODEL_PATH = 'kaggle-siim-covid/exp/weights/best.pt'","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:23:32.099075Z","iopub.execute_input":"2021-06-15T03:23:32.100718Z","iopub.status.idle":"2021-06-15T03:23:32.10774Z","shell.execute_reply.started":"2021-06-15T03:23:32.100692Z","shell.execute_reply":"2021-06-15T03:23:32.106776Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"```\n--weights {MODEL_PATH} \\ # path to the best model.\n--source {TEST_PATH} \\ # absolute path to the test images.\n--img {IMG_SIZE} \\ # Size of image\n--conf 0.281 \\ # Confidence threshold (default is 0.25)\n--iou-thres 0.5 \\ # IOU threshold (default is 0.45)\n--max-det 3 \\ # Number of detections per image (default is 1000) \n--save-txt \\ # Save predicted bounding box coordinates as txt files\n--save-conf # Save the confidence of prediction for each bounding box\n```","metadata":{}},{"cell_type":"code","source":"!python detect.py --weights {MODEL_PATH} \\\n                  --source {TEST_PATH} \\\n                  --img {IMG_SIZE} \\\n                  --conf 0.281 \\\n                  --iou-thres 0.5 \\\n                  --max-det 3 \\\n                  --save-txt \\\n                  --save-conf","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:23:32.111694Z","iopub.execute_input":"2021-06-15T03:23:32.112252Z","iopub.status.idle":"2021-06-15T03:23:39.733151Z","shell.execute_reply.started":"2021-06-15T03:23:32.112221Z","shell.execute_reply":"2021-06-15T03:23:39.73218Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"PRED_PATH = 'runs/detect/exp/labels'\n!ls {PRED_PATH}","metadata":{"execution":{"iopub.status.busy":"2021-06-15T03:23:39.734926Z","iopub.execute_input":"2021-06-15T03:23:39.735309Z","iopub.status.idle":"2021-06-15T03:23:40.36983Z","shell.execute_reply.started":"2021-06-15T03:23:39.735269Z","shell.execute_reply":"2021-06-15T03:23:40.368587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 예측한 좌표들을 visualize\n%cat runs/detect/exp/labels/87c51db67bf7.txt","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:51:12.805706Z","iopub.execute_input":"2021-06-15T01:51:12.806101Z","iopub.status.idle":"2021-06-15T01:51:13.448512Z","shell.execute_reply.started":"2021-06-15T01:51:12.806063Z","shell.execute_reply":"2021-06-15T01:51:13.447602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> 1 -> class id(opacity), and then (x_center, y_center, width, height) , 마지막 float은 confidence","metadata":{}},{"cell_type":"code","source":"prediction_files=os.listdir(PRED_PATH)\nprint('Number of test images predicted as opaque: ', len(prediction_files))","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:51:15.651432Z","iopub.execute_input":"2021-06-15T01:51:15.651822Z","iopub.status.idle":"2021-06-15T01:51:15.659427Z","shell.execute_reply.started":"2021-06-15T01:51:15.651768Z","shell.execute_reply":"2021-06-15T01:51:15.65845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# submission -> xmin, ymin, xmax, ymax\n# YOLOv5 -> x_center, y_center, width, height 를 반환\ndef correct_bbox_format(bboxes):\n    correct_bboxes = []\n    for b in bboxes:\n        xc, yc = int(np.round(b[0]*IMG_SIZE)), int(np.round(b[1]*IMG_SIZE))\n        w, h = int(np.round(b[2]*IMG_SIZE)), int(np.round(b[3]*IMG_SIZE))\n\n        xmin = xc - int(np.round(w/2))\n        xmax = xc + int(np.round(w/2))\n        ymin = yc - int(np.round(h/2))\n        ymax = yc + int(np.round(h/2))\n        \n        correct_bboxes.append([xmin, xmax, ymin, ymax])\n        \n    return correct_bboxes\n\n# inference 와 extract하는 동안 YOLOv5에 의해 만들어진 txt file을 읽음\n# confidence and bounding box coordinates.\ndef get_conf_bboxes(file_path):\n    confidence = []\n    bboxes = []\n    with open(file_path, 'r') as file:\n        for line in file:\n            preds = line.strip('\\n').split(' ')\n            preds = list(map(float, preds))\n            confidence.append(preds[-1])\n            bboxes.append(preds[1:-1])\n    return confidence, bboxes","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:51:18.496131Z","iopub.execute_input":"2021-06-15T01:51:18.49649Z","iopub.status.idle":"2021-06-15T01:51:18.50633Z","shell.execute_reply.started":"2021-06-15T01:51:18.496458Z","shell.execute_reply":"2021-06-15T01:51:18.505103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# submission file 읽기\nsub_df = pd.read_csv('/kaggle/input/siim-covid19-detection/sample_submission.csv')\nsub_df.tail()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:51:22.18184Z","iopub.execute_input":"2021-06-15T01:51:22.182172Z","iopub.status.idle":"2021-06-15T01:51:22.204572Z","shell.execute_reply.started":"2021-06-15T01:51:22.182141Z","shell.execute_reply":"2021-06-15T01:51:22.203327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# pred loop\npredictions = []\n\nfor i in tqdm(range(len(sub_df))):\n    row = sub_df.loc[i]\n    id_name = row.id.split('_')[0]\n    id_level = row.id.split('_')[-1]\n    \n    if id_level == 'study':\n        # do study-level classification\n        predictions.append(\"Negative 1 0 0 1 1\") # dummy prediction\n        \n    elif id_level == 'image':\n        # we can do image-level classification here.\n        # also we can rely on the object detector's classification head.\n        # for this example submisison we will use YOLO's classification head. \n        # since we already ran the inference we know which test images belong to opacity.\n        if f'{id_name}.txt' in prediction_files:\n            # opacity label\n            confidence, bboxes = get_conf_bboxes(f'{PRED_PATH}/{id_name}.txt')\n            bboxes = correct_bbox_format(bboxes)\n            pred_string = ''\n            for j, conf in enumerate(confidence):\n                pred_string += f'opacity {conf} ' + ' '.join(map(str, bboxes[j])) + ' '\n            predictions.append(pred_string[:-1]) \n        else:\n            predictions.append(\"None 1 0 0 1 1\")","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:51:24.165898Z","iopub.execute_input":"2021-06-15T01:51:24.166232Z","iopub.status.idle":"2021-06-15T01:51:24.593752Z","shell.execute_reply.started":"2021-06-15T01:51:24.166203Z","shell.execute_reply":"2021-06-15T01:51:24.592774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.chdir(\"/kaggle/working\")","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:51:31.693544Z","iopub.execute_input":"2021-06-15T01:51:31.693885Z","iopub.status.idle":"2021-06-15T01:51:31.700554Z","shell.execute_reply.started":"2021-06-15T01:51:31.693852Z","shell.execute_reply":"2021-06-15T01:51:31.699766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df['PredictionString'] = predictions\nsub_df.to_csv('submission1.csv', index=False)\nsub_df.tail()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:51:33.436282Z","iopub.execute_input":"2021-06-15T01:51:33.436607Z","iopub.status.idle":"2021-06-15T01:51:33.458051Z","shell.execute_reply.started":"2021-06-15T01:51:33.436578Z","shell.execute_reply":"2021-06-15T01:51:33.457111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}