{"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":"# Mayo Clinic Baseline Resnet18\n\nthe data processing is based on https://www.kaggle.com/code/jirkaborovec/bloodclots-classif-baseline-flash-effnet","metadata":{}},{"cell_type":"code","source":"!pip uninstall -y torchtext\n# !pip install -q --upgrade torch torchvision\n!mkdir -p frozen_packages\n!cp ../input/starter-flash-semantic-segmentation/frozen_packages/* frozen_packages/\n!pip install -q \"lightning-flash[image]\" \"torchmetrics<0.8\" --no-index --find-links frozen_packages/\n!pip install -q -U timm --no-index --find-links frozen_packages/\n\n! pip list | grep -e torch -e lightning\n! nvidia-smi -L","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-21T08:52:01.905161Z","iopub.execute_input":"2022-07-21T08:52:01.905807Z","iopub.status.idle":"2022-07-21T08:53:19.266928Z","shell.execute_reply.started":"2022-07-21T08:52:01.905643Z","shell.execute_reply":"2022-07-21T08:53:19.265783Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q -U 'lightning-flash[image]'","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:53:19.269047Z","iopub.execute_input":"2022-07-21T08:53:19.269806Z","iopub.status.idle":"2022-07-21T08:55:56.530384Z","shell.execute_reply.started":"2022-07-21T08:53:19.269761Z","shell.execute_reply":"2022-07-21T08:55:56.529225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os, glob\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision.models as models\nimport flash\nfrom flash.image import ImageClassificationData, ImageClassifier\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-21T08:55:56.532348Z","iopub.execute_input":"2022-07-21T08:55:56.53275Z","iopub.status.idle":"2022-07-21T08:56:06.294844Z","shell.execute_reply.started":"2022-07-21T08:55:56.532695Z","shell.execute_reply":"2022-07-21T08:56:06.293508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#path\nDATASET_FOLDER = \"/kaggle/input/mayo-clinic-strip-ai/\"\nDATASET_SMALL_FOLDER = \"/kaggle/input/stroke-blood-clot-origin-1k-scale-bg-crop\"","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:56:06.298212Z","iopub.execute_input":"2022-07-21T08:56:06.299212Z","iopub.status.idle":"2022-07-21T08:56:06.304007Z","shell.execute_reply.started":"2022-07-21T08:56:06.299171Z","shell.execute_reply":"2022-07-21T08:56:06.303034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path_csv = os.path.join(DATASET_FOLDER, \"train.csv\")\ndf_train = pd.read_csv(path_csv)\ndisplay(df_train.head())\n","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:56:06.30768Z","iopub.execute_input":"2022-07-21T08:56:06.308012Z","iopub.status.idle":"2022-07-21T08:56:06.33837Z","shell.execute_reply.started":"2022-07-21T08:56:06.307987Z","shell.execute_reply":"2022-07-21T08:56:06.337513Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Converting test images\n\nthe image conversion is using https://www.kaggle.com/code/jirkaborovec/bloodclots-classif-eda-load-crop-images","metadata":{}},{"cell_type":"code","source":"from PIL import Image\n\nImage.MAX_IMAGE_PIXELS = 25_000_000_000\n\ndef prune_image_rows_cols(im, mask, thr=0.990):\n    # delete empty columns\n    for l in reversed(range(im.shape[1])):\n        if (np.sum(mask[:, l]) / float(mask.shape[0])) > thr:\n            im = np.delete(im, l, 1)\n    # delete empty rows\n    for l in reversed(range(im.shape[0])):\n        if (np.sum(mask[l, :]) / float(mask.shape[1])) > thr:\n            im = np.delete(im, l, 0)\n    return im\n\n\ndef mask_median(im, val=255):\n    masks = [None] * 3\n    for c in range(3):\n        masks[c] = im[..., c] >= np.median(im[:, :, c]) - 5\n    mask = np.logical_and(*masks)\n    im[mask, :] = val\n    return im, mask\n\n\ndef image_load_scale_norm(img_path, prune_thr=0.990, bg_val=255):\n    img = Image.open(img_path)\n    if (img.width * img.height) > 1_500_000_000:  # todo: for train images it was fine 4_000_000_000\n        print(img.width, img.height)\n        return None\n    scale = min(img.height / 2e3, img.width / 2e3)\n    tmp_size = int(img.width / scale), int(img.height / scale)\n    img.thumbnail(tmp_size, resample=Image.Resampling.BILINEAR, reducing_gap=scale)\n    im, mask = mask_median(np.array(img), val=bg_val)\n    im = prune_image_rows_cols(im, mask, thr=prune_thr)\n    img = Image.fromarray(im)\n    scale = min(img.height / 1e3, img.width / 1e3)\n    if scale > 1:\n        img = img.resize((int(img.width / scale), int(img.height / scale)), Image.LANCZOS)\n    return img","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-21T08:56:06.341496Z","iopub.execute_input":"2022-07-21T08:56:06.34283Z","iopub.status.idle":"2022-07-21T08:56:06.355811Z","shell.execute_reply.started":"2022-07-21T08:56:06.342795Z","shell.execute_reply":"2022-07-21T08:56:06.35477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\nfrom tqdm.auto import tqdm\n\nls_imgs_tif = glob.glob(os.path.join(DATASET_FOLDER, \"test\", \"*.tif\"))\nnames = [os.path.splitext(os.path.basename(p))[0] for p in ls_imgs_tif]\npatient_ids = set([n.split(\"_\")[0] for n in names])\nprint(patient_ids)\n\n! mkdir test_images\n\nfor img_path in tqdm(ls_imgs_tif):\n    name, _ = os.path.splitext(os.path.basename(img_path))\n    img = image_load_scale_norm(img_path)\n    if not img:\n        print(f\"missing: {name}\")\n        continue\n    img.save(os.path.join(\"test_images\", f\"{name}.png\"))\n    del img\n    gc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-21T08:56:06.358634Z","iopub.execute_input":"2022-07-21T08:56:06.359793Z","iopub.status.idle":"2022-07-21T08:58:19.254421Z","shell.execute_reply.started":"2022-07-21T08:56:06.35975Z","shell.execute_reply":"2022-07-21T08:58:19.253408Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1. Create the Data by DataModule\n","metadata":{}},{"cell_type":"code","source":"import shutil\n\n!mkdir -p /kaggle/temp/images/CE\n!mkdir -p /kaggle/temp/images/LAA\n\nfor _, row in df_train.iterrows():\n    p_img = os.path.join(DATASET_SMALL_FOLDER, \"train_images\", f\"{row['image_id']}.png\")\n    if not os.path.isfile(p_img):\n        print(f\"missing: {p_img}\")\n        continue\n    shutil.copy(p_img, os.path.join(\"/kaggle/temp/images\", row[\"label\"], f\"{row['image_id']}.png\"))","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-21T08:58:19.255806Z","iopub.execute_input":"2022-07-21T08:58:19.256982Z","iopub.status.idle":"2022-07-21T08:58:35.014895Z","shell.execute_reply.started":"2022-07-21T08:58:19.256943Z","shell.execute_reply":"2022-07-21T08:58:35.013756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRANSFORM_PARAMS = {\n    \"image_size\": (528, 528),\n    # \"mean\": (0.485, 0.456, 0.406), \"std\": (0.229, 0.224, 0.225),\n}\n\ndatamodule = ImageClassificationData.from_folders(\n    train_folder=\"/kaggle/temp/images\",\n    val_split=0.1,\n    batch_size=8,\n    transform_kwargs=TRANSFORM_PARAMS,\n    num_workers=2,\n) ","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:58:35.016735Z","iopub.execute_input":"2022-07-21T08:58:35.017163Z","iopub.status.idle":"2022-07-21T08:58:35.040733Z","shell.execute_reply.started":"2022-07-21T08:58:35.01712Z","shell.execute_reply":"2022-07-21T08:58:35.039766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. import models by torchvision\nA step-by-step model building and training can make you understand the process more easily","metadata":{}},{"cell_type":"code","source":"\nmodel = models.resnet18(pretrained=False) \ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\n# model = model.to(device)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T09:03:14.074406Z","iopub.execute_input":"2022-07-21T09:03:14.075487Z","iopub.status.idle":"2022-07-21T09:03:14.330834Z","shell.execute_reply.started":"2022-07-21T09:03:14.075438Z","shell.execute_reply":"2022-07-21T09:03:14.329782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fc_features = model.fc.in_features \n#since we need output probabilities but the provided pretrained model output a 1000 long data\nmodel.fc = nn.Linear(fc_features, 2)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T09:03:41.195095Z","iopub.execute_input":"2022-07-21T09:03:41.195444Z","iopub.status.idle":"2022-07-21T09:03:41.200472Z","shell.execute_reply.started":"2022-07-21T09:03:41.195414Z","shell.execute_reply":"2022-07-21T09:03:41.19956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = model.to(device) #after changing model, need to reset this","metadata":{"execution":{"iopub.status.busy":"2022-07-21T09:03:46.478262Z","iopub.execute_input":"2022-07-21T09:03:46.478609Z","iopub.status.idle":"2022-07-21T09:03:50.734417Z","shell.execute_reply.started":"2022-07-21T09:03:46.478578Z","shell.execute_reply":"2022-07-21T09:03:50.733439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model","metadata":{"execution":{"iopub.status.busy":"2022-07-21T09:03:50.737345Z","iopub.execute_input":"2022-07-21T09:03:50.737974Z","iopub.status.idle":"2022-07-21T09:03:50.746927Z","shell.execute_reply.started":"2022-07-21T09:03:50.737935Z","shell.execute_reply":"2022-07-21T09:03:50.746032Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3. Train and evaluate","metadata":{}},{"cell_type":"code","source":"\ncriterion = nn.CrossEntropyLoss()\n\noptimizer = optim.Adam(model.parameters(),lr = 0.05)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T09:04:07.287762Z","iopub.execute_input":"2022-07-21T09:04:07.288201Z","iopub.status.idle":"2022-07-21T09:04:07.297468Z","shell.execute_reply.started":"2022-07-21T09:04:07.288159Z","shell.execute_reply":"2022-07-21T09:04:07.296347Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\nnum_epochs = 2\n\ntotal_step = len(datamodule.train_dataloader()) \nloss_list = []\nacc_list = []\nfor epoch in range(num_epochs):\n    \n    running_loss = 0.0\n    correct = 0\n    y_train = 0\n    for i,batch in enumerate(datamodule.train_dataloader()): \n        \n        images = batch['input'].to(device)\n        labels = batch['target'].to(device)\n        outputs = model(images)\n        \n        loss = criterion(outputs,labels)\n        loss_list.append(loss.item())\n\n        \n        optimizer.zero_grad()\n        \n        loss.backward()\n        \n        optimizer.step()\n\n        # codes below just for showing training process \n        total = labels.size(0)\n        \n        _,predicted = torch.max(outputs.data,1)\n        \n        correct += (predicted == labels).sum().item() \n        \n        y_train += total\n        \n        running_loss += loss.item()\n        if (i+1) % 7 == 0:\n            print('Epoch[{}/{}],Step[{},{}],Loss Current Batch:{:.4f},Loss Avg:{:4f}, Accuracy:{:.2f} %'\n            .format(epoch+1,\n                    num_epochs,\n                    i+1,\n                    total_step,\n                    loss.item(), \n                    running_loss/400, \n                    (correct/y_train),\n#                     accuracy_score(correct, y_train),\n#                     f1_score(correct, y_train, average='micro')\n                   ))\n            running_loss=0.0\n            correct = 0\n            y_train = 0\n            \n","metadata":{"execution":{"iopub.status.busy":"2022-07-21T09:04:08.26985Z","iopub.execute_input":"2022-07-21T09:04:08.270267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\n\nwith torch.no_grad():\n    correct = 0\n    total = 0\n    for batch in datamodule.val_dataloader():\n        images = batch['input'].to(device)\n        labels = batch['target'].to(device)\n        outputs = model(images)\n        _,predicted = torch.max(outputs.data,1)\n        cur_acc = (predicted == labels).sum().item()/labels.size(0)\n        print('current batch accuracy:{}%'.format(cur_acc*100))\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n    print('Test Accuracy of the model on the valid images:{} %'.format((correct / total) * 100))","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:58:55.870361Z","iopub.status.idle":"2022-07-21T08:58:55.871048Z","shell.execute_reply.started":"2022-07-21T08:58:55.870782Z","shell.execute_reply":"2022-07-21T08:58:55.870805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4. make submission","metadata":{}},{"cell_type":"code","source":"dm_test = ImageClassificationData.from_folders(\n    test_folder=\"/kaggle/working/test_images\",\n    \n    batch_size=3,\n    transform_kwargs=TRANSFORM_PARAMS,\n    \n) ","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:58:55.872358Z","iopub.status.idle":"2022-07-21T08:58:55.873043Z","shell.execute_reply.started":"2022-07-21T08:58:55.872777Z","shell.execute_reply":"2022-07-21T08:58:55.872799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"m = nn.Softmax(dim=1)\nfor batch in dm_test.test_dataloader():\n    \n    images = batch['input'].to(device)\n    outputs = model(images)\n    predictions = m(outputs).cpu().detach().numpy()\n    ","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:58:55.874334Z","iopub.status.idle":"2022-07-21T08:58:55.875003Z","shell.execute_reply.started":"2022-07-21T08:58:55.874761Z","shell.execute_reply":"2022-07-21T08:58:55.874784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_pred = pd.DataFrame(predictions)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:58:55.876252Z","iopub.status.idle":"2022-07-21T08:58:55.876927Z","shell.execute_reply.started":"2022-07-21T08:58:55.876661Z","shell.execute_reply":"2022-07-21T08:58:55.876683Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ls_imgs_png = glob.glob(os.path.join(\"test_images\", \"*.png\"))\n\nnames = [os.path.splitext(os.path.basename(p))[0] for p in ls_imgs_png]\ndf_pred[\"patient_id\"] = [n.split(\"_\")[0] for n in names]\ndf_pred.loc[len(df_pred)]=[0.6, 0.4, '006388']\ndf_pred.columns=['CE', 'LAA','patient_id']","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:58:55.878171Z","iopub.status.idle":"2022-07-21T08:58:55.878838Z","shell.execute_reply.started":"2022-07-21T08:58:55.878581Z","shell.execute_reply":"2022-07-21T08:58:55.878604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_pred.groupby(\"patient_id\").mean().to_csv('submission.csv')\n!head submission.csv","metadata":{"execution":{"iopub.status.busy":"2022-07-21T08:58:55.880051Z","iopub.status.idle":"2022-07-21T08:58:55.880721Z","shell.execute_reply.started":"2022-07-21T08:58:55.880479Z","shell.execute_reply":"2022-07-21T08:58:55.880501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}