229 lines (228 with data), 8.4 kB
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "covidtesting notebook.ipynb",
"provenance": [],
"collapsed_sections": [],
"toc_visible": true,
"mount_file_id": "1LK7pcqyeGafFPUjp_1ld_vAp6ortxV9k",
"authorship_tag": "ABX9TyNrMW/nJjb2vdqOvLx5Te+c",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/github/ajsanjoaquin/COVID-19-Scanner/blob/master/covidtesting_notebook.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "syNJC42pUjl9",
"colab_type": "text"
},
"source": [
"This model is provided as-is, and not meant to diagnose COVID-19. This model has no clinical approval, nor endorsements from any health organizations. At the moment, this model is a proof of concept. In no way is the author responsible for any damages resulting from using this model. License: MIT "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fDTcYzSMDucn",
"colab_type": "text"
},
"source": [
"#PURE PYTORCH IMPLEMENTATION\n",
"\n",
"Model instantiation"
]
},
{
"cell_type": "code",
"metadata": {
"id": "kxVuivn32TCY",
"colab_type": "code",
"colab": {}
},
"source": [
"#download model\n",
"!wget -O corona_V2.pth https://www.dropbox.com/s/hovi7vc0edv8fxt/corona_V2.pth?dl=0"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "GZHgM1-Z8Oqb",
"colab_type": "code",
"colab": {}
},
"source": [
"## The code below gives you Flatten and the double Adaptive Pooling (from fastai), plus\n",
"## a viable head. You must fill the number of FC's nodes manually through the myhead function\n",
"from torch import Tensor\n",
"from torch import nn\n",
"from torchvision import transforms\n",
"from torch.autograd import Variable\n",
"import PIL.Image\n",
"import torch\n",
"import torchvision\n",
"import logging as log\n",
"from typing import Optional # required for \"Optional[type]\"\n",
"import os,re\n",
"#if using CPU; else, comment out\n",
"torch.cuda.device(\"cuda\")\n",
"\n",
"#put test images in test folder\n",
"if not os.path.isdir('test'):\n",
" os.makedirs('test')\n",
"\n",
"class Flatten(nn.Module):\n",
" \"Flatten `x` to a single dimension, often used at the end of a model. `full` for rank-1 tensor\"\n",
" def __init__(self, full:bool=False):\n",
" super().__init__()\n",
" self.full = full\n",
"\n",
" def forward(self, x):\n",
" return x.view(-1) if self.full else x.view(x.size(0), -1)\n",
"\n",
"class AdaptiveConcatPool2d(nn.Module):\n",
" \"Layer that concats `AdaptiveAvgPool2d` and `AdaptiveMaxPool2d`.\" # from pytorch\n",
" def __init__(self, sz:Optional[int]=None): \n",
" \"Output will be 2*sz or 2 if sz is None\"\n",
" super().__init__()\n",
" self.output_size = sz or 1\n",
" self.ap = nn.AdaptiveAvgPool2d(self.output_size)\n",
" self.mp = nn.AdaptiveMaxPool2d(self.output_size)\n",
" def forward(self, x): return torch.cat([self.mp(x), self.ap(x)], 1)\n",
" \n",
"def myhead(nf, nc):\n",
" return \\\n",
" nn.Sequential( # the dropout is needed otherwise you cannot load the weights\n",
" AdaptiveConcatPool2d(),\n",
" Flatten(),\n",
" nn.BatchNorm1d(nf,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True),\n",
" nn.Dropout(p=0.25,inplace=False),\n",
" nn.Linear(nf, 512,bias=True),\n",
" nn.ReLU(True),\n",
" nn.BatchNorm1d(512,eps=1e-05,momentum=0.1,affine=True,track_running_stats=True),\n",
" nn.Dropout(p=0.5,inplace=False),\n",
" nn.Linear(512, nc,bias=True),\n",
" )\n",
"\n",
"\n",
"my_model=torchvision.models.resnet50() \n",
"modules=list(my_model.children())\n",
"modules.pop(-1) \n",
"modules.pop(-1) \n",
"temp=nn.Sequential(nn.Sequential(*modules))\n",
"tempchildren=list(temp.children()) \n",
"#append the special fastai head\n",
"#Configured according to Model Architecture\n",
"\n",
"tempchildren.append(myhead(4096,2))\n",
"model_r50=nn.Sequential(*tempchildren)\n",
"\n",
"#LOAD MODEL\n",
"state = torch.load('corona_V2.pth')\n",
"model_r50.load_state_dict(state['model'])\n",
"\n",
"\n",
"#important to set to evaluation mode\n",
"model_r50.eval()\n",
"\n",
"\n",
"test_transforms = transforms.Compose([\n",
" transforms.Resize(512),\n",
" transforms.ToTensor(),\n",
" transforms.Normalize(mean=[0.485, 0.456, 0.406],\n",
" std=[0.229, 0.224, 0.225])\n",
"])\n",
"\n",
"def predict_image(model,image):\n",
" softmaxer = torch.nn.Softmax(dim=1)\n",
" image_tensor = PIL.Image.open(image)\n",
" image_tensor = image_tensor.convert('RGB')\n",
" image_tensor = test_transforms(image_tensor).float()\n",
" image_tensor = Variable(image_tensor,requires_grad=True)\n",
" image_tensor=image_tensor.unsqueeze(0)\n",
" image_tensor.cuda() #assuming using GPU w/ CUDA\n",
"\n",
" #convert evaluation to probabilities with softmax\n",
" with torch.no_grad(): #turn off backpropagation\n",
" processed=softmaxer(model(image_tensor))\n",
" return processed[0] #return probabilities\n"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "bEe1PH4dwYix",
"colab_type": "text"
},
"source": [
"##Before running the code below, put the test images in the test folder that was just created."
]
},
{
"cell_type": "code",
"metadata": {
"id": "K8r9AL6X_F_F",
"colab_type": "code",
"colab": {}
},
"source": [
"reg = re.compile('^.ipynb*')\n",
"test_files=[file for file in sorted(os.listdir('test'))if not reg.match(file)]\n",
"pytorch_results={filename:predict_image(model_r50,'test/'+filename) for filename in test_files}\n"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "FuRl6NDtw5-o",
"colab_type": "text"
},
"source": [
"###Results are saved in a .csv file in the colab workspace."
]
},
{
"cell_type": "code",
"metadata": {
"id": "t7YqjQQw_STi",
"colab_type": "code",
"colab": {}
},
"source": [
"import pandas as pd\n",
"final_df=pd.DataFrame.from_dict(pytorch_results,orient='index',columns=['corona','other']).rename_axis('filename').reset_index()\n",
"final_df['corona']=final_df['corona'].apply(lambda x: x.item())\n",
"final_df['other']=final_df['other'].apply(lambda x: x.item())\n",
"final_df.loc[final_df['corona'] > final_df['other'], 'Predicted Label'] = \"Corona\"\n",
"final_df.loc[final_df['corona'] < final_df['other'], 'Predicted Label'] = \"Other\"\n",
"final_df.to_csv('results.csv', header=True)"
],
"execution_count": 0,
"outputs": []
}
]
}