{"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":"# 前言：\n**从零开始摸索COVID19比赛奥义,错误地方请随时指出。**\n\n我们是知识的搬运工，交流贴，目前还有很多不懂的，可随时交流。","metadata":{}},{"cell_type":"code","source":"!conda install gdcm -c conda-forge -y","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:36:52.416530Z","iopub.execute_input":"2021-06-15T01:36:52.416883Z","iopub.status.idle":"2021-06-15T01:37:54.848868Z","shell.execute_reply.started":"2021-06-15T01:36:52.416808Z","shell.execute_reply":"2021-06-15T01:37:54.847986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"! python -m pip install pillow","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:37:54.850521Z","iopub.execute_input":"2021-06-15T01:37:54.850856Z","iopub.status.idle":"2021-06-15T01:38:01.448630Z","shell.execute_reply.started":"2021-06-15T01:37:54.850811Z","shell.execute_reply":"2021-06-15T01:38:01.447706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport cv2\nimport os\nimport re\nimport pydicom\nimport warnings\nimport glob\nimport ast\nimport math\nimport wandb\nfrom PIL import Image\nimport albumentations as A\nimport torch\nfrom matplotlib import pyplot as plt\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nwarnings.filterwarnings(\"ignore\")","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-15T01:38:01.450779Z","iopub.execute_input":"2021-06-15T01:38:01.451128Z","iopub.status.idle":"2021-06-15T01:38:04.684161Z","shell.execute_reply.started":"2021-06-15T01:38:01.451093Z","shell.execute_reply":"2021-06-15T01:38:04.683331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def visualize(**images):\n    \"\"\"PLot images in one row.\"\"\"\n    n = len(images)\n    plt.figure(figsize=(16, 5))\n    for i, (name, image) in enumerate(images.items()):\n        plt.subplot(1, n, i + 1)\n        plt.xticks([])\n        plt.yticks([])\n        plt.title(' '.join(name.split('_')).title())\n        plt.imshow(image)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:04.686045Z","iopub.execute_input":"2021-06-15T01:38:04.686423Z","iopub.status.idle":"2021-06-15T01:38:04.692928Z","shell.execute_reply.started":"2021-06-15T01:38:04.686385Z","shell.execute_reply":"2021-06-15T01:38:04.691750Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DIR_INPUT = '../input/siim-covid19-detection/'\nDIR_TRAIN = '../input/siim-covid19-detection/train/'\nDIR_TEST = '../input/siim-covid19-detection/test/'","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:04.694343Z","iopub.execute_input":"2021-06-15T01:38:04.694900Z","iopub.status.idle":"2021-06-15T01:38:04.705805Z","shell.execute_reply.started":"2021-06-15T01:38:04.694844Z","shell.execute_reply":"2021-06-15T01:38:04.705041Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#study numbers\nlen(os.listdir(DIR_TRAIN)),len(os.listdir(DIR_TEST))","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:04.707085Z","iopub.execute_input":"2021-06-15T01:38:04.707498Z","iopub.status.idle":"2021-06-15T01:38:04.875961Z","shell.execute_reply.started":"2021-06-15T01:38:04.707467Z","shell.execute_reply":"2021-06-15T01:38:04.875188Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"测试结果中既包含study结果，也包含image结果。","metadata":{}},{"cell_type":"code","source":"sample_sub = pd.read_csv(DIR_INPUT+'sample_submission.csv')\nsample_sub = sample_sub.sort_values('id')\nprint(len(sample_sub))\nsample_sub.head(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:04.877203Z","iopub.execute_input":"2021-06-15T01:38:04.877587Z","iopub.status.idle":"2021-06-15T01:38:04.911974Z","shell.execute_reply.started":"2021-06-15T01:38:04.877551Z","shell.execute_reply":"2021-06-15T01:38:04.911227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**study,series,image,patients**对应关系： 一个患者（patient）可以做多次检查（study），一次检查包含多个检查部位（series），而每个检查部位都有一张或多张相应的影像图像（image）（https://blog.csdn.net/qq_38330148/article/details/107094334） \n\n训练集：共6334个图片，6054次检查。有部分单次检查存在多个图片（多个部位的照片），参考例子：测试集中的0847751da0f7号检查。","metadata":{}},{"cell_type":"code","source":"image_lel = pd.read_csv(DIR_INPUT+'train_image_level.csv')\nimage_lel = image_lel.sort_values('StudyInstanceUID')\nprint('image,',len(image_lel))\nprint('study,',len(image_lel['StudyInstanceUID'].unique()))\nimage_lel.head(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:04.914752Z","iopub.execute_input":"2021-06-15T01:38:04.915007Z","iopub.status.idle":"2021-06-15T01:38:04.970763Z","shell.execute_reply.started":"2021-06-15T01:38:04.914983Z","shell.execute_reply":"2021-06-15T01:38:04.970012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**图像角度研究：图像有无异常情况**\n\nopacity: 肺内磨玻璃密度影。\n\n肺内磨玻璃密度影(ground—glass opacity，GGO)是指高分辨率CT(high—resolution CT，HRCT)图像上表现为密度轻度增加，但其内的支气管血管束仍可显示，见于各种炎症、水肿、纤维化及肿瘤等病变。","metadata":{}},{"cell_type":"code","source":"#训练集label信息。\nlabel_type = dict()\nfor x in image_lel[['label']].iterrows():\n    label = x[1].values[0].split(' ')[0]\n    if label not in label_type:\n        label_type[label] = 0\n    label_type[label] += 1\nlabel_type","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:04.973811Z","iopub.execute_input":"2021-06-15T01:38:04.974056Z","iopub.status.idle":"2021-06-15T01:38:05.379440Z","shell.execute_reply.started":"2021-06-15T01:38:04.974032Z","shell.execute_reply":"2021-06-15T01:38:05.378628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**检查角度研究：犯了什么毛病。**\n\n四类：Negative for Pneumonia，Typical Appearance，Indeterminate Appearance，Atypical Appearance\n\n大概意思就是：没毛病，典型COVID19肺炎, 未确定的样式， 非典型COVID19肺炎样式\n\n我的理解：opacity说明图片发现了问题， 一个或多个图片综合诊断判断病人是否存在：典型COVID19肺炎, 未确定的样式， 非典型COVID19肺炎样式。 是否如此还需进一步发掘。","metadata":{}},{"cell_type":"code","source":"study_lel = pd.read_csv(DIR_INPUT+'train_study_level.csv')\nstudy_lel = study_lel.sort_values('id')\nprint(len(study_lel))\nstudy_lel.head(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:05.380850Z","iopub.execute_input":"2021-06-15T01:38:05.381199Z","iopub.status.idle":"2021-06-15T01:38:05.410125Z","shell.execute_reply.started":"2021-06-15T01:38:05.381162Z","shell.execute_reply":"2021-06-15T01:38:05.409248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 样本详情：\n\nBody Part Examined： 测试部位; Study Instance UID: Study编号； Series Instance UID： Series编号； SOP Instance UID： image编号； Patient's Sex： 患者性别； Patient ID： 患者编号\n","metadata":{}},{"cell_type":"code","source":"sample_id = \"../input/siim-covid19-detection/train/27f8616263ed/00eab0514ef6/7e4a4ef3ff9f.dcm\"\ndicom = pydicom.dcmread(sample_id)\ndicom","metadata":{"_kg_hide-output":false,"execution":{"iopub.status.busy":"2021-06-15T01:38:05.411324Z","iopub.execute_input":"2021-06-15T01:38:05.411655Z","iopub.status.idle":"2021-06-15T01:38:05.752586Z","shell.execute_reply.started":"2021-06-15T01:38:05.411621Z","shell.execute_reply":"2021-06-15T01:38:05.751604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(dicom.pixel_array, cmap='bone')\nprint(dicom.pixel_array.shape) #图片尺寸","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:05.753961Z","iopub.execute_input":"2021-06-15T01:38:05.754296Z","iopub.status.idle":"2021-06-15T01:38:07.628230Z","shell.execute_reply.started":"2021-06-15T01:38:05.754261Z","shell.execute_reply":"2021-06-15T01:38:07.627419Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_lel['boxes'][2498],image_lel['label'][2498]#image label","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:07.629291Z","iopub.execute_input":"2021-06-15T01:38:07.629648Z","iopub.status.idle":"2021-06-15T01:38:07.635800Z","shell.execute_reply.started":"2021-06-15T01:38:07.629614Z","shell.execute_reply":"2021-06-15T01:38:07.635029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_lel.head(2)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:07.637151Z","iopub.execute_input":"2021-06-15T01:38:07.637648Z","iopub.status.idle":"2021-06-15T01:38:07.657022Z","shell.execute_reply.started":"2021-06-15T01:38:07.637612Z","shell.execute_reply":"2021-06-15T01:38:07.656276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_lel['StudyInstanceUID'] = '-1'\ndef studylevel(x):\n    x['StudyInstanceUID'] = x['id'].split('_')[0]\n    return x\n\nstudy_lel = study_lel.apply(lambda x:studylevel(x), axis = 1)\nstudy_lel.head(2)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:07.658172Z","iopub.execute_input":"2021-06-15T01:38:07.658533Z","iopub.status.idle":"2021-06-15T01:38:08.192797Z","shell.execute_reply.started":"2021-06-15T01:38:07.658498Z","shell.execute_reply":"2021-06-15T01:38:08.191993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#检查有没有重复的study号\nflag = study_lel['StudyInstanceUID'].duplicated()\nflag.any()","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:08.194021Z","iopub.execute_input":"2021-06-15T01:38:08.194370Z","iopub.status.idle":"2021-06-15T01:38:08.202388Z","shell.execute_reply.started":"2021-06-15T01:38:08.194326Z","shell.execute_reply":"2021-06-15T01:38:08.201317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del study_lel['id']\ntrain_df = pd.merge(image_lel,study_lel,how='left',on='StudyInstanceUID')\ntrain_df.head(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:08.203711Z","iopub.execute_input":"2021-06-15T01:38:08.204240Z","iopub.status.idle":"2021-06-15T01:38:08.230026Z","shell.execute_reply.started":"2021-06-15T01:38:08.204198Z","shell.execute_reply":"2021-06-15T01:38:08.229183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for row in train_df.iterrows():\n    if row[1][0].split('_')[0] == '7e4a4ef3ff9f':\n        print(row)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:08.231284Z","iopub.execute_input":"2021-06-15T01:38:08.231650Z","iopub.status.idle":"2021-06-15T01:38:08.656984Z","shell.execute_reply.started":"2021-06-15T01:38:08.231615Z","shell.execute_reply":"2021-06-15T01:38:08.656150Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"一个生病的病人，不一定每张图片都能观察到症状。更有甚者，每张图片都没有问题，还被诊断有毛病。病人多次照片的原因，观察规律，大致判断为病人一次取图未检测到结果，重新再取图。","metadata":{}},{"cell_type":"code","source":"#查看单检查多图片的情况\ndup = train_df.groupby('StudyInstanceUID').count()>1\ndup = dup[dup['id'] == True].index\nrepeat_df = train_df[train_df['StudyInstanceUID'].isin(dup)]\nprint('重复检查的图片数量：',len(repeat_df))\nrepeat_df.head(6)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:56.973549Z","iopub.execute_input":"2021-06-15T01:38:56.974011Z","iopub.status.idle":"2021-06-15T01:38:57.016664Z","shell.execute_reply.started":"2021-06-15T01:38:56.973969Z","shell.execute_reply":"2021-06-15T01:38:57.015691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"code references: https://www.kaggle.com/andradaolteanu/siim-covid-19-box-detect-dcm-metadata","metadata":{}},{"cell_type":"code","source":"def fix_inverted_radiograms(data, img):\n    '''Fixes inverted radiograms - with PhotometricInterpretation == \"MONOCHROME1\"\n    data: the .dcm dataset\n    img: the .dcm pixel_array'''\n    \n    if data.PhotometricInterpretation == \"MONOCHROME1\":\n        img = np.amax(img) - img\n    \n    img = img - np.min(img)\n    img = img / np.max(img)\n    img = (img * 255).astype(np.uint8)\n    \n    return img\ndef get_image_metadata(study_id, df):\n    '''Returns the label and bounding boxes (if any)\n    for a speciffic study id.'''\n    \n    data = df[df[\"StudyInstanceUID\"] == study_id]\n    \n    if data[\"Negative for Pneumonia\"].values == 1:\n        label = \"negative_for_pneumonia\"\n    elif data[\"Typical Appearance\"].values == 1:\n        label = \"typical\"\n    elif data[\"Indeterminate Appearance\"].values == 1:\n        label = \"indeterminate\"\n    else:\n        label = \"atypical\"\n        \n    bbox = list(data[\"boxes\"].values)\n    \n    return label, bbox\ndef return_coords(box):\n    '''Returns coordinates from a bbox'''\n    # Get the list of dictionaries\n    box = ast.literal_eval(box)[0]\n    # Get the exact x and y coordinates\n    x1, y1, x2, y2 = box[\"x\"], box[\"y\"], box[\"x\"] + box[\"width\"], box[\"y\"] + box[\"height\"]\n    # Save coordinates\n    return (int(x1), int(y1), int(x2), int(y2))","metadata":{"_kg_hide-input":true,"_kg_hide-output":false,"execution":{"iopub.status.busy":"2021-06-15T01:38:57.018165Z","iopub.execute_input":"2021-06-15T01:38:57.018876Z","iopub.status.idle":"2021-06-15T01:38:57.028283Z","shell.execute_reply.started":"2021-06-15T01:38:57.018833Z","shell.execute_reply":"2021-06-15T01:38:57.027370Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_dcm_info(study_ids, df):\n    '''Show .dcm images along with description.'''\n    wandb_logs = []\n    \n    fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(21,10))\n\n    # Get .dcm paths\n    dcm_paths = [glob.glob(f\"../input/siim-covid19-detection/train/{study_id}/*/*\")[0]\n                 for study_id in study_ids]\n    datasets = [pydicom.dcmread(path) for path in dcm_paths]\n    images = [apply_voi_lut(dataset.pixel_array, dataset) for dataset in datasets]\n\n    # Loop through the information\n    for study_id, data, img, i in zip(study_ids, datasets, images, range(2*3)):\n        # Fix inverted images\n        img = fix_inverted_radiograms(data, img)\n\n        # Below function available in functions section ;)\n        label, bbox = get_image_metadata(study_id, df)\n        \n        # Check for bounding box and add if it's the case\n        try: \n            # For no bbox, the list is [nan]\n            no_box = math.isnan(bbox[0])\n            pass\n        except TypeError:\n            # Retrieve the bounding box\n            all_coords = []\n            for box in bbox:\n                all_coords.append(return_coords(box))\n\n            for (x1, y1, x2, y2) in all_coords:\n                cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 0), 15)\n                cv2.putText(img, label, (x1, y1-14), \n                            cv2.FONT_HERSHEY_SIMPLEX, 3, (0, 0, 0), 4)\n                \n        # Plot the image\n        x = i // 3\n        y = i % 3\n        \n        axes[x, y].imshow(img, cmap=\"bone\")\n        axes[x, y].set_title(f\"Label: {label} \\n Sex: {data.PatientSex} | Body Part: {data.BodyPartExamined}\", \n                  fontsize=14, weight='bold')\n        axes[x, y].axis('off');\n        \n        # Save to W&B\n        wandb_logs.append(wandb.Image(img, \n                                      caption=f\"Label: {label} \\n Sex: {data.PatientSex} | Body Part: {data.BodyPartExamined}\"))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-15T01:38:57.030283Z","iopub.execute_input":"2021-06-15T01:38:57.030894Z","iopub.status.idle":"2021-06-15T01:38:57.046215Z","shell.execute_reply.started":"2021-06-15T01:38:57.030858Z","shell.execute_reply":"2021-06-15T01:38:57.045352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"图像文件可视化观察","metadata":{}},{"cell_type":"code","source":"# 典型症状的样本图示\nshow_dcm_info(study_ids=[\"72044bb44d41\", \"5b65a69885b6\", \"6aa32e76f998\",\n                         \"c9ffe6312921\", \"082cafb03942\", \"d3e83031ebea\"], \n              df=train_df)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:38:57.048160Z","iopub.execute_input":"2021-06-15T01:38:57.048835Z","iopub.status.idle":"2021-06-15T01:39:20.523279Z","shell.execute_reply.started":"2021-06-15T01:38:57.048796Z","shell.execute_reply":"2021-06-15T01:39:20.522256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#非典型症状的样本图示\nshow_dcm_info(study_ids=[\"f807cd855d31\", \"8087e3bc0efe\", \"7249de10ed69\",\n                         \"e300a4e86207\", \"4bac6c7da8b8\", \"f2d30ac37f7b\"], \n              df=train_df)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:39:20.524751Z","iopub.execute_input":"2021-06-15T01:39:20.525105Z","iopub.status.idle":"2021-06-15T01:39:42.988328Z","shell.execute_reply.started":"2021-06-15T01:39:20.525064Z","shell.execute_reply":"2021-06-15T01:39:42.987252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#不确定症状的样本图示\nshow_dcm_info(study_ids=[\"b949689a9ef1\", \"fe7e6015560d\", \"feffa20fac13\",\n                         \"747483509d0e\", \"c70369caef91\", \"1e1b4b1b53cb\"], \n              df=train_df)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:39:42.989801Z","iopub.execute_input":"2021-06-15T01:39:42.990125Z","iopub.status.idle":"2021-06-15T01:40:09.289269Z","shell.execute_reply.started":"2021-06-15T01:39:42.990092Z","shell.execute_reply":"2021-06-15T01:40:09.288327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 无肺炎症状的样本图示\nshow_dcm_info(study_ids=[\"612ea5194007\", \"db14e640e037\", \"d4ab797396b4\",\n                         \"6ae8a88c4b0c\", \"b3cf474bee3b\", \"0ba55e5422ab\"], \n              df=train_df)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:09.290666Z","iopub.execute_input":"2021-06-15T01:40:09.290984Z","iopub.status.idle":"2021-06-15T01:40:21.792191Z","shell.execute_reply.started":"2021-06-15T01:40:09.290951Z","shell.execute_reply":"2021-06-15T01:40:21.791188Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 数据集","metadata":{}},{"cell_type":"code","source":"image_ids = train_df['id'].unique()\nvalid_ids = image_ids[-700:]\ntrain_ids = image_ids[:-700]\nlen(train_ids),len(valid_ids)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:21.794746Z","iopub.execute_input":"2021-06-15T01:40:21.795063Z","iopub.status.idle":"2021-06-15T01:40:21.805160Z","shell.execute_reply.started":"2021-06-15T01:40:21.795029Z","shell.execute_reply":"2021-06-15T01:40:21.804095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_df = train_df[train_df['id'].isin(valid_ids)]\ntrain_df = train_df[train_df['id'].isin(train_ids)]\nvalid_df.head(2)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:21.807471Z","iopub.execute_input":"2021-06-15T01:40:21.807853Z","iopub.status.idle":"2021-06-15T01:40:21.826329Z","shell.execute_reply.started":"2021-06-15T01:40:21.807814Z","shell.execute_reply":"2021-06-15T01:40:21.825263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader, Dataset","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:21.827827Z","iopub.execute_input":"2021-06-15T01:40:21.828189Z","iopub.status.idle":"2021-06-15T01:40:21.832285Z","shell.execute_reply.started":"2021-06-15T01:40:21.828153Z","shell.execute_reply":"2021-06-15T01:40:21.831340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"data_link: thanks to https://www.kaggle.com/xhlulu/siim-covid19-resized-to-256px-jpg","metadata":{}},{"cell_type":"code","source":"img = cv2.imread ('../input/siim-covid19-resized-to-256px-jpg/train/000a312787f2.jpg',1)\nimg.shape\nvisualize(\n    image = img,\n)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:21.833803Z","iopub.execute_input":"2021-06-15T01:40:21.834174Z","iopub.status.idle":"2021-06-15T01:40:21.939067Z","shell.execute_reply.started":"2021-06-15T01:40:21.834126Z","shell.execute_reply":"2021-06-15T01:40:21.938248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta = pd.read_csv('../input/siim-covid19-resized-to-256px-jpg/meta.csv')\nmeta.head()\n\nmeta_dict = dict()\nfor row in meta.iterrows():\n    meta_dict[row[1][0]] = [row[1][1]/256,row[1][2]/256]\n# meta_dict","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:21.940253Z","iopub.execute_input":"2021-06-15T01:40:21.940777Z","iopub.status.idle":"2021-06-15T01:40:22.485069Z","shell.execute_reply.started":"2021-06-15T01:40:21.940738Z","shell.execute_reply":"2021-06-15T01:40:22.484232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def img2tensor(img,dtype:np.dtype=np.float32): ## float 32/16\n    if img.ndim==2 : img = np.expand_dims(img,2)\n    img = np.transpose(img,(2,0,1))\n    return torch.from_numpy(img.astype(dtype, copy=False))\n\ndef get_bbox(img_id, box):\n    box_list= []\n    b_list = box.split(' ')\n    \n    for i in range(len(box.split(' '))//6):\n        box_list.append([float(b_list[i*6+2])/meta_dict[img_id][1], float(b_list[i*6+3])/meta_dict[img_id][0],\n                         float(b_list[i*6+4])/meta_dict[img_id][1], float(b_list[i*6+5])/meta_dict[img_id][0]])\n#         box_list.append([float(b_list[i*6+2])/meta_dict[img_id][0], float(b_list[i*6+3])/meta_dict[img_id][1],\n#                          float(b_list[i*6+4])/meta_dict[img_id][0], float(b_list[i*6+5])/meta_dict[img_id][1]])\n    return np.array(box_list).astype('float64')\n\ndef get_image(line):\n    # LINE 4,5,6,7 -> NP，TA，IA，AA\n    factors = line[2].split(' ')\n    \n    num = len(factors)//6\n    \n    return np.array([1 if factors[i*6]=='opacity' else 0 for i in range(num)])\n\n#     return np.array([[line[4], line[5], line[6], line[7],] for i in range(num)]).astype('int64')\n#     return np.array([i-4 for i in range(4,8) if line[i]==1 for j in range(num)]).astype('int64')\n","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:22.486376Z","iopub.execute_input":"2021-06-15T01:40:22.486736Z","iopub.status.idle":"2021-06-15T01:40:22.496465Z","shell.execute_reply.started":"2021-06-15T01:40:22.486698Z","shell.execute_reply":"2021-06-15T01:40:22.495535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.values[0]","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:22.497669Z","iopub.execute_input":"2021-06-15T01:40:22.498025Z","iopub.status.idle":"2021-06-15T01:40:22.515060Z","shell.execute_reply.started":"2021-06-15T01:40:22.497989Z","shell.execute_reply":"2021-06-15T01:40:22.514244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class COVID19Dataset(Dataset):\n    def __init__(self, df, pth, transforms=None):\n        super().__init__()\n        self.ids = df[\"id\"].unique()\n        self.df = df\n        self.pth = pth\n        self.transforms = transforms\n        \n    def __getitem__(self, index):\n        img_id = self.ids[index].split('_')[0]\n        img = cv2.imread (self.pth+img_id+'.jpg',1)\n        \n        line = self.df.values[index]\n        boxes = get_bbox(img_id, line[2])\n        image_labels = None\n        image_confid = None\n        image_labels = get_image(line)\n        \n        target = dict()\n        target['boxes'] = torch.from_numpy(boxes)\n        target['labels'] = torch.from_numpy(image_labels)\n#         target['study_confid'] = torch.from_numpy(study_labels.astype('float32'))\n        \n        return img2tensor(img/255), target\n\n    def __len__(self):\n        return self.ids.shape[0]\n        \n        \ntrain_dataset = COVID19Dataset(train_df,'../input/siim-covid19-resized-to-256px-jpg/train/', True)\n# valid_dataset = COVID19Dataset(valid_df, None)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:22.516285Z","iopub.execute_input":"2021-06-15T01:40:22.516814Z","iopub.status.idle":"2021-06-15T01:40:22.527183Z","shell.execute_reply.started":"2021-06-15T01:40:22.516776Z","shell.execute_reply":"2021-06-15T01:40:22.526230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x,y = train_dataset[0]\nx,y","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:22.528643Z","iopub.execute_input":"2021-06-15T01:40:22.529014Z","iopub.status.idle":"2021-06-15T01:40:22.621012Z","shell.execute_reply.started":"2021-06-15T01:40:22.528979Z","shell.execute_reply":"2021-06-15T01:40:22.620077Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 数据增强","metadata":{}},{"cell_type":"markdown","source":"# 模型","metadata":{}},{"cell_type":"markdown","source":"code references: https://www.kaggle.com/pestipeti/vinbigdata-fasterrcnn-pytorch-train/notebook","metadata":{}},{"cell_type":"code","source":"import torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:22.622268Z","iopub.execute_input":"2021-06-15T01:40:22.622618Z","iopub.status.idle":"2021-06-15T01:40:22.748636Z","shell.execute_reply.started":"2021-06-15T01:40:22.622582Z","shell.execute_reply":"2021-06-15T01:40:22.747883Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:22.749862Z","iopub.execute_input":"2021-06-15T01:40:22.750190Z","iopub.status.idle":"2021-06-15T01:40:29.109967Z","shell.execute_reply.started":"2021-06-15T01:40:22.750154Z","shell.execute_reply":"2021-06-15T01:40:29.109106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_classes = 2\nin_features = model.roi_heads.box_predictor.cls_score.in_features\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\ndevice","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:29.111519Z","iopub.execute_input":"2021-06-15T01:40:29.111866Z","iopub.status.idle":"2021-06-15T01:40:29.142587Z","shell.execute_reply.started":"2021-06-15T01:40:29.111829Z","shell.execute_reply":"2021-06-15T01:40:29.141755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = COVID19Dataset(train_df,'../input/siim-covid19-resized-to-256px-jpg/train/', True)\nvalid_dataset = COVID19Dataset(valid_df,'../input/siim-covid19-resized-to-256px-jpg/train/', True)\nlen(train_dataset), len(valid_dataset)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:29.143966Z","iopub.execute_input":"2021-06-15T01:40:29.144341Z","iopub.status.idle":"2021-06-15T01:40:29.190585Z","shell.execute_reply.started":"2021-06-15T01:40:29.144283Z","shell.execute_reply":"2021-06-15T01:40:29.189711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def collate_fn(batch):\n    return tuple(zip(*batch))\n\ntrain_data_loader = DataLoader(\n    train_dataset,\n    batch_size=10,\n    shuffle=True,\n    num_workers=4,\n    collate_fn=collate_fn\n)\n\nvalid_data_loader = DataLoader(\n    valid_dataset,\n    batch_size=10,\n    shuffle=False,\n    num_workers=4,\n    collate_fn=collate_fn\n)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:29.193537Z","iopub.execute_input":"2021-06-15T01:40:29.193816Z","iopub.status.idle":"2021-06-15T01:40:29.200574Z","shell.execute_reply.started":"2021-06-15T01:40:29.193791Z","shell.execute_reply":"2021-06-15T01:40:29.199727Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# number = 7\n# images, targets = next(iter(train_data_loader))\n# images = list(image.to(device) for image in images)\n# targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n# boxes = targets[number]['boxes'].cpu().numpy().astype(np.int32)\n# sample = images[number].permute(1,2,0).cpu().numpy()\n# fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\n# for box in boxes:\n#     cv2.rectangle(sample,\n#                   (box[0], box[1]),\n#                   (box[2], box[3]),\n#                   (0, 220, 0), 3)\n    \n# ax.set_axis_off()\n# ax.imshow(sample)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:29.201800Z","iopub.execute_input":"2021-06-15T01:40:29.202341Z","iopub.status.idle":"2021-06-15T01:40:29.214213Z","shell.execute_reply.started":"2021-06-15T01:40:29.202288Z","shell.execute_reply":"2021-06-15T01:40:29.213395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 训练","metadata":{}},{"cell_type":"code","source":"class Averager:\n    def __init__(self):\n        self.current_total = 0.0\n        self.iterations = 0.0\n\n    def send(self, value):\n        self.current_total += value\n        self.iterations += 1\n\n    @property\n    def value(self):\n        if self.iterations == 0:\n            return 0\n        else:\n            return 1.0 * self.current_total / self.iterations\n\n    def reset(self):\n        self.current_total = 0.0\n        self.iterations = 0.0","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:29.218063Z","iopub.execute_input":"2021-06-15T01:40:29.218387Z","iopub.status.idle":"2021-06-15T01:40:29.225948Z","shell.execute_reply.started":"2021-06-15T01:40:29.218347Z","shell.execute_reply":"2021-06-15T01:40:29.225155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.to(device)\nparams = [p for p in model.parameters() if p.requires_grad]\noptimizer = torch.optim.SGD(params, lr=0.005, momentum=0.9, weight_decay=0.0005)\nlr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.1)\nnum_epochs = 10","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:29.227749Z","iopub.execute_input":"2021-06-15T01:40:29.228227Z","iopub.status.idle":"2021-06-15T01:40:33.452814Z","shell.execute_reply.started":"2021-06-15T01:40:29.228170Z","shell.execute_reply":"2021-06-15T01:40:33.451952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss_hist = Averager()\nitr = 1\n\nfor epoch in range(num_epochs):\n    loss_hist.reset()\n    \n    print(f'epoch {epoch} starting ...')\n    for images, targets in train_data_loader:\n        \n        images_t = list(image.to(device) for image in images)\n        targets_t = [{k: v.to(device) for k, v in t.items()} for t in targets]\n        \n        loss_dict = model(images_t, targets_t)\n#         print(loss_dict)\n        losses = sum(loss for loss in loss_dict.values())\n        loss_value = losses.item()\n\n        loss_hist.send(loss_value)\n\n        optimizer.zero_grad()\n        losses.backward()\n        optimizer.step()\n        if itr % 100 == 0:\n            print(f\"Iteration #{itr} loss: {loss_hist.value}\")\n        itr += 1\n#         break\n    \n    # update the learning rate\n    if lr_scheduler is not None:\n        lr_scheduler.step()\n\n    print(f\"Epoch #{epoch} loss: {loss_hist.value}\")\n    print(\"Saving epoch's state...\")\n    torch.save(model.state_dict(), f\"model_state_epoch_{epoch}.pth\")\n    break","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:40:33.454173Z","iopub.execute_input":"2021-06-15T01:40:33.454534Z","iopub.status.idle":"2021-06-15T01:54:42.655565Z","shell.execute_reply.started":"2021-06-15T01:40:33.454499Z","shell.execute_reply":"2021-06-15T01:54:42.654522Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\nres = model([images_t[0]])\nres","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:54:42.660625Z","iopub.execute_input":"2021-06-15T01:54:42.662741Z","iopub.status.idle":"2021-06-15T01:54:42.772763Z","shell.execute_reply.started":"2021-06-15T01:54:42.662696Z","shell.execute_reply":"2021-06-15T01:54:42.771859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"targets_t[0]","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:54:42.777002Z","iopub.execute_input":"2021-06-15T01:54:42.779153Z","iopub.status.idle":"2021-06-15T01:54:42.790278Z","shell.execute_reply.started":"2021-06-15T01:54:42.779112Z","shell.execute_reply":"2021-06-15T01:54:42.789456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 预测结果","metadata":{}},{"cell_type":"code","source":"TH = 0.6\ndef clean_res(res, th):\n    for re in res:\n        i = 0\n        for i in range(len(re['scores'])):\n            if re['scores'][i] < th:\n                re['boxes'] = re['boxes'][:i]\n                re['labels'] = re['labels'][:i]\n                re['scores'] = re['scores'][:i]\n                break\n                \n        if i == 0:\n            re['boxes'] = torch.Tensor([[0,0,1,1]])\n            re['labels'] = torch.Tensor([0])\n            re['scores'] = torch.Tensor([1])\n    return res\n\ndef record(res, row, test_name):\n    PredictionString = ''\n    for i in range(len(res['labels'])):\n        if res['labels'][i] == 1:\n            PredictionString += 'opacity '\n            PredictionString += str(res['scores'][i].item()) + ' '\n            \n            for bx in range(len(res['boxes'][i])):\n                if bx%2 == 0:\n                    PredictionString += str(res['boxes'][i][bx].item()*meta_dict[test_name][1]) + ' '\n                else:\n                    PredictionString += str(res['boxes'][i][bx].item()*meta_dict[test_name][0]) + ' '\n        else:\n            PredictionString += 'none 1 0 0 1 1'\n            break\n    row['PredictionString'] = PredictionString\n    return row\n        \ndef predict(row):\n    test_type = row['id'].split('_')[1]\n    if test_type == 'study': return row\n        \n    test_name = row['id'].split('_')[0]\n    img = cv2.imread (test_path+test_name+'.jpg',1)\n    img = img2tensor(img/255)\n    img = img.to(device)\n    res = model([img])\n    res = clean_res(res, TH)\n    \n    row = record(res[0], row, test_name)\n    return row","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-15T01:54:42.795195Z","iopub.execute_input":"2021-06-15T01:54:42.797714Z","iopub.status.idle":"2021-06-15T01:54:42.817005Z","shell.execute_reply.started":"2021-06-15T01:54:42.797674Z","shell.execute_reply":"2021-06-15T01:54:42.815912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"number = 0\nimages = [images_t[0].cpu()]\ntargets = [targets_t[0]]\n\nimages = list(image.to(device) for image in images)\ntargets = [{k: v.to(device) for k, v in t.items()} for t in targets]\nboxes = targets[number]['boxes'].cpu().detach().numpy().astype(np.int32)\nsample = images[number].permute(1,2,0).cpu().numpy()\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in boxes:\n    cv2.rectangle(sample,\n                  (box[0], box[1]),\n                  (box[2], box[3]),\n                  (0, 220, 0), 3)\n    \nax.set_axis_off()\nax.imshow(sample)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:54:42.821472Z","iopub.execute_input":"2021-06-15T01:54:42.823955Z","iopub.status.idle":"2021-06-15T01:54:43.050754Z","shell.execute_reply.started":"2021-06-15T01:54:42.823915Z","shell.execute_reply":"2021-06-15T01:54:43.049839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"number = 0\nimages = [images_t[0].cpu()]\ntargets = clean_res(res, 0.6)\n\nimages = list(image.to(device) for image in images)\ntargets = [{k: v.to(device) for k, v in t.items()} for t in targets]\nboxes = targets[number]['boxes'].cpu().detach().numpy().astype(np.int32)\nsample = images[number].permute(1,2,0).cpu().numpy()\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in boxes:\n    cv2.rectangle(sample,\n                  (box[0], box[1]),\n                  (box[2], box[3]),\n                  (0, 220, 0), 3)\n    \nax.set_axis_off()\nax.imshow(sample)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:54:43.054664Z","iopub.execute_input":"2021-06-15T01:54:43.056701Z","iopub.status.idle":"2021-06-15T01:54:43.225994Z","shell.execute_reply.started":"2021-06-15T01:54:43.056658Z","shell.execute_reply":"2021-06-15T01:54:43.225065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model.eval()\nsample_sub = pd.read_csv('../input/siim-covid19-detection/sample_submission.csv')\ntest_path = '../input/siim-covid19-resized-to-256px-jpg/test/'\n\nsample_sub = sample_sub.apply(lambda x:predict(x), axis = 1)","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:54:43.227446Z","iopub.execute_input":"2021-06-15T01:54:43.227930Z","iopub.status.idle":"2021-06-15T01:56:20.280283Z","shell.execute_reply.started":"2021-06-15T01:54:43.227890Z","shell.execute_reply":"2021-06-15T01:56:20.279202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_sub.to_csv('submission.csv')","metadata":{"execution":{"iopub.status.busy":"2021-06-15T01:56:20.284598Z","iopub.execute_input":"2021-06-15T01:56:20.284945Z","iopub.status.idle":"2021-06-15T01:56:20.513867Z","shell.execute_reply.started":"2021-06-15T01:56:20.284912Z","shell.execute_reply":"2021-06-15T01:56:20.512960Z"},"trusted":true},"execution_count":null,"outputs":[]}]}