{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport PIL\nimport cv2\nimport torch\nimport fastai\nimport numpy as np\nimport pandas as pd\nfrom fastai.vision import *\nfrom matplotlib import pyplot as plt\nfrom sklearn.decomposition import PCA\nfrom xgboost import XGBClassifier\nfrom torchvision import models, transforms\nfrom torch.utils.data import DataLoader, Dataset\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, cohen_kappa_score\n\ntorch.manual_seed(0)\ntorch.backends.cudnn.deterministic = True\n\nprint(os.listdir(\"../input\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Extracting Features using pretrained ResNet.\n\nCNNs typically extracted feature from input data and classify using one. So those features which output from CNN are also able to use other machine learning algorithms such as decision tree knn etc.\n\n![](https://s3.amazonaws.com/algorithmia-assets/algo_desc_images/imageclassification_ResNetFeatureExtraction/featurevec.png)"},{"metadata":{},"cell_type":"markdown","source":"## Image preprocessing\nReference from [Ben's&Cropping](https://www.kaggle.com/ratthachat/aptos-updatedv14-preprocessing-ben-s-cropping)"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"def crop_image_from_gray(img,tol=7):\n    if img.ndim ==2:\n        mask = img>tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim==3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img>tol\n        \n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0): # image is too dark so that we crop out everything,\n            return img # return original image\n        else:\n            img1=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n            img = np.stack([img1,img2,img3],axis=-1)\n        return img\n\ndef load_ben_color(image, image_size,sigmaX=10):\n    image = np.array(image)\n    image = crop_image_from_gray(image)\n    image = cv2.resize(image, image_size)\n    image = cv2.addWeighted(image,4, cv2.GaussianBlur( image , (0,0) , sigmaX) ,-4 ,128)\n    image = PIL.Image.fromarray(image)\n    return image\n\nclass BenColor:\n    def __call__(self, img, image_size=(512, 512)):\n        return load_ben_color(img, image_size)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Define Train & Test Dataset for torch.DataLoader"},{"metadata":{"trusted":true},"cell_type":"code","source":"class TrainDataset(Dataset):\n    def __init__(self, dataframe, transforms):\n        self.data = dataframe\n        self.transform = transform\n        self.c = 5\n        \n    def __len__(self):\n        return len(self.data)\n    \n    def __getitem__(self, idx):\n        img_name = os.path.join(\n            \"../input/aptos2019-blindness-detection/train_images/{}\".format(self.data.loc[idx, \"id_code\"])\n        )\n        image = PIL.Image.open(img_name)\n        image = self.transform(image)\n        label = torch.tensor(self.data.loc[idx, \"diagnosis\"])\n        return image, label\n\n\nclass TestDataset(Dataset):\n    def __init__(self, df, transform):\n        self.data = df\n        self.transform = transform\n        self.c = 5\n    \n    def __len__(self):\n        return len(self.data)\n    \n    def __getitem__(self, idx):\n        img_path = os.path.join(\"../input/aptos2019-blindness-detection/test_images/\", self.data.loc[idx, \"id_code\"])\n        img = PIL.Image.open(img_path)\n        img = self.transform(img)\n        return img\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 512\n\ntrain_table = pd.read_csv(\"../input/aptos2019-blindness-detection/train.csv\")\ntest_table = pd.read_csv(\"../input/aptos2019-blindness-detection/test.csv\")\n\n\ntrain_table[\"id_code\"] = train_table[\"id_code\"].apply(lambda x: x + \".png\")\ntest_table[\"id_code\"] = test_table[\"id_code\"].apply(lambda x: x + \".png\")\n\nx_train, x_val, y_train, y_val = train_test_split(train_table[\"id_code\"], train_table[\"diagnosis\"], random_state=0)\n\nx_train.index = np.arange(len(x_train))\ny_train.index = np.arange(len(y_train))\nx_val.index = np.arange(len(x_val))\ny_val.index = np.arange(len(y_val))\n\n\ntransform = transforms.Compose([\n    BenColor(),\n    transforms.RandomChoice([\n        transforms.RandomCrop(299),\n        transforms.Resize(299)\n    ]),\n    transforms.RandomChoice([\n        transforms.RandomHorizontalFlip(),\n        transforms.RandomVerticalFlip()\n    ]),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\nval_transform = transforms.Compose([\n    BenColor(),\n    transforms.Resize(299),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds = TrainDataset(pd.concat([x_train, y_train], axis=1), transform)\nval_ds = TrainDataset(pd.concat([x_val, y_val], axis=1), val_transform)\ntest_ds = TestDataset(test_table, val_transform)\n\ntrain_loader = DataLoader(train_ds, batch_size=32, num_workers=4)\nval_loader = DataLoader(val_ds, batch_size=32, num_workers=4)\ntest_loader = DataLoader(test_ds, batch_size=32, num_workers=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Re-struct pretrained ResNet 50."},{"metadata":{"trusted":true},"cell_type":"code","source":"body = create_body(models.resnet50, False, None)\nhead = create_head(4096, 5)\n\nmodel = nn.Sequential(body, head)\nmodel.load_state_dict(\n    torch.load(\"../input/pretraind-fastai-resnet50/fastai_resnet50_epochs.pth\")\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Define Extraction\nto extract feature from image. I define `class Extraction`."},{"metadata":{"trusted":true},"cell_type":"code","source":"class Extraction:\n    def __init__(self, network):\n        self.device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n        self.network = network.eval().to(self.device)\n        \n    def for_train(self, loader):\n        data_tmp = []\n        label_tmp = []\n        \n        with torch.no_grad():\n            for x, y in loader:\n                x = x.to(self.device)\n            \n                outputs = self.network[0](x)\n                outputs = self.network[1][0](outputs)\n                data_tmp.append(outputs.view(-1, 4096).cpu().numpy())\n                \n                label_tmp.append(y.cpu().numpy())\n                \n        return np.vstack(data_tmp), np.hstack(label_tmp)\n        \n    \n    def for_test(self, loader):\n        tmp = []\n        with torch.no_grad():\n            for x in loader:\n                x = x.to(self.device)\n            \n                outputs = self.network[0](x)\n                outputs = self.network[1][0](outputs)\n                tmp.append(outputs.view(-1, 4096).cpu().numpy())\n        return np.vstack(tmp)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ext = Extraction(model)\n\ntrain_feature, train_label = ext.for_train(train_loader)\nval_feature, val_label = ext.for_train(val_loader)\ntest_feature = ext.for_test(test_loader)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_feature.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Dimension reduction\noutput features has 4096 dimensions so I will try to reduce dimensions."},{"metadata":{"trusted":true},"cell_type":"code","source":"pca = PCA()\npca.fit(train_feature)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(np.round(pca.explained_variance_ratio_, 3)[:4])\nprint(\"-\"*50)\nprint(np.round(pca.explained_variance_ratio_, 5)[:4].sum())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_fea = pca.transform(train_feature)[:, :4]\nval_fea = pca.transform(val_feature)[:, :4]\ntest_fea = pca.transform(test_feature)[:, :4]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame(train_fea[:, :2]).plot(kind=\"scatter\", x=0, y=1, c=train_label, cmap=\"tab10\", figsize=(15, 10))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.empty_cache()\n\ntree = XGBClassifier(random_state=1997)\ntree.fit(train_fea, train_label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cohen_kappa_score(val_label, tree.predict(val_fea), weights=\"quadratic\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submit = pd.read_csv(\"../input/aptos2019-blindness-detection/sample_submission.csv\")\nsubmit[\"diagnosis\"] = tree.predict(test_fea)\nsubmit.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}