Skip to content

Instantly share code, notes, and snippets.

@moarshy
Created August 18, 2021 08:44
Show Gist options
  • Save moarshy/9db404370a27c4bff9f0f4996fc42be0 to your computer and use it in GitHub Desktop.
Save moarshy/9db404370a27c4bff9f0f4996fc42be0 to your computer and use it in GitHub Desktop.
Resize Learning Dataloader.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Resize Learning Dataloader.ipynb",
"provenance": [],
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
},
"accelerator": "GPU",
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"2b05b7b27a094553bc05b6b65e762ac3": {
"model_module": "@jupyter-widgets/controls",
"model_name": "HBoxModel",
"model_module_version": "1.5.0",
"state": {
"_view_name": "HBoxView",
"_dom_classes": [],
"_model_name": "HBoxModel",
"_view_module": "@jupyter-widgets/controls",
"_model_module_version": "1.5.0",
"_view_count": null,
"_view_module_version": "1.5.0",
"box_style": "",
"layout": "IPY_MODEL_b959d79e1fbc46e58aba72117561d455",
"_model_module": "@jupyter-widgets/controls",
"children": [
"IPY_MODEL_955683c0986e4d1d921a06c38ad02e0c",
"IPY_MODEL_b74e208e588a4756a291dc522abe48ab",
"IPY_MODEL_f1ef7898135c4de489cc2a60777998f8"
]
}
},
"b959d79e1fbc46e58aba72117561d455": {
"model_module": "@jupyter-widgets/base",
"model_name": "LayoutModel",
"model_module_version": "1.2.0",
"state": {
"_view_name": "LayoutView",
"grid_template_rows": null,
"right": null,
"justify_content": null,
"_view_module": "@jupyter-widgets/base",
"overflow": null,
"_model_module_version": "1.2.0",
"_view_count": null,
"flex_flow": null,
"width": null,
"min_width": null,
"border": null,
"align_items": null,
"bottom": null,
"_model_module": "@jupyter-widgets/base",
"top": null,
"grid_column": null,
"overflow_y": null,
"overflow_x": null,
"grid_auto_flow": null,
"grid_area": null,
"grid_template_columns": null,
"flex": null,
"_model_name": "LayoutModel",
"justify_items": null,
"grid_row": null,
"max_height": null,
"align_content": null,
"visibility": null,
"align_self": null,
"height": null,
"min_height": null,
"padding": null,
"grid_auto_rows": null,
"grid_gap": null,
"max_width": null,
"order": null,
"_view_module_version": "1.2.0",
"grid_template_areas": null,
"object_position": null,
"object_fit": null,
"grid_auto_columns": null,
"margin": null,
"display": null,
"left": null
}
},
"955683c0986e4d1d921a06c38ad02e0c": {
"model_module": "@jupyter-widgets/controls",
"model_name": "HTMLModel",
"model_module_version": "1.5.0",
"state": {
"_view_name": "HTMLView",
"style": "IPY_MODEL_a0da8d020d9e483b88f8ff7512e800bf",
"_dom_classes": [],
"description": "",
"_model_name": "HTMLModel",
"placeholder": "",
"_view_module": "@jupyter-widgets/controls",
"_model_module_version": "1.5.0",
"value": "100%",
"_view_count": null,
"_view_module_version": "1.5.0",
"description_tooltip": null,
"_model_module": "@jupyter-widgets/controls",
"layout": "IPY_MODEL_038aa417e9804fc5a2f3b5bc0fd76148"
}
},
"b74e208e588a4756a291dc522abe48ab": {
"model_module": "@jupyter-widgets/controls",
"model_name": "FloatProgressModel",
"model_module_version": "1.5.0",
"state": {
"_view_name": "ProgressView",
"style": "IPY_MODEL_ea1fbf303f094c70a7bb47eb174ca885",
"_dom_classes": [],
"description": "",
"_model_name": "FloatProgressModel",
"bar_style": "success",
"max": 46830571,
"_view_module": "@jupyter-widgets/controls",
"_model_module_version": "1.5.0",
"value": 46830571,
"_view_count": null,
"_view_module_version": "1.5.0",
"orientation": "horizontal",
"min": 0,
"description_tooltip": null,
"_model_module": "@jupyter-widgets/controls",
"layout": "IPY_MODEL_296f84b308ba47b4a69cde53064e148a"
}
},
"f1ef7898135c4de489cc2a60777998f8": {
"model_module": "@jupyter-widgets/controls",
"model_name": "HTMLModel",
"model_module_version": "1.5.0",
"state": {
"_view_name": "HTMLView",
"style": "IPY_MODEL_f74a87d4253b4410a53bad4d2378bbb3",
"_dom_classes": [],
"description": "",
"_model_name": "HTMLModel",
"placeholder": "",
"_view_module": "@jupyter-widgets/controls",
"_model_module_version": "1.5.0",
"value": " 44.7M/44.7M [00:00<00:00, 62.8MB/s]",
"_view_count": null,
"_view_module_version": "1.5.0",
"description_tooltip": null,
"_model_module": "@jupyter-widgets/controls",
"layout": "IPY_MODEL_cc1a93fd046e432bbd2d33425bab35c8"
}
},
"a0da8d020d9e483b88f8ff7512e800bf": {
"model_module": "@jupyter-widgets/controls",
"model_name": "DescriptionStyleModel",
"model_module_version": "1.5.0",
"state": {
"_view_name": "StyleView",
"_model_name": "DescriptionStyleModel",
"description_width": "",
"_view_module": "@jupyter-widgets/base",
"_model_module_version": "1.5.0",
"_view_count": null,
"_view_module_version": "1.2.0",
"_model_module": "@jupyter-widgets/controls"
}
},
"038aa417e9804fc5a2f3b5bc0fd76148": {
"model_module": "@jupyter-widgets/base",
"model_name": "LayoutModel",
"model_module_version": "1.2.0",
"state": {
"_view_name": "LayoutView",
"grid_template_rows": null,
"right": null,
"justify_content": null,
"_view_module": "@jupyter-widgets/base",
"overflow": null,
"_model_module_version": "1.2.0",
"_view_count": null,
"flex_flow": null,
"width": null,
"min_width": null,
"border": null,
"align_items": null,
"bottom": null,
"_model_module": "@jupyter-widgets/base",
"top": null,
"grid_column": null,
"overflow_y": null,
"overflow_x": null,
"grid_auto_flow": null,
"grid_area": null,
"grid_template_columns": null,
"flex": null,
"_model_name": "LayoutModel",
"justify_items": null,
"grid_row": null,
"max_height": null,
"align_content": null,
"visibility": null,
"align_self": null,
"height": null,
"min_height": null,
"padding": null,
"grid_auto_rows": null,
"grid_gap": null,
"max_width": null,
"order": null,
"_view_module_version": "1.2.0",
"grid_template_areas": null,
"object_position": null,
"object_fit": null,
"grid_auto_columns": null,
"margin": null,
"display": null,
"left": null
}
},
"ea1fbf303f094c70a7bb47eb174ca885": {
"model_module": "@jupyter-widgets/controls",
"model_name": "ProgressStyleModel",
"model_module_version": "1.5.0",
"state": {
"_view_name": "StyleView",
"_model_name": "ProgressStyleModel",
"description_width": "",
"_view_module": "@jupyter-widgets/base",
"_model_module_version": "1.5.0",
"_view_count": null,
"_view_module_version": "1.2.0",
"bar_color": null,
"_model_module": "@jupyter-widgets/controls"
}
},
"296f84b308ba47b4a69cde53064e148a": {
"model_module": "@jupyter-widgets/base",
"model_name": "LayoutModel",
"model_module_version": "1.2.0",
"state": {
"_view_name": "LayoutView",
"grid_template_rows": null,
"right": null,
"justify_content": null,
"_view_module": "@jupyter-widgets/base",
"overflow": null,
"_model_module_version": "1.2.0",
"_view_count": null,
"flex_flow": null,
"width": null,
"min_width": null,
"border": null,
"align_items": null,
"bottom": null,
"_model_module": "@jupyter-widgets/base",
"top": null,
"grid_column": null,
"overflow_y": null,
"overflow_x": null,
"grid_auto_flow": null,
"grid_area": null,
"grid_template_columns": null,
"flex": null,
"_model_name": "LayoutModel",
"justify_items": null,
"grid_row": null,
"max_height": null,
"align_content": null,
"visibility": null,
"align_self": null,
"height": null,
"min_height": null,
"padding": null,
"grid_auto_rows": null,
"grid_gap": null,
"max_width": null,
"order": null,
"_view_module_version": "1.2.0",
"grid_template_areas": null,
"object_position": null,
"object_fit": null,
"grid_auto_columns": null,
"margin": null,
"display": null,
"left": null
}
},
"f74a87d4253b4410a53bad4d2378bbb3": {
"model_module": "@jupyter-widgets/controls",
"model_name": "DescriptionStyleModel",
"model_module_version": "1.5.0",
"state": {
"_view_name": "StyleView",
"_model_name": "DescriptionStyleModel",
"description_width": "",
"_view_module": "@jupyter-widgets/base",
"_model_module_version": "1.5.0",
"_view_count": null,
"_view_module_version": "1.2.0",
"_model_module": "@jupyter-widgets/controls"
}
},
"cc1a93fd046e432bbd2d33425bab35c8": {
"model_module": "@jupyter-widgets/base",
"model_name": "LayoutModel",
"model_module_version": "1.2.0",
"state": {
"_view_name": "LayoutView",
"grid_template_rows": null,
"right": null,
"justify_content": null,
"_view_module": "@jupyter-widgets/base",
"overflow": null,
"_model_module_version": "1.2.0",
"_view_count": null,
"flex_flow": null,
"width": null,
"min_width": null,
"border": null,
"align_items": null,
"bottom": null,
"_model_module": "@jupyter-widgets/base",
"top": null,
"grid_column": null,
"overflow_y": null,
"overflow_x": null,
"grid_auto_flow": null,
"grid_area": null,
"grid_template_columns": null,
"flex": null,
"_model_name": "LayoutModel",
"justify_items": null,
"grid_row": null,
"max_height": null,
"align_content": null,
"visibility": null,
"align_self": null,
"height": null,
"min_height": null,
"padding": null,
"grid_auto_rows": null,
"grid_gap": null,
"max_width": null,
"order": null,
"_view_module_version": "1.2.0",
"grid_template_areas": null,
"object_position": null,
"object_fit": null,
"grid_auto_columns": null,
"margin": null,
"display": null,
"left": null
}
}
}
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/moarshy/9db404370a27c4bff9f0f4996fc42be0/resize-learning-dataloader.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "038Pg2-Sd_09",
"outputId": "341aadf6-8c25-4b18-a683-cfca994abc1a"
},
"source": [
"!pip install fastai -Uqq"
],
"execution_count": 1,
"outputs": [
{
"output_type": "stream",
"text": [
"\u001b[K |████████████████████████████████| 188 kB 5.2 MB/s \n",
"\u001b[K |████████████████████████████████| 56 kB 4.0 MB/s \n",
"\u001b[?25h"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "WIK1uqjfZlma"
},
"source": [
"from fastai.vision.all import *\n",
"from torch.utils.data import (Dataset, DataLoader) \n",
"from skimage import io\n",
"import torchvision.transforms as transforms # Transformations we can perform on our dataset\n",
"import torchvision\n",
"import torch\n",
"import torch.nn as nn # All neural network modules, nn.Linear, nn.Conv2d, BatchNorm, Loss functions\n",
"import torch.optim as optim # For all Optimization algorithms, SGD, Adam, etc.\n",
"from tqdm.notebook import tqdm"
],
"execution_count": 1,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "sgqGkupzaHso"
},
"source": [
"path = untar_data(URLs.FLOWERS)"
],
"execution_count": 2,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xo-u1K0bcfcj",
"outputId": "8064be2e-2275-40c7-d049-d1a8e6be1cd2"
},
"source": [
"path.ls()"
],
"execution_count": 3,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"(#4) [Path('/root/.fastai/data/oxford-102-flowers/jpg'),Path('/root/.fastai/data/oxford-102-flowers/train.txt'),Path('/root/.fastai/data/oxford-102-flowers/valid.txt'),Path('/root/.fastai/data/oxford-102-flowers/test.txt')]"
]
},
"metadata": {
"tags": []
},
"execution_count": 3
}
]
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iJJt83r0aSEh",
"outputId": "eeaad6e9-0414-4836-a60a-cd7a8d1ef8cf"
},
"source": [
"(path/'jpg').ls()"
],
"execution_count": 4,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"(#8189) [Path('/root/.fastai/data/oxford-102-flowers/jpg/image_05623.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_06659.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_05948.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_01715.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_04326.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_02545.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_05310.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_01938.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_02645.jpg'),Path('/root/.fastai/data/oxford-102-flowers/jpg/image_07797.jpg')...]"
]
},
"metadata": {
"tags": []
},
"execution_count": 4
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "LnBFu6V6cdnL"
},
"source": [
"train_df = pd.concat([\n",
" pd.read_csv(path/'train.txt', sep=' ', header=None, names=['path', 'class']),\n",
" pd.read_csv(path/'test.txt', sep=' ', header=None, names=['path', 'class'])]).sample(frac=1).reset_index(drop=True)\n",
"train_df['is_valid'] = False\n",
"valid_df = pd.read_csv(path/'valid.txt', sep=' ', header=None, names=['path', 'class'])\n",
"valid_df['is_valid'] = True\n",
"df = pd.concat([train_df, valid_df]).sample(frac=1).reset_index(drop=True)"
],
"execution_count": 5,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "Nvs-MuAXdPd9"
},
"source": [
"## Fastai bs=1 with Grad Accum"
]
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 173
},
"id": "Cg5-b7UDaVAa",
"outputId": "9eaa299e-b7e6-4c31-a61a-9173f7711466"
},
"source": [
"dls = DataBlock(\n",
" blocks=(ImageBlock, CategoryBlock),\n",
" splitter=ColSplitter(),\n",
" get_x=ColReader('path', pref=path),\n",
" get_y=ColReader('class') \n",
").dataloaders(df, bs=1, drop_last=True)\n",
"dls.show_batch()"
],
"execution_count": 6,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 216x216 with 1 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "m4ULttZYTXI_"
},
"source": [
"# https://arxiv.org/pdf/2103.09950.pdf\n",
"# https://github.com/yundaehyuck/Learning-to-resize-images-for-computer-vision-tasks/blob/main/resizing_network.ipynb\n",
"\n",
"class ResBlock(nn.Module):\n",
" def __init__(self,num_channels=16):\n",
" super(ResBlock,self).__init__()\n",
" \n",
" self.conv1 = nn.Conv2d(num_channels,num_channels,kernel_size=3,stride=1,padding=1)\n",
" self.bn1 = nn.BatchNorm2d(num_channels)\n",
" self.leakyrelu = nn.LeakyReLU(negative_slope=0.2,inplace=True)\n",
" \n",
" self.conv2 = nn.Conv2d(num_channels,num_channels,kernel_size=3,stride=1,padding=1)\n",
" self.bn2 = nn.BatchNorm2d(num_channels)\n",
" \n",
" def forward(self,x):\n",
" residual = x\n",
" \n",
" out = self.conv1(x)\n",
" out = self.bn1(out)\n",
" \n",
" out = self.leakyrelu(out)\n",
" \n",
" out = self.conv2(out)\n",
" out = self.bn2(out)\n",
" out += residual\n",
" \n",
" return out\n",
"\n",
"def make_block(r,n):\n",
" residual = []\n",
" \n",
" for i in range(r):\n",
" block = ResBlock(num_channels=n)\n",
" residual.append(block)\n",
" \n",
" return nn.Sequential(*residual)\n",
"\n",
"class ResizingNetwork(nn.Module):\n",
" def __init__(self, img_size=224, in_chans = 3, r=1, n=16):\n",
" super(ResizingNetwork, self).__init__()\n",
"\n",
" self.img_size = img_size\n",
" \n",
" self.conv1 = nn.Conv2d(in_channels=in_chans,out_channels=n,kernel_size=7,stride=1,padding=3)\n",
" self.leakyrelu1 = nn.LeakyReLU(negative_slope=0.2,inplace=True)\n",
" \n",
" self.conv2 = nn.Conv2d(n,n,kernel_size=1,stride=1)\n",
" self.leakyrelu2 = nn.LeakyReLU(negative_slope=0.2,inplace=True)\n",
" self.bn1 = nn.BatchNorm2d(n)\n",
" \n",
" self.resblock = make_block(r,n) \n",
" \n",
" self.conv3 = nn.Conv2d(n,n,kernel_size=3,stride=1,padding=1)\n",
" self.bn2 = nn.BatchNorm2d(n)\n",
" \n",
" self.conv4 = nn.Conv2d(n,out_channels=in_chans,kernel_size=7,stride=1,padding=3)\n",
"\n",
" def forward(self, x):\n",
" \n",
" residual = F.interpolate(x, size=(self.img_size, self.img_size), mode='bilinear', align_corners=False)\n",
" \n",
" out = self.conv1(x)\n",
" out = self.leakyrelu1(out)\n",
" \n",
" out = self.conv2(out)\n",
" out = self.leakyrelu2(out)\n",
" out = self.bn1(out)\n",
" \n",
" out_residual = F.interpolate(out, size=(self.img_size, self.img_size), mode='bilinear', align_corners=False)\n",
" \n",
" out = self.resblock(out_residual)\n",
" \n",
" out = self.conv3(out)\n",
" out = self.bn2(out)\n",
" out += out_residual\n",
" \n",
" out = self.conv4(out)\n",
" out += residual\n",
"\n",
" return out\n",
"\n",
"class RSModel(nn.Module):\n",
" def __init__(self):\n",
" super(RSModel, self).__init__()\n",
" self.resizenet = ResizingNetwork(224)\n",
" self.m = resnet18(pretrained=True)\n",
" self.body = nn.Sequential(*self.m.children())[:-2]\n",
" self.head = nn.Sequential(AdaptiveConcatPool2d(), \n",
" nn.Flatten(), \n",
" nn.Dropout(), \n",
" nn.Linear(512*2, 250), \n",
" nn.ReLU(inplace=True), \n",
" nn.Dropout(), \n",
" nn.Linear(250, 102))\n",
" self.model = nn.Sequential(self.body, self.head)\n",
" apply_init(self.head, nn.init.kaiming_uniform_)\n",
"\n",
" def forward(self, x):\n",
" x = self.resizenet(x)\n",
" #x = x.type(torch.cuda.FloatTensor)\n",
" x = self.model(x)\n",
"\n",
" return x"
],
"execution_count": 7,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 148
},
"id": "TkdFkLv5cLcF",
"outputId": "302347cf-f5d1-47d5-a98d-300fb49a8738"
},
"source": [
"learn = Learner(dls, RSModel(), metrics = accuracy, cbs=[GradientAccumulation(32)]).to_fp16()\n",
"learn.fine_tune(1)"
],
"execution_count": null,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/html": [
"\n",
" <div>\n",
" <style>\n",
" /* Turns off some styling */\n",
" progress {\n",
" /* gets rid of default border in Firefox and Opera. */\n",
" border: none;\n",
" /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
" background-size: auto;\n",
" }\n",
" .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
" background: #F44336;\n",
" }\n",
" </style>\n",
" <progress value='0' class='' max='1' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
" 0.00% [0/1 00:00<00:00]\n",
" </div>\n",
" \n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: left;\">\n",
" <th>epoch</th>\n",
" <th>train_loss</th>\n",
" <th>valid_loss</th>\n",
" <th>accuracy</th>\n",
" <th>time</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" </tbody>\n",
"</table><p>\n",
"\n",
" <div>\n",
" <style>\n",
" /* Turns off some styling */\n",
" progress {\n",
" /* gets rid of default border in Firefox and Opera. */\n",
" border: none;\n",
" /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
" background-size: auto;\n",
" }\n",
" .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
" background: #F44336;\n",
" }\n",
" </style>\n",
" <progress value='1403' class='' max='7169' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
" 19.57% [1403/7169 05:53<24:14 9.1354]\n",
" </div>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
},
{
"output_type": "stream",
"text": [
"/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at /pytorch/c10/core/TensorImpl.h:1156.)\n",
" return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)\n"
],
"name": "stderr"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "EYnLq-p-dxAs"
},
"source": [
"## Resize Learning"
]
},
{
"cell_type": "code",
"metadata": {
"id": "umgkbROMdXWf"
},
"source": [
"# https://arxiv.org/pdf/2103.09950.pdf\n",
"# https://github.com/yundaehyuck/Learning-to-resize-images-for-computer-vision-tasks/blob/main/resizing_network.ipynb\n",
"\n",
"class ResBlock(nn.Module):\n",
" def __init__(self,num_channels=16):\n",
" super(ResBlock,self).__init__()\n",
" \n",
" self.conv1 = nn.Conv2d(num_channels,num_channels,kernel_size=3,stride=1,padding=1)\n",
" self.bn1 = nn.BatchNorm2d(num_channels)\n",
" self.leakyrelu = nn.LeakyReLU(negative_slope=0.2,inplace=True)\n",
" \n",
" self.conv2 = nn.Conv2d(num_channels,num_channels,kernel_size=3,stride=1,padding=1)\n",
" self.bn2 = nn.BatchNorm2d(num_channels)\n",
" \n",
" def forward(self,x):\n",
" residual = x\n",
" \n",
" out = self.conv1(x)\n",
" out = self.bn1(out)\n",
" \n",
" out = self.leakyrelu(out)\n",
" \n",
" out = self.conv2(out)\n",
" out = self.bn2(out)\n",
" out += residual\n",
" \n",
" return out\n",
"\n",
"def make_block(r,n):\n",
" residual = []\n",
" \n",
" for i in range(r):\n",
" block = ResBlock(num_channels=n)\n",
" residual.append(block)\n",
" \n",
" return nn.Sequential(*residual)\n",
"\n",
"class ResizingNetwork(nn.Module):\n",
" def __init__(self, img_size=224, in_chans = 3, r=1, n=16):\n",
" super(ResizingNetwork, self).__init__()\n",
"\n",
" self.img_size = img_size\n",
" \n",
" self.conv1 = nn.Conv2d(in_channels=in_chans,out_channels=n,kernel_size=7,stride=1,padding=3)\n",
" self.leakyrelu1 = nn.LeakyReLU(negative_slope=0.2,inplace=True)\n",
" \n",
" self.conv2 = nn.Conv2d(n,n,kernel_size=1,stride=1)\n",
" self.leakyrelu2 = nn.LeakyReLU(negative_slope=0.2,inplace=True)\n",
" self.bn1 = nn.BatchNorm2d(n)\n",
" \n",
" self.resblock = make_block(r,n) \n",
" \n",
" self.conv3 = nn.Conv2d(n,n,kernel_size=3,stride=1,padding=1)\n",
" self.bn2 = nn.BatchNorm2d(n)\n",
" \n",
" self.conv4 = nn.Conv2d(n,out_channels=in_chans,kernel_size=7,stride=1,padding=3)\n",
"\n",
" def forward(self, x):\n",
" \n",
" residual = F.interpolate(x, size=(self.img_size, self.img_size), mode='bilinear', align_corners=False)\n",
" \n",
" out = self.conv1(x)\n",
" out = self.leakyrelu1(out)\n",
" \n",
" out = self.conv2(out)\n",
" out = self.leakyrelu2(out)\n",
" out = self.bn1(out)\n",
" \n",
" out_residual = F.interpolate(out, size=(self.img_size, self.img_size), mode='bilinear', align_corners=False)\n",
" \n",
" out = self.resblock(out_residual)\n",
" \n",
" out = self.conv3(out)\n",
" out = self.bn2(out)\n",
" out += out_residual\n",
" \n",
" out = self.conv4(out)\n",
" out += residual\n",
"\n",
" return out"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "JpddqYGDH0Xb"
},
"source": [
"class RSModel(nn.Module):\n",
" def __init__(self):\n",
" super(RSModel, self).__init__()\n",
" self.resizenet = ResizingNetwork(224)\n",
" self.m = resnet18(pretrained=True)\n",
" self.body = nn.Sequential(*self.m.children())[:-2]\n",
" self.head = create_head(512, 102)\n",
" self.model = nn.Sequential(self.body, self.head)\n",
"\n",
" def forward(self, x):\n",
" x_rs = []\n",
" for img in x:\n",
" img = img.type(torch.cuda.FloatTensor)\n",
" x_rs.append(self.resizenet(img))\n",
"\n",
" x = torch.stack(x_rs).squeeze(1)\n",
" x = x.type(torch.cuda.FloatTensor)\n",
" x = self.model(x)\n",
"\n",
" return x"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "v7lMf8FDe8Om"
},
"source": [
"class Dataset(Dataset):\n",
" def __init__(self, df, root_dir, bs, transform=None):\n",
" self.df = df\n",
" self.root_dir = root_dir\n",
" self.transform = transform\n",
" self.items = [i for i in range(len(self.df))]\n",
" random.shuffle(self.items)\n",
" self.bs = bs\n",
"\n",
" def __len__(self):\n",
" return len(self.df)//self.bs\n",
"\n",
" def __getitem__(self, index):\n",
" sel_index = self.items[index:index+self.bs]\n",
"\n",
" imgs, labels = [], []\n",
" for ind in sel_index:\n",
" img_path = os.path.join(self.root_dir, self.df.loc[ind, 'path'])\n",
" image = io.imread(img_path)\n",
" image = self.transform(image)\n",
"\n",
" y_label = torch.tensor(int(self.df.loc[ind, 'class']))\n",
" imgs.append(image)\n",
" labels.append(y_label)\n",
" \n",
" labels = torch.stack(labels).reshape(self.bs,1)\n",
"\n",
" return (imgs, labels)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "JStW9PZ6e8MI"
},
"source": [
"train_df = df[df['is_valid'] == False].reset_index(drop=True)\n",
"valid_df = df[df['is_valid'] == True].reset_index(drop=True)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "7pqYqMOxe8HT"
},
"source": [
"train_dset = Dataset(df=train_df, root_dir=path, bs=8, transform=transforms.ToTensor())\n",
"test_dset = Dataset(df=valid_df, root_dir=path, bs=8, transform=transforms.ToTensor())"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "lt4xoDaDe8E6"
},
"source": [
"train_loader = DataLoader(dataset=train_dset, batch_size=1, shuffle=True)\n",
"test_loader = DataLoader(dataset=train_dset, batch_size=1, shuffle=True)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "k3TSQog0e783"
},
"source": [
"x, y = next(iter(train_loader))"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "5_PpdNmAqBPg"
},
"source": [
"# Check accuracy on training to see how good our model is\n",
"def check_accuracy(loader, model):\n",
" num_correct = 0\n",
" num_samples = 0\n",
" model.eval()\n",
"\n",
" with torch.no_grad():\n",
" for x, y in loader:\n",
" #x = x.to(device=device)\n",
" y = y.to(device=device)\n",
"\n",
" scores = model(x)\n",
" _, predictions = scores.max(1)\n",
" num_correct += (predictions == y).sum()\n",
" num_samples += predictions.size(0)\n",
"\n",
" print(\n",
" f\"Got {num_correct} / {num_samples} with accuracy {float(num_correct)/float(num_samples)*100:.2f}\"\n",
" )\n",
"\n",
" model.train()"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 66,
"referenced_widgets": [
"2b05b7b27a094553bc05b6b65e762ac3",
"b959d79e1fbc46e58aba72117561d455",
"955683c0986e4d1d921a06c38ad02e0c",
"b74e208e588a4756a291dc522abe48ab",
"f1ef7898135c4de489cc2a60777998f8",
"a0da8d020d9e483b88f8ff7512e800bf",
"038aa417e9804fc5a2f3b5bc0fd76148",
"ea1fbf303f094c70a7bb47eb174ca885",
"296f84b308ba47b4a69cde53064e148a",
"f74a87d4253b4410a53bad4d2378bbb3",
"cc1a93fd046e432bbd2d33425bab35c8"
]
},
"id": "xa8w0ZaceqcZ",
"outputId": "d1de3ce0-d4e3-4740-d4a1-da4057fe3131"
},
"source": [
"# Loss and optimizer\n",
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"model = RSModel()\n",
"model.to(device)\n",
"criterion = CrossEntropyLossFlat()\n",
"optimizer = optim.Adam(model.parameters(), lr=1e-3)"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Downloading: \"https://download.pytorch.org/models/resnet18-f37072fd.pth\" to /root/.cache/torch/hub/checkpoints/resnet18-f37072fd.pth\n"
],
"name": "stderr"
},
{
"output_type": "display_data",
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2b05b7b27a094553bc05b6b65e762ac3",
"version_minor": 0,
"version_major": 2
},
"text/plain": [
" 0%| | 0.00/44.7M [00:00<?, ?B/s]"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "a2VaE8H3ojX3",
"outputId": "16ddca73-65f8-45f7-ef5b-769381547862"
},
"source": [
"for epoch in range(3):\n",
" losses = []\n",
"\n",
" for batch_idx, (data, targets) in enumerate(train_loader):\n",
" # Get data to cuda if possible\n",
" #data = data.to(device=device)\n",
" targets = targets.to(device=device)\n",
"\n",
" # forward\n",
" scores = model(data)\n",
" loss = criterion(scores, targets.reshape(-1))\n",
"\n",
" losses.append(loss.item())\n",
"\n",
" # backward\n",
" optimizer.zero_grad()\n",
" loss.backward()\n",
"\n",
" # gradient descent or adam step\n",
" optimizer.step()\n",
"\n",
" print(f\"Loss at epoch {epoch} is {sum(losses)/len(losses)}\")\n",
"\n",
" check_accuracy(test_loader, model)\n",
"\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at /pytorch/c10/core/TensorImpl.h:1156.)\n",
" return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)\n"
],
"name": "stderr"
},
{
"output_type": "stream",
"text": [
"Cost at epoch 0 is 2.975573916753222\n",
"Got 4033 / 7168 with accuracy 56.26\n",
"Cost at epoch 1 is 0.6661968021736746\n",
"Got 6001 / 7168 with accuracy 83.72\n",
"Cost at epoch 2 is 0.21216427958695153\n",
"Got 5250 / 7168 with accuracy 73.24\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "ztkYGpi5tICV"
},
"source": [
""
],
"execution_count": null,
"outputs": []
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment