{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%matplotlib inline\n", "from matplotlib import pyplot as plt\n", "import numpy as np\n", "import collections\n", "\n", "import torch\n", "import torch.nn as nn\n", "import torch.nn.functional as F\n", "import torch.optim as optim\n", "\n", "torch.set_printoptions(edgeitems=2)\n", "torch.manual_seed(123)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "class_names = ['airplane','automobile','bird','cat','deer',\n", " 'dog','frog','horse','ship','truck']" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/local/lib/python3.7/dist-packages/torchvision/io/_video_opt.py:17: UserWarning: video reader based on ffmpeg c++ ops not available\n", " warnings.warn(\"video reader based on ffmpeg c++ ops not available\")\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Files already downloaded and verified\n" ] } ], "source": [ "from torchvision import datasets, transforms\n", "data_path = '../data-unversioned/p1ch6/'\n", "cifar10 = datasets.CIFAR10(\n", " data_path, train=True, download=True,\n", " transform=transforms.Compose([\n", " transforms.ToTensor(),\n", " transforms.Normalize((0.4915, 0.4823, 0.4468),\n", " (0.2470, 0.2435, 0.2616))\n", " ]))" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Files already downloaded and verified\n" ] } ], "source": [ "cifar10_val = datasets.CIFAR10(\n", " data_path, train=False, download=True,\n", " transform=transforms.Compose([\n", " transforms.ToTensor(),\n", " transforms.Normalize((0.4915, 0.4823, 0.4468),\n", " (0.2470, 0.2435, 0.2616))\n", " ]))" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "label_map = {0: 0, 2: 1}\n", "class_names = ['airplane', 'bird']\n", "cifar2 = [(img, label_map[label])\n", " for img, label in cifar10\n", " if label in [0, 2]]\n", "cifar2_val = [(img, label_map[label])\n", " for img, label in cifar10_val\n", " if label in [0, 2]]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "connected_model = nn.Sequential(\n", " nn.Linear(3072, 1024),\n", " nn.Tanh(),\n", " nn.Linear(1024, 512),\n", " nn.Tanh(),\n", " nn.Linear(512, 128),\n", " nn.Tanh(),\n", " nn.Linear(128, 2))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3737474, [3145728, 1024, 524288, 512, 65536, 128, 256, 2])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numel_list = [p.numel()\n", " for p in connected_model.parameters()\n", " if p.requires_grad == True]\n", "sum(numel_list), numel_list" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "first_model = nn.Sequential(\n", " nn.Linear(3072, 512),\n", " nn.Tanh(),\n", " nn.Linear(512, 2),\n", " nn.LogSoftmax(dim=1))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1574402, [1572864, 512, 1024, 2])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numel_list = [p.numel() for p in first_model.parameters()]\n", "sum(numel_list), numel_list" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(torch.Size([1024, 3072]), torch.Size([1024]))" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linear = nn.Linear(3072, 1024)\n", "\n", "linear.weight.shape, linear.bias.shape" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1))" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "conv = nn.Conv2d(3, 16, kernel_size=3) # <1>\n", "conv" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(torch.Size([16, 3, 3, 3]), torch.Size([16]))" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "conv.weight.shape, conv.bias.shape" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(torch.Size([1, 3, 32, 32]), torch.Size([1, 16, 30, 30]))" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "img, _ = cifar2[0]\n", "output = conv(img.unsqueeze(0))\n", "img.unsqueeze(0).shape, output.shape" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.imshow(img.mean(0), cmap='gray')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlAAAAEtCAYAAADHtl7HAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nO3de2yd933f8c9X1IUiJYoiJUrUxbrYinxTZBtKmosXZGmSpUXbJAXqNCg6F0jrDGiGFmjRZdml6bABQdGmKNAtgDtncbq0Tbaki9sFW51kiaFeMsuRZTuWbNkSbV0oStSdupP67Q8ed4yj8/3o4cPLkfV+AYIofvic8zvP85zf+elcPoxSigAAAHD95sz2AAAAAG40LKAAAAAqYgEFAABQEQsoAACAilhAAQAAVMQCCgAAoCIWUACAm0JE/CAi3j3b48AbQ9ADhekQEUXSplLKS614eQAwHSLiC5IOllL+9WyPBdOLZ6AAAAAqYgGFVETcERHfiYhTjae/f6bx/e9ExC9P+Llfiojtja+faHx7V0SMRMRHIuLdEXEwIj4VEcMRMRARvzBh+0qXN923G8AbT2PeeW9EfDoivhIRX4yIs425bdvrfu5fRsTzEXEyIv5LRLQ3sn+Ymyb8fImI2yLiIUm/IOm3GnPVX87sLcRMYgGFpiJinqS/lPTXkvok/XNJX4qIzdl2pZR3Nb7cWkpZVEr5cuPfKyUtk7Ra0oOSHnaXZS4PACbrZyT9uaRuSY9J+qPX5b8g6Z9IulXSmyTZl+RKKQ9L+pKk323MVT89pSNGS2EBhczbJC2S9JlSyuVSyrcl/ZWkj9a4zH9TSrlUSvmupP8p6YEpGCcAVLW9lPKNUsqYpD+RtPV1+R+VUg6UUk5I+g+qN+/hDYgFFDKrJB0opVyd8L1XNP4M0mScLKWce91lrZrs4ACghiMTvj4vqT0i5k743oEJXzNX4UewgELmsKS1ETHxPLlF0iFJ5yR1TPj+yuu4vKUR0fm6yzrc+HoylwcA02XthK+bzlUR8fq5io+23yRYQCHzPY1PFr8VEfMa/Sk/rfH3DTwt6WcjoiMibpP0sddtOyRp4zUu83ciYn5E/CNJPyXpvzW+P9nLA4Dp8KsRsSYieiR9StJr773cJemuiLin8cbyT79uO+aqmwQLKDRVSrms8Tda/oSkYUn/SdI/LaXskfQHki5rfLJ4VONvnJzo05IebXx677X3OR2RdFLj/5P7kqR/1rgsTfLyAGC6/KnGP0Czr/Hn30tSKeVFSf9O0jcl7ZW0/XXbPSLpzsZc9T9mbriYaRRpYkY0nr36r6WUNbM9FgDIRMSApF8upXxztseC1sUzUAAAABWxgAIAAKiIl/AAAAAq4hkoAACAilhAAQAAVDTX/0hzEfEBSX8oqU3Sfy6lfCb7+c7OztLd3d00X7BgQXp9o6OjaX7p0qU0dy9XtrW11do+y922c+fmh2LOnHytW/e2RUSt3Kn7UvHVq1dr5e7cuXz5cpovXLiwaeb2rTsv3bF1+95dv+Muf8WKFbUu/6mnnhoupSyvdSHTpMoc1tXVVbJ9cebMmfS65s+fn+Z1j6Pb3l1/NgfNmzcv3dad4xcuXEhzN/a6+2ZsbCzN3X2w7vzr5ie3f931O27+y/bPdL/Nx829ded2x20/PDzcdP6a9AIqItok/UdJ75N0UNKTEfFYKeX5Ztt0d3fr4x//eNPL3Lgx7x47fvx4mr/yyitpfuXKlTRfvHhxmrsDneXuJOjt7U3z9vb2NHcnQbZwlfzi1T3Iuju4m8BcfvHixTQ/d+5cmp84cSLNBwYG0vzuu+9umi1ZsiTd9uWXX07zRYsWpblbXLvrrzt5/+Zv/maaOxGR3zFnSdU5bMWKFfrsZz/b9PK+/e1vp9e3enX+G5DccXTngZu/3PVni8Ply/P17/79+9P8mWeeSXN329385eanU6dOpXlHR0eaZ/+Bkvz86xaQq1blvyWms7Mzzd31u9t/8uTJplnduds5dOhQmo+MjKS5Wxe4BeCxY8fS/JFHHmk6f9VZ1r5V0kullH2NwsU/l/TBGpcHADOJOQzApNVZQK3WD/+yxYOa/C+ZBYCZxhwGYNLqLKCu9ZzpjzxXFhEPRcSOiNjhXmYBgBlk57CJ89fp06dnaFgAbgR1FlAH9cO/rXqN/v9vq/4HpZSHSynbSinb3Ou4ADCD7Bw2cf5y79MBcHOps4B6UtKmiNgQEfMl/bykx6ZmWAAw7ZjDAEzapD+FV0oZjYhPSPrfGv8I8OdLKT+YspEBwDRiDgNQR60eqFLKNyR943p/vr29XXfccUfT3H3U031U1X2M98iRI2nuPu7Y39+f5tlHQYeHhye9rST19fWlufsofN2OGFdz4DpwDhw4kObu+t2xcRUV7qOw7qOs2Uf9e3p6al23q2hwH6F2NQWufsNVZLyRVZnDIiI9D9xx+u53v5vmW7ZsSfOurq40d+eZew/q+fPnm2bu/uVqDu688840d/Ofy919wFVAuMcW99jk7kPuscOdO3V7+lzNwb59+5pm7rHFzd2uxsU9brvz2qnbIZihiRwAAKAiFlAAAAAVsYACAACoiAUUAABARSygAAAAKmIBBQAAUBELKAAAgIpq9UBVNTY2lvYF7d27N93e9ZisX78+zefMydeLrivJdTFlXUWua8L1gLgek46Ojlq56zFxPSiHDh1Kc9fB5XpSnFOnTqW566k6e/ZsmmfHz3XkXLp0Kc3rdry4nifX08KvKLk+ly5d0quvvto037hxY7p9d3d3mm/YsCHN3Ryye/fuNH/++efTfNOmTU0z93sAXZePu3/V7TFy43Ndba7nzm3verDcHOBun+Pm5+PHj6f5rl27mmYrVqxIt33Tm96U5u5XuLmOL3fb3OP64OBgrctPr3vSWwIAANykWEABAABUxAIKAACgIhZQAAAAFbGAAgAAqIgFFAAAQEUsoAAAACqa0R6o0dFRnThxomnu+hxWr16d5kuXLk1z18Pi+iiynicpH//FixfTbVetWpXmrkvDdQG5jqvz58+n+bFjx9I8O66SH7/rKnI9Kq7j5ujRo2k+MjKS5ocPH26aubG5DpxFixalueuZch1hrufJ7XuMu3jxovbs2dM037x5c7r9li1b0jy7bMl3mbmuNze//f3f/33TrKurK93WnWNu7nzxxRfT3J3jrofJdWi52+cee9z8+cILL6S5e2xy43M9gu7cyHq0Vq5cmW7r5vaxsbE0d/2O8+bNS/Ph4eE0r9tBluEZKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAVsYACAACoiAUUAABARSygAAAAKprRHqh58+alnRKjo6Pp9q4vx3URuZ6o9vb2NHddIsuWLWuauZ4h1+PkekBcV9DQ0FCau64O12NVt+fJ3f5Dhw6l+a5du9LcnRuu5yXbvqenJ93W5e68c1zHy4IFC9LcdYRh3JUrV3Tw4MGmueurcV1Brq/G3QfXrl2b5vfee2+aZ/cxN/adO3emubt/u7nZbe/09vamubuPuvnb9eS5Hiz32OY6Et2543q6snPHHRt32w8cOJDmrkfPnfeu38xdvtv3GZ6BAgAAqIgFFAAAQEUsoAAAACpiAQUAAFARCygAAICKWEABAABUxAIKAACgolo9UBExIOmspDFJo6WUbdnPt7W1pX1B3d3d6fWdOXMmzV0XhuP6dFyXx9y5zXen6xkZHh5Oc9dBlV235HtEXFeQ67hxPU+O6+o4d+5cmrtjc9ddd6X5bbfdlub9/f1Ns76+vnRbx43dndcLFy6sdfmuQ+yNrMocVkpJu+pcH47rs3F9YNk5KPn7uOuJOn78eNPM9ai5niE3v7muoVtuuSXNXU+Tmz9cV5HruXPX77qGXM+Vmx8ff/zxNHdzwOLFi5tm7ra7Y+vG7s5bd7+JiDR3HWB1TEWR5j8upeR7EABaF3MYgMp4CQ8AAKCiuguoIumvI+KpiHhoKgYEADOIOQzApNR9Ce+dpZTDEdEn6fGI2FNKeWLiDzQmpYek/HfFAcAsSOewifOXe68ZgJtLrWegSimHG38flfQXkt56jZ95uJSyrZSyzb3REABmkpvDJs5f7oMWAG4uk15ARURnRCx+7WtJ75f03FQNDACmE3MYgDrqvIS3QtJfND5COFfSn5ZS/teUjAoAph9zGIBJm/QCqpSyT9LWKtuMjY2lnTZZF8Vr22dcV5F7D8PJkyfT/JVXXknzrMelbo+S63lyPSOuh8r1TGUdMZLv+nA9J+72uXzdunVp/v73vz/NXQfZ5s2bm2bu2A0MDKT5+fPn07zuvnX9Zlm30RtZ1TksItK+NNdXs3HjxjR354nrwXN9Xm9/+9vT/L3vfW/TzM3NrmfIzX9Hjx5N87a2tjR394HBwcE0dx1bGzZsSPOurq40d3OEu4/v2bMnzbdv357mQ0NDab5y5cqmmbttrl/MzT91Ow7d+C5cuJDmrn8tQ40BAABARSygAAAAKmIBBQAAUBELKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAV1f1deJW4HhXX9dHZ2ZnmrovE/SoZl584cSLNsy4P1/PR19eX5q7nye0718PiuoDcvnXc+JxTp06ledZjIvmuEtcjk3XsuH3n+sXcdbtjX/fccT0pGDc6Opr2obn54/Dhw2nueupcD5TroXrqqafS/KWXXmqaudvmepJWr16d5u4+snv37jR3+87ND+6xxXW1uS4h12XkeqJcB6I79uvXr0/z7Pi4sfX29qa56ydzYx8eHk7zuvNnnR48noECAACoiAUUAABARSygAAAAKmIBBQAAUBELKAAAgIpYQAEAAFQ0ozUGpZRaHwd3H4V3H2W9evVqmnd3d6d5VsEgqdZHnHt6etLcfdTz9OnTae64mgX3UfezZ8+meUSkuTt27vKXL1+e5u7cch+1HRoaaprNmZP/P8TtO/cR6K6urjR3NQbuvHcfscb1cfvRVXGsW7cuzd38NzAwkObnzp1L8+w+dujQoXTbo0ePpvmyZcvS3H3UfOnSpWnu5g9XY1L3scPNH9ljgyR1dHSkuatRcI8f73nPe9I8O/augsI9Lu7duzfN3f3C1Xe4ud09rtep6OEZKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAVsYACAACoiAUUAABARSygAAAAKprRApg5c+akfReuL2fx4sVp7vocXFeS65twfT9ZD4zr6Zg/f36aux4Qt+/c2N1td/nJkyfTfGxsLM1d15E79q6DZ3BwMM3d/snOLddh43pIXEeY2951bLn7RZ0elJvJ2NhYep67c9AdZ9fT5LqG6vZ5ZV1qroduZGQkzd1t27JlS5r39/enuetpcrk7Nu4+4nrq3PznOr4OHDiQ5itWrEjzH/uxH0vzrAfQHXuXu8cut+9cz5R7bHX7lh4oAACAGcQCCgAAoCIWUAAAABWxgAIAAKiIBRQAAEBFLKAAAAAqYgEFAABQkS0OiYjPS/opSUdLKXc3vtcj6cuS1ksakPRAKSUvApI0b9489fX1Nc1dV4jrOXFdG3X7KubNm5fmWZeR6wpyPSquq8J1Xbh9667/2LFjae56VlyPU3t7e5qvW7cuzd2xuXz5cpovXbo0zRcuXJjmGdcx5cbu1D02dfuDWt1UzWERkfa1ufnjxIkTaX7q1Kk0z3qaJKmzszPNXd9Odh9dtmxZuu3hw4fT3J3jo6Ojae7G7uYP17N3/PjxNHf3keHh4TR3HYSuh+rIkSNp3tvbm+bu8cHNURnX07Rhw4Y0d3Pvq6++muZu37n5r85tv54tvyDpA6/73iclfauUsknStxr/BoBW9AUxhwGYYnYBVUp5QtLr/+v0QUmPNr5+VNKHpnhcADAlmMMATIfJPne1opQyKEmNv5u/LgcArYc5DEAt0/4m8oh4KCJ2RMQO9xo/ALSSifOX+110AG4uk11ADUVEvyQ1/j7a7AdLKQ+XUraVUra5X4oKADPkuuawifNX3Tf7A3hjmewC6jFJDza+flDS16dmOAAwI5jDANRiF1AR8WeS/k7S5og4GBEfk/QZSe+LiL2S3tf4NwC0HOYwANPBFsCUUj7aJPrxKR6L7dpwXT6uB8r1QbiuDNezknVxuMt2HTGuZ8V10Fy4cCHNXU+Ju3zXQ7Jx48Y0d/t27969aX7rrbemeUTUyrMemqGhoXRb17HlOnBcT4nrsLl06VKar1y5Ms1vdFM5h2VziHuPlNvP7jyo2+flxpedx+66Xc/d2rVr03zNmjVpvmrVqjR343NdRW5+dD1Pe/bsSfP9+/enuXt8qHvsX3jhhTTP5l933rpj4469u+1u/nTHzp33rmMsQxM5AABARSygAAAAKmIBBQAAUBELKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAV2R6oqXT16tW0k+bixYvp9i6fP39+mi9cuDDN29vb03zJkiVpnnWhuN8DeObMmTSv2/Pkctcjsnr16jR3XSHu1/i42+96st7+9renueuZ2bVrV5qXUppmrqfJ7VvXQXXu3Lk0dz0mbnvXP4RxpZS0U8bNLx0dHWnuun7ccXLnketay7qOXJfOfffdl+aup83N3a7LzP2aHbdvXdfQzp0703xgYCDN3bFzjz1uDnFdTO7xI9t/riPQ9Ti5fP369Wm+YcOGNHc9eG7d4B7XMzwDBQAAUBELKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAVsYACAACoiAUUAABARTPaA1VKSfuIXFdHXa6nxXVt9PX1pfnY2FjTLOtYkXyXheuROnnyZJq7HhXX05T1IEm+5+TYsWNpfvDgwTR3PVGuB2bBggVp7safnRtu37mOLHdeun3T1dWV5nWPLca1tbVp6dKlTfOsB+617TOuj8bdh9057LqOsq4n13Xm5m43t7qOKnf/dtu7feO6gtzlr1ixIs3d+N19cMeOHWn+rne9K803btyY5tljl5t73WOb27eXL19Oc9dxlY1d8o+troMrwzNQAAAAFbGAAgAAqIgFFAAAQEUsoAAAACpiAQUAAFARCygAAICKWEABAABUNKM9UG1tbWnXiesKcV0kruvDdSm5PgrXdXLkyJGm2Z49e9JtDx06lOaui+PEiRNpnnW8SL4jpm4XkTu2rsfKdei4Y+uu33WJnDt3rmnmOqY6OjrS3J1XLnc9U66/LOtmww/LzhPX0+TOYXcO1u1Cc3032X3EdVz19vam+eLFi9PcdaG5+cXtW/fYcNddd6X5HXfckebnz59Pcze/7dy5M81dT1REpPltt92W5s8991zTzB0bNz+5fe/mn8HBwTR33PbZ47bDM1AAAAAVsYACAACoiAUUAABARSygAAAAKmIBBQAAUBELKAAAgIpYQAEAAFRke6Ai4vOSfkrS0VLK3Y3vfVrSr0g61vixT5VSvmGvbO5cLVu2rGnuelBcz4rLjx8/nuauz8L1sBw4cKBpdvjw4XTbixcvprnr0nBcB4zrMnL71vVQuY4ad/s7OztrXb/rSnKyHizXkeM6aubPn5/mrsMqu09JvkPnjd4DNVVz2NjYWNoH5rrWzp49m+buOLr7gOPGl3UNuR4h1wPlepDc2Nzc7OYn19Pk9q3rIHTHzs0Rx44dS3M3Prd/9+/fn+bZ+FyH1+nTp9PczW/Ovn370tztG3ds3GNf5nqegfqCpA9c4/t/UEq5p/HHLp4AYJZ8QcxhAKaYXUCVUp6QlP/3HgBaFHMYgOlQ5z1Qn4iIZyLi8xGxdMpGBAAzgzkMwKRNdgH1OUm3SrpH0qCk32/2gxHxUETsiIgd7n0qADBDrmsOmzh/1X0fIoA3lkktoEopQ6WUsVLKVUl/LOmtyc8+XErZVkrZ1tPTM9lxAsCUud45bOL85d7MD+DmMqkFVET0T/jnhyU1/1XOANBimMMA1HU9NQZ/JundkpZFxEFJvy3p3RFxj6QiaUDSx6dxjAAwacxhAKaDXUCVUj56jW8/Mpkru3jxovbu3ds0dz0prsvj8uXLab5r1640dz1US5YsSfOsiyTrj5F8z4jr8uno6Ehzd9tcT5TraXHHZuHChWnuXh5x+8fdfnfsXNdJ1pPi9m1EpLnriXLHxt1v6uY3uqmawzo7O/WWt7ylaV63z2vVqlVpvnRpvfe5DwwMpHnW5+O6dFxPk+vgcz1OrqvMncOuq8i9v83l7ti4+TvrEJT8/Dc4OJjmrgcqm/9cD5Obn/r7+9PcdQQ6rgdq8+bNae7m/gxN5AAAABWxgAIAAKiIBRQAAEBFLKAAAAAqYgEFAABQEQsoAACAilhAAQAAVDSjv5tgZGREf/u3f9s0r9tH43pWduzYkeauj+dtb3tbmq9fv75ptmfPnnRb16XhuirqdgW531NYd3yuh8l16Lgupb6+vjR3PTKuZyXrEhkZGUm37e3tTXN33rp96zrG3PjcvsW4rq4uve9972uau+Pk+mrcfcTdB938lc29kvT88883zVxPkevycT1t7hwtpaS563lyPXYLFiyodfnPPvtsmmc9cpK/fa5nb2hoKM23bt2a5kePHm2a7dy5M93WzR/Lly9P8w0bNqS5e2xy1++2r9NDxTNQAAAAFbGAAgAAqIgFFAAAQEUsoAAAACpiAQUAAFARCygAAICKWEABAABUNKM9UJcvX9a+ffua5mNjY+n2rqvD9elcvHgxzV1Xx+23357mK1eubJodP3483XbhwoVp7sbmeo4ct+9dT5PruOnp6Ulzd/tXrFiR5qtWrUrzM2fOpLnrgcrOve7u7nTbrq6uNHfnpes5ccfG9VDV7V+7WSxatEj3339/09z1yVy9ejXNXReQ63ly54E7z/bv3980cz1N7j5w+fLlNHcdWqtXr05z1zXkepzcvnE9TK5ryM3/bv51PU+uQ6xOz5Z77HnyySfTfOnSpWnu5mZ3v3LzV9ZxJUn33HNPmmd4BgoAAKAiFlAAAAAVsYACAACoiAUUAABARSygAAAAKmIBBQAAUBELKAAAgIpmtAdqbGxM586da5q7nhPH9ai4Pot169al+ebNm9M869pwt831oLgeJNfzMTo6muZufK6Dy43fdRG1t7en+W233Zbmbv/U7eEaHh5umrkOF9eD4jpy3OW7DrANGzaked373c1i7ty56bF0PU/uPujOg7o9USdPnkzzZ599tmnm7p9u7ty1a1eau64f19PkuH334osvpvmpU6fS3HUZ1T03Ll26lOauK+6ll15K82x+do977rbVfWyq2zHmOrT27t2b5hmegQIAAKiIBRQAAEBFLKAAAAAqYgEFAABQEQsoAACAilhAAQAAVMQCCgAAoCLbAxURayV9UdJKSVclPVxK+cOI6JH0ZUnrJQ1IeqCUkhaNRITmz5/fNJ8zp956znX5bNq0Kc3f/OY3p7nru8i6QFauXJlu29/fn+auS+jKlStp3tPTk+avvvpqms+dm58qb3rTm9I8O+6S73lZtmxZmjuHDh1Kc9dzk+1f15Hleppch0zdnijXIeOu/0Y2lfOXlM9Rrs/GnePuPHHHOevYk6SzZ8+medYT5XrYXNeOu//VmVuv5/Ld/OX2jctdz5y7fnf7b7nlljRf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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(10, 4.8)) # bookskip\n", "ax1 = plt.subplot(1, 2, 1) # bookskip\n", "plt.title('output') # bookskip\n", "plt.imshow(output[0, 0].detach(), cmap='gray')\n", "plt.subplot(1, 2, 2, sharex=ax1, sharey=ax1) # bookskip\n", "plt.imshow(img.mean(0), cmap='gray') # bookskip\n", "plt.title('input') # bookskip\n", "plt.savefig('Ch8_F2_PyTorch.png') # bookskip\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(torch.Size([1, 3, 32, 32]), torch.Size([1, 1, 32, 32]))" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "conv = nn.Conv2d(3, 1, kernel_size=3, padding=1) # <1>\n", "output = conv(img.unsqueeze(0))\n", "img.unsqueeze(0).shape, output.shape" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "with torch.no_grad():\n", " conv.bias.zero_()\n", " \n", "with torch.no_grad():\n", " conv.weight.fill_(1.0 / 9.0)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "output = conv(img.unsqueeze(0))\n", "plt.figure(figsize=(10, 4.8)) # bookskip\n", "ax1 = plt.subplot(1, 2, 1) # bookskip\n", "plt.title('output') # bookskip\n", "plt.imshow(output[0, 0].detach(), cmap='gray')\n", "plt.subplot(1, 2, 2, sharex=ax1, sharey=ax1) # bookskip\n", "plt.imshow(img.mean(0), cmap='gray') # bookskip\n", "plt.title('input') # bookskip\n", "plt.savefig('Ch8_F4_PyTorch.png') # bookskip\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "conv = nn.Conv2d(3, 1, kernel_size=3, padding=1)\n", "\n", "with torch.no_grad():\n", " conv.weight[:] = torch.tensor([[-1.0, 0.0, 1.0],\n", " [-1.0, 0.0, 1.0],\n", " [-1.0, 0.0, 1.0]])\n", " conv.bias.zero_()" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "image/png": "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NK+/m6Cjo0P33HNP3fzo0aPp9q4rxHWRRESaj4yMpLnrw+js7KybuS4f1/NUSklz1/XT0dGR5q5nxY3PHRu3vTt22b6VpPXr16e52/+u68j1bGU9NOfPn0+3XblyZZr39fWleU9PT5q7fes6ZlzPSyM9Km8lXV1devDBB+vmbj+4vprly5enuTsO7hz927/92zR/8cUX62aup8h1+bj5x10jbv5zPU+uh87Nn+72n3/++TR385d7fBcvXkzzEydOpPn27dvTfHh4uG62e/fudFv3vOo6+jZt2pTmriPR3b/bvpEeKl6BAgAAqIgFFAAAQEUsoAAAACpiAQUAAFARCygAAICKWEABAABUxAIKAACgonntgWpvb9eWLVvq5gcPHky3d11Drs/G9aScPn06zbOeFCnv63E9HI7rSXEdNN3d3WnuuoKynhBJev3119N8fHw8zW+5JT8Vu7q60ry3tzfNXceOe/yuJyrruRkbG0u3dfvW9ai4feM6ZFxPiuuZ2rBhQ5rfKDo7O/We97ynbu76ZNw55rqA3PzV1taW5u4aHRwcrJu5+WfFihVp7nrg3Py1bt26NHfXiOtxcvum0WtodHQ0zd384nqe3PzWSM+W67B6+umn09w995w9ezbN3XWVdfBJfn7NuikdXoECAACoiAUUAABARSygAAAAKmIBBQAAUBELKAAAgIpYQAEAAFTEAgoAAKCiee2BWrhwYdpXceHChXR71yXk+iKWLFmS5u7+jx49muZXr16tm7melJGRkTR3PSLr169Pc9ezcunSpTR3PSXZY5ekiEhz15Hjjr3rKurv709z11Pj9k92/25bt29cx0yj+9b1n7nryvW83ChuueWW9LE2eg67c7DRnih3nJ9//vm6WXt7e7rtxo0b03zPnj1p7s4x19PkuH338ssvp7nrcnNdRo2eG64D0c0Br7zySpqvXLmybrZ169Z0W/fYXAeVe+yNdoy5Dq39+/eneYZXoAAAACpiAQUAAFARCygAAICKWEABAABUxAIKAACgIhZQAAAAFbGAAgAAqMj2QEXEgKTPS1ojaVLSo6WUP4yIHklflHSrpCFJD5VS0qKRUkrax+H6HFwXkev6uOWW/OG6Pgt3/52dnXWzxYsXp9s22gPlepgWLMjXyq6Hxe0710Pitnf37/Le3t4037x5c5q7riV3fDo6Oupmq1at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AZhN015ARUSnpC9L+ngp5aykP5a0WdI9uvYvvN+vs90jEbErIna596kAwFyYjfnL/b5GADeXaS2gImKRrk0+XyilfEWSSiknSikTpZRJSX8i6f7rbVtKebSUsqOUssO90RAAZttszV/uzbAAbi52ARXXPv71mKS9pZTPTPn+1I9d/Yyk/K30ADDPmL8AzJXpfArv3ZJ+UdLzEfHG55k/KekjEXGPpCJpSNKvzckIAWDmmL8AzInpfApvp6TrlRClnSnXMzExobGxsbq560pyPSuuB8r1Vbiuj46OjjQ/ceJE3cz1oLiuDWdgYCDN3fs3Dhw4kOaui2jNmjVp7o5N1qM0HW78ly5dSvNVq1alueupyc6tRs/LrJ9H8h02rt+sq6urodt3+6aZZnP+unr1akPXuPPyyy+n+XPPPZfmr776apq7LqWs68y9f9VdX+4aeP7559P8Pe95T5q7feeOTW9vb5pv27YtzVesWJHmJ0+eTPPjx483dPv33ntvmruut4zr4Dt8+HCaZ8/5kj933PbveMc70tw9d+3bty/N09ue8ZYAAAA3KRZQAAAAFbGAAgAAqIgFFAAAQEUsoAAAACpiAQUAAFARCygAAICK5rXAxfVATU5Optu7PgrXJeT6blzPk+vTyfpwXNfPuXPn0nzduvwXyLueENczNTw8nOZu37rbdx1fbt+67bN+HskfW3duuPvPju+1Muz6jh49muZu+zvvvDPN3dhPnTqV5u7cWrt2bZrfKMbHx9PrxB1H13dz5MiRhrbPepwk3zWUbd/f3183k/z163qWXE+R62lzj+3gwYNp7q4xd424+3cdXK7Hys3P7rnR7b+s662trS3d1s0vg4ODae7O2/vuuy/NXUeZuy5dz16GV6AAAAAqYgEFAABQEQsoAACAilhAAQAAVMQCCgAAoCIWUAAAABWxgAIAAKho3nugzp49WzfPepQk30fh+mhcF9PExESau66NZcuW1c1OnjyZbjs6OprmrgfKdWhlPR+S1NPTk+aXL19O8zNnzqS561Fx9++6OoaGhtLcdYW4riN3/9m56zqo3NhcT4rrsDp//nyauw6t7u7uNHfXxY1ifHw8vY6vXLmSbu+6htx+dnOEO4ddX092nm3fvj3d9tVXX03zQ4cOpfk73/nONHfzw8aNG9PcneOux8l1cLlj63r0BgYG0tzNbxcvXkzzRp7b3Hl59913p/mxY8fS3I3NzY8LFuSvA7n5z3Wcpfc94y0BAABuUiygAAAAKmIBBQAAUBELKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAVzWsPVCkl7Xxob29Pt3ddPC7POqgk3+Pitl++fHndzHVVuB4PlzfaA7Vy5co0d+N39z8yMpLmrqOrs7MzzV2Piuvhcrnr0Mk6eNzYXU+U60lx/UCuo8Zx58bN4sqVK2mfkdvP7ji68+TOO+9Mc9e15vq6stzNfWNjY2nurq+dO3em+dve9rY0X7JkSZq/613vSvP169enuevYyuZ+yV9DrutteHg4zQcHB9O8kR4rd167+cv1O7oeu0Y7CN3zurvuMrwCBQAAUBELKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAVsYACAACoiAUUAABARbYHKiLaJT0laXHt7//3UspvR0SPpC9KulXSkKSHSimns9tasGBB2kfk+iYuXLiQ5q6PwvU9uK6T8+fPp3mmra0tzXt6etLcdVm4HhbXQeM6tFatWpXmbt+6Y+c6aty54XpaXA/W8ePH09z12GSPz3XEuA4ap9F+M9fT0t3dneaug6eZZnP+WrhwYXqeuWvMncPuOLhz2PXluC62oaGhutnChQvTbV2P0bJly9L86tWrae723bFjxxrafuvWrWnueuDc/ODmZ9cTtX379jRfu3Ztmh85ciTN3fyXceftu9/97jR35607N1xHopufGunJm84rUJclva+Usl3SPZI+EBE/LOkTkr5RStki6Ru1PwNAK2H+AjAn7AKqXPPGSy+Lav8VSR+U9Hjt+49L+tCcjBAAZoj5C8BcmdZ7oCJiYUQ8K2lY0pOllO9I6iulHJOk2v9Xz90wAWBmmL8AzIVpLaBKKROllHskrZd0f0TcPd07iIhHImJXROxy79UAgNk2W/PXuXPn5m6QAN5yKn0Kr5QyJulbkj4g6URE9EtS7f/X/W2HpZRHSyk7Sik73C8NBIC50uj85d4IDeDmYhdQEbEqIlbUvl4i6f2S9kl6QtLDtb/2sKSvztUgAWAmmL8AzBVbYyCpX9LjEbFQ1xZcXyql/HVE/J2kL0XERyUdlPRzczhOAJgJ5i8Ac8IuoEopz0m69zrfH5X0o1Xv0PX9ZFzPistdX4XrQnK3n3WluJ4k10WxYEH+YuGpU6fS3L1/Y3x8PM3dvnH71vWouPNicnIyzV3Xh+ticvvHjT/rMnH7dvXq/P3Lrifl0qVLae7OW7fvG+k/a7bZnL8WLlyo7G0Irovs0KFDDeWOm0PccczOAzf/uJ6oTZs2pbnrQXIdfydOnEjzwcHBNHfX/8aNG9PcXUOuJ8v1MLW3t6f5wMBAmt9+++1pnp07Bw4cSLd1P9ru7e1Nc3deuvPa9Zu5+dHN7RmayAEAACpiAQUAAFARCygAAICKWEABAABUxAIKAACgIhZQAAAAFbGAAgAAqCga6WWqfGcRI5Jem/KtXkkn520A1bXy+Fp5bFJrj6+VxybdeOPbWEpZNVeDmS/MX7OulcfXymOTWnt8rTw2aRbnr3ldQP3AnUfsKqXsaNoAjFYeXyuPTWrt8bXy2CTG91bR6vuB8c1cK49Nau3xtfLYpNkdHz/CAwAAqIgFFAAAQEXNXkA92uT7d1p5fK08Nqm1x9fKY5MY31tFq+8HxjdzrTw2qbXH18pjk2ZxfE19DxQAAMBbUbNfgQIAAHjLacoCKiI+EBEvRcQrEfGJZowhExFDEfF8RDwbEbtaYDyfjYjhiHhhyvd6IuLJiNhf+393i43vUxFxpLYPn42In2jS2AYi4v9ExN6I+F5E/Ebt+03ff8nYWmXftUfE/42IPbXx/U7t+03fd83GHFZpLMxfMx9by85fZnxN33/zMX/N+4/wImKhpJclPSjpsKSnJX2klPLivA4kERFDknaUUlqiyyIiHpB0XtLnSyl31773u5JOlVI+XZvAu0sp/6KFxvcpSedLKb/XjDFNGVu/pP5SyncjYpmkZyR9SNIvqcn7LxnbQ2qNfReSlpZSzkfEIkk7Jf2GpJ9Vi5x7zcAcVnkszF8zH1vLzl9mfE2fw+Zj/mrGK1D3S3qllHKglHJF0l9I+mATxvGWUUp5StKpN337g5Ier339uK6dtE1RZ3wtoZRyrJTy3drX5yTtlbROLbD/krG1hHLN+dofF9X+K2qBfddkzGEVMH/NXCvPX2Z8TTcf81czFlDrJB2a8ufDapEdPkWR9DcR8UxEPNLswdTRV0o5Jl07iSWtbvJ4rudjEfFc7SXypv+YJyJulXSvpO+oxfbfm8Ymtci+i4iFEfGspGFJT5ZSWm7fNQFzWOPeCudQS1yDb2jl+UtqzTlsruevZiyg4jrfa7WPAr67lHKfpB+X9Ou1l3hRzR9L2izpHknHJP1+MwcTEZ2Svizp46WUs80cy5tdZ2wts+9KKROllHskrZd0f0Tc3ayxtBDmsBtfy1yDUmvPX1LrzmFzPX81YwF1WNLAlD+vl3S0CeOoq5RytPb/YUl/qWsv2beaE7WfP7/xc+jhJo/n+5RSTtRO3klJf6Im7sPaz7+/LOkLpZSv1L7dEvvvemNrpX33hlLKmKRvSfqAWmTfNRFzWONa+hxqpWuwleeveuNrpf1XG8+czF/NWEA9LWlLRGyKiDZJPy/piSaM47oiYmntzXCKiKWSfkzSC/lWTfGEpIdrXz8s6atNHMsPeOMErfkZNWkf1t5I+JikvaWUz0yJmr7/6o2thfbdqohYUft6iaT3S9qnFth3TcYc1riWPoda6Bps2flLau05bF7mr1LKvP8n6Sd07VMsr0r6V80YQzK22yTtqf33vVYYn6Q/17WXQa/q2r9+PypppaRvSNpf+39Pi43vTyU9L+m52gnb36SxvUfXfrzynKRna//9RCvsv2RsrbLv3iFpd20cL0j6t7XvN33fNfs/5rBK42H+mvnYWnb+MuNr+v6bj/mLJnIAAICKaCIHAACoiAUUAABARSygAAAAKmIBBQAAUBELKAAAgIpYQAEAAFTEAgoAAKAiFlAAAAAV/T9TGXXliXzVJQAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "output = conv(img.unsqueeze(0))\n", "plt.figure(figsize=(10, 4.8)) # bookskip\n", "ax1 = plt.subplot(1, 2, 1) # bookskip\n", "plt.title('output') # bookskip\n", "plt.imshow(output[0, 0].detach(), cmap='gray')\n", "plt.subplot(1, 2, 2, sharex=ax1, sharey=ax1) # bookskip\n", "plt.imshow(img.mean(0), cmap='gray') # bookskip\n", "plt.title('input') # bookskip\n", "plt.savefig('Ch8_F5_PyTorch.png') # bookskip\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(torch.Size([1, 3, 32, 32]), torch.Size([1, 3, 16, 16]))" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pool = nn.MaxPool2d(2)\n", "output = pool(img.unsqueeze(0))\n", "\n", "img.unsqueeze(0).shape, output.shape" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "model = nn.Sequential(\n", " nn.Conv2d(3, 16, kernel_size=3, padding=1),\n", " nn.Tanh(),\n", " nn.MaxPool2d(2),\n", " nn.Conv2d(16, 8, kernel_size=3, padding=1),\n", " nn.Tanh(),\n", " nn.MaxPool2d(2),\n", " # ...\n", " )" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "model = nn.Sequential(\n", " nn.Conv2d(3, 16, kernel_size=3, padding=1),\n", " nn.Tanh(),\n", " nn.MaxPool2d(2),\n", " nn.Conv2d(16, 8, kernel_size=3, padding=1),\n", " nn.Tanh(),\n", " nn.MaxPool2d(2),\n", " # ... <1>\n", " nn.Linear(8 * 8 * 8, 32),\n", " nn.Tanh(),\n", " nn.Linear(32, 2))" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(18090, [432, 16, 1152, 8, 16384, 32, 64, 2])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numel_list = [p.numel() for p in model.parameters()]\n", "sum(numel_list), numel_list" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "scrolled": true, "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "RuntimeError", "evalue": "size mismatch, m1: [64 x 8], m2: [512 x 32] at ../aten/src/TH/generic/THTensorMath.cpp:41", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmodel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mimg\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munsqueeze\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_slow_forward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 538\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 539\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 540\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mhook\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_forward_hooks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 541\u001b[0m \u001b[0mhook_result\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhook\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/torch/nn/modules/container.py\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, input)\u001b[0m\n\u001b[1;32m 98\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 99\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mmodule\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 100\u001b[0;31m \u001b[0minput\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodule\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 101\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_slow_forward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 538\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 539\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 540\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mhook\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_forward_hooks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 541\u001b[0m \u001b[0mhook_result\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhook\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/torch/nn/modules/linear.py\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, input)\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 86\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 87\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mF\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlinear\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mweight\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbias\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 88\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 89\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mextra_repr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py\u001b[0m in \u001b[0;36mlinear\u001b[0;34m(input, weight, bias)\u001b[0m\n\u001b[1;32m 1377\u001b[0m \u001b[0mret\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maddmm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbias\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mweight\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1378\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1379\u001b[0;31m \u001b[0moutput\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmatmul\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mweight\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1380\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mbias\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1381\u001b[0m \u001b[0moutput\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mbias\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mRuntimeError\u001b[0m: size mismatch, m1: [64 x 8], m2: [512 x 32] at ../aten/src/TH/generic/THTensorMath.cpp:41" ] } ], "source": [ "model(img.unsqueeze(0))" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "class Net(nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)\n", " self.act1 = nn.Tanh()\n", " self.pool1 = nn.MaxPool2d(2)\n", " self.conv2 = nn.Conv2d(16, 8, kernel_size=3, padding=1)\n", " self.act2 = nn.Tanh()\n", " self.pool2 = nn.MaxPool2d(2)\n", " self.fc1 = nn.Linear(8 * 8 * 8, 32)\n", " self.act3 = nn.Tanh()\n", " self.fc2 = nn.Linear(32, 2)\n", "\n", " def forward(self, x):\n", " out = self.pool1(self.act1(self.conv1(x)))\n", " out = self.pool2(self.act2(self.conv2(out)))\n", " out = out.view(-1, 8 * 8 * 8) # <1>\n", " out = self.act3(self.fc1(out))\n", " out = self.fc2(out)\n", " return out" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(18090, [432, 16, 1152, 8, 16384, 32, 64, 2])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = Net()\n", "\n", "numel_list = [p.numel() for p in model.parameters()]\n", "sum(numel_list), numel_list" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "import torch.nn.functional as F\n", "\n", "class Net(nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)\n", " self.conv2 = nn.Conv2d(16, 8, kernel_size=3, padding=1)\n", " self.fc1 = nn.Linear(8 * 8 * 8, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = F.max_pool2d(torch.tanh(self.conv1(x)), 2)\n", " out = F.max_pool2d(torch.tanh(self.conv2(out)), 2)\n", " out = out.view(-1, 8 * 8 * 8)\n", " out = torch.tanh(self.fc1(out))\n", " out = self.fc2(out)\n", " return out" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tensor([[-0.0157, 0.1143]], grad_fn=)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = Net()\n", "model(img.unsqueeze(0))" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "import datetime # <1>\n", "\n", "def training_loop(n_epochs, optimizer, model, loss_fn, train_loader):\n", " for epoch in range(1, n_epochs + 1): # <2>\n", " loss_train = 0.0\n", " for imgs, labels in train_loader: # <3>\n", " \n", " outputs = model(imgs) # <4>\n", " \n", " loss = loss_fn(outputs, labels) # <5>\n", "\n", " optimizer.zero_grad() # <6>\n", " \n", " loss.backward() # <7>\n", " \n", " optimizer.step() # <8>\n", "\n", " loss_train += loss.item() # <9>\n", "\n", " if epoch == 1 or epoch % 10 == 0:\n", " print('{} Epoch {}, Training loss {}'.format(\n", " datetime.datetime.now(), epoch,\n", " loss_train / len(train_loader))) # <10>" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:07:21.889707 Epoch 1, Training loss 0.5634813266954605\n", "2020-01-16 23:07:37.560610 Epoch 10, Training loss 0.3277610331109375\n", "2020-01-16 23:07:54.966180 Epoch 20, Training loss 0.3035225479086493\n", "2020-01-16 23:08:12.361597 Epoch 30, Training loss 0.28249378549824855\n", "2020-01-16 23:08:29.769820 Epoch 40, Training loss 0.2611226033253275\n", "2020-01-16 23:08:47.185401 Epoch 50, Training loss 0.24105800626574048\n", "2020-01-16 23:09:04.644522 Epoch 60, Training loss 0.21997178820477928\n", "2020-01-16 23:09:22.079625 Epoch 70, Training loss 0.20370126601047578\n", "2020-01-16 23:09:39.593780 Epoch 80, Training loss 0.18939699422401987\n", "2020-01-16 23:09:57.111441 Epoch 90, Training loss 0.17283396527266046\n", "2020-01-16 23:10:14.632351 Epoch 100, Training loss 0.1614033816868712\n" ] } ], "source": [ "train_loader = torch.utils.data.DataLoader(cifar2, batch_size=64,\n", " shuffle=True) # <1>\n", "\n", "model = Net() # <2>\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2) # <3>\n", "loss_fn = nn.CrossEntropyLoss() # <4>\n", "\n", "training_loop( # <5>\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Accuracy train: 0.93\n", "Accuracy val: 0.89\n" ] } ], "source": [ "train_loader = torch.utils.data.DataLoader(cifar2, batch_size=64,\n", " shuffle=False)\n", "val_loader = torch.utils.data.DataLoader(cifar2_val, batch_size=64,\n", " shuffle=False)\n", "\n", "def validate(model, train_loader, val_loader):\n", " for name, loader in [(\"train\", train_loader), (\"val\", val_loader)]:\n", " correct = 0\n", " total = 0\n", "\n", " with torch.no_grad(): # <1>\n", " for imgs, labels in loader:\n", " outputs = model(imgs)\n", " _, predicted = torch.max(outputs, dim=1) # <2>\n", " total += labels.shape[0] # <3>\n", " correct += int((predicted == labels).sum()) # <4>\n", "\n", " print(\"Accuracy {}: {:.2f}\".format(name , correct / total))\n", "\n", "validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "torch.save(model.state_dict(), data_path + 'birds_vs_airplanes.pt')" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "loaded_model = Net() # <1>\n", "loaded_model.load_state_dict(torch.load(data_path\n", " + 'birds_vs_airplanes.pt'))" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Training on device cuda.\n" ] } ], "source": [ "device = (torch.device('cuda') if torch.cuda.is_available()\n", " else torch.device('cpu'))\n", "print(f\"Training on device {device}.\")" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "import datetime\n", "\n", "def training_loop(n_epochs, optimizer, model, loss_fn, train_loader):\n", " for epoch in range(1, n_epochs + 1):\n", " loss_train = 0.0\n", " for imgs, labels in train_loader:\n", " imgs = imgs.to(device=device) # <1>\n", " labels = labels.to(device=device)\n", " outputs = model(imgs)\n", " loss = loss_fn(outputs, labels)\n", "\n", " optimizer.zero_grad()\n", " loss.backward()\n", " optimizer.step()\n", "\n", " loss_train += loss.item()\n", "\n", " if epoch == 1 or epoch % 10 == 0:\n", " print('{} Epoch {}, Training loss {}'.format(\n", " datetime.datetime.now(), epoch,\n", " loss_train / len(train_loader)))" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:10:35.563216 Epoch 1, Training loss 0.5717791349265227\n", "2020-01-16 23:10:39.730262 Epoch 10, Training loss 0.3285350770137872\n", "2020-01-16 23:10:45.906321 Epoch 20, Training loss 0.29493294959994637\n", "2020-01-16 23:10:52.086905 Epoch 30, Training loss 0.26962305994550134\n", "2020-01-16 23:10:56.551582 Epoch 40, Training loss 0.24709946277794564\n", "2020-01-16 23:11:00.991432 Epoch 50, Training loss 0.22623272664892446\n", "2020-01-16 23:11:05.421524 Epoch 60, Training loss 0.20996672821462534\n", "2020-01-16 23:11:09.951312 Epoch 70, Training loss 0.1934866009719053\n", "2020-01-16 23:11:14.499484 Epoch 80, Training loss 0.1799132404908253\n", "2020-01-16 23:11:19.047609 Epoch 90, Training loss 0.16620008706761774\n", "2020-01-16 23:11:23.590435 Epoch 100, Training loss 0.15667157247662544\n" ] } ], "source": [ "train_loader = torch.utils.data.DataLoader(cifar2, batch_size=64,\n", " shuffle=True)\n", "\n", "model = Net().to(device=device) # <1>\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Accuracy train: 0.93\n", "Accuracy val: 0.89\n" ] } ], "source": [ "train_loader = torch.utils.data.DataLoader(cifar2, batch_size=64,\n", " shuffle=False)\n", "val_loader = torch.utils.data.DataLoader(cifar2_val, batch_size=64,\n", " shuffle=False)\n", "all_acc_dict = collections.OrderedDict()\n", "\n", "def validate(model, train_loader, val_loader):\n", " accdict = {}\n", " for name, loader in [(\"train\", train_loader), (\"val\", val_loader)]:\n", " correct = 0\n", " total = 0\n", "\n", " with torch.no_grad():\n", " for imgs, labels in loader:\n", " imgs = imgs.to(device=device)\n", " labels = labels.to(device=device)\n", " outputs = model(imgs)\n", " _, predicted = torch.max(outputs, dim=1) # <1>\n", " total += labels.shape[0]\n", " correct += int((predicted == labels).sum())\n", "\n", " print(\"Accuracy {}: {:.2f}\".format(name , correct / total))\n", " accdict[name] = correct / total\n", " return accdict\n", "\n", "all_acc_dict[\"baseline\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "loaded_model = Net().to(device=device)\n", "loaded_model.load_state_dict(torch.load(data_path\n", " + 'birds_vs_airplanes.pt',\n", " map_location=device))" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "class NetWidth(nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)\n", " self.conv2 = nn.Conv2d(32, 16, kernel_size=3, padding=1)\n", " self.fc1 = nn.Linear(16 * 8 * 8, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = F.max_pool2d(torch.tanh(self.conv1(x)), 2)\n", " out = F.max_pool2d(torch.tanh(self.conv2(out)), 2)\n", " out = out.view(-1, 16 * 8 * 8)\n", " out = torch.tanh(self.fc1(out))\n", " out = self.fc2(out)\n", " return out" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:11:25.327462 Epoch 1, Training loss 0.5696582685989938\n", "2020-01-16 23:11:29.501642 Epoch 10, Training loss 0.32219217129194055\n", "2020-01-16 23:11:34.735670 Epoch 20, Training loss 0.2806013466636087\n", "2020-01-16 23:11:40.264154 Epoch 30, Training loss 0.24591451655527588\n", "2020-01-16 23:11:46.186918 Epoch 40, Training loss 0.21836834832741198\n", "2020-01-16 23:11:51.856774 Epoch 50, Training loss 0.1943585573677804\n", "2020-01-16 23:11:57.697704 Epoch 60, Training loss 0.1715057151522606\n", "2020-01-16 23:12:03.421155 Epoch 70, Training loss 0.1487851360231448\n", "2020-01-16 23:12:09.117316 Epoch 80, Training loss 0.12702234032427429\n", "2020-01-16 23:12:14.856157 Epoch 90, Training loss 0.10666295210979167\n", "2020-01-16 23:12:20.585829 Epoch 100, Training loss 0.08831981746301909\n", "Accuracy train: 0.96\n", "Accuracy val: 0.89\n" ] }, { "data": { "text/plain": [ "{'train': 0.9633, 'val': 0.89}" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = NetWidth().to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "\n", "validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "class NetWidth(nn.Module):\n", " def __init__(self, n_chans1=32):\n", " super().__init__()\n", " self.n_chans1 = n_chans1\n", " self.conv1 = nn.Conv2d(3, n_chans1, kernel_size=3, padding=1)\n", " self.conv2 = nn.Conv2d(n_chans1, n_chans1 // 2, kernel_size=3,\n", " padding=1)\n", " self.fc1 = nn.Linear(8 * 8 * n_chans1 // 2, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = F.max_pool2d(torch.tanh(self.conv1(x)), 2)\n", " out = F.max_pool2d(torch.tanh(self.conv2(out)), 2)\n", " out = out.view(-1, 8 * 8 * self.n_chans1 // 2)\n", " out = torch.tanh(self.fc1(out))\n", " out = self.fc2(out)\n", " return out\n" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:12:22.646242 Epoch 1, Training loss 0.5444508081029176\n", "2020-01-16 23:12:26.841887 Epoch 10, Training loss 0.31707597633076323\n", "2020-01-16 23:12:31.310813 Epoch 20, Training loss 0.27454944429503886\n", "2020-01-16 23:12:35.891615 Epoch 30, Training loss 0.2425653456123012\n", "2020-01-16 23:12:40.420664 Epoch 40, Training loss 0.21338120942852298\n", "2020-01-16 23:12:44.954698 Epoch 50, Training loss 0.18698934290059813\n", "2020-01-16 23:12:49.527939 Epoch 60, Training loss 0.16319987830367816\n", "2020-01-16 23:12:54.380134 Epoch 70, Training loss 0.14089395708529054\n", "2020-01-16 23:12:59.247492 Epoch 80, Training loss 0.11998948957889703\n", "2020-01-16 23:13:04.068846 Epoch 90, Training loss 0.10076516851260783\n", "2020-01-16 23:13:08.913110 Epoch 100, Training loss 0.0832248356217032\n", "Accuracy train: 0.96\n", "Accuracy val: 0.90\n" ] } ], "source": [ "model = NetWidth(n_chans1=32).to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "\n", "all_acc_dict[\"width\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "38386" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sum(p.numel() for p in model.parameters())" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "def training_loop_l2reg(n_epochs, optimizer, model, loss_fn,\n", " train_loader):\n", " for epoch in range(1, n_epochs + 1):\n", " loss_train = 0.0\n", " for imgs, labels in train_loader:\n", " imgs = imgs.to(device=device)\n", " labels = labels.to(device=device)\n", " outputs = model(imgs)\n", " loss = loss_fn(outputs, labels)\n", "\n", " l2_lambda = 0.001\n", " l2_norm = sum(p.pow(2.0).sum()\n", " for p in model.parameters()) # <1>\n", " loss = loss + l2_lambda * l2_norm\n", "\n", " optimizer.zero_grad()\n", " loss.backward()\n", " optimizer.step()\n", " \n", " loss_train += loss.item()\n", " if epoch == 1 or epoch % 10 == 0:\n", " print('{} Epoch {}, Training loss {}'.format(\n", " datetime.datetime.now(), epoch,\n", " loss_train / len(train_loader)))\n" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:13:10.225792 Epoch 1, Training loss 0.584277889151482\n", "2020-01-16 23:13:17.795340 Epoch 10, Training loss 0.36633389723149073\n", "2020-01-16 23:13:26.277897 Epoch 20, Training loss 0.3225795095133933\n", "2020-01-16 23:13:35.341923 Epoch 30, Training loss 0.29615209541123383\n", "2020-01-16 23:13:44.351376 Epoch 40, Training loss 0.2775719240782367\n", "2020-01-16 23:13:53.296178 Epoch 50, Training loss 0.2636590329514947\n", "2020-01-16 23:14:02.220169 Epoch 60, Training loss 0.2515565001755763\n", "2020-01-16 23:14:11.076573 Epoch 70, Training loss 0.24007968713713299\n", "2020-01-16 23:14:20.807501 Epoch 80, Training loss 0.22931366546708307\n", "2020-01-16 23:14:31.504612 Epoch 90, Training loss 0.21898466424577556\n", "2020-01-16 23:14:41.934048 Epoch 100, Training loss 0.20924225397360552\n", "Accuracy train: 0.90\n", "Accuracy val: 0.87\n" ] } ], "source": [ "model = Net().to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop_l2reg(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "all_acc_dict[\"l2 reg\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [], "source": [ "class NetDropout(nn.Module):\n", " def __init__(self, n_chans1=32):\n", " super().__init__()\n", " self.n_chans1 = n_chans1\n", " self.conv1 = nn.Conv2d(3, n_chans1, kernel_size=3, padding=1)\n", " self.conv1_dropout = nn.Dropout2d(p=0.4)\n", " self.conv2 = nn.Conv2d(n_chans1, n_chans1 // 2, kernel_size=3,\n", " padding=1)\n", " self.conv2_dropout = nn.Dropout2d(p=0.4)\n", " self.fc1 = nn.Linear(8 * 8 * n_chans1 // 2, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = F.max_pool2d(torch.tanh(self.conv1(x)), 2)\n", " out = self.conv1_dropout(out)\n", " out = F.max_pool2d(torch.tanh(self.conv2(out)), 2)\n", " out = self.conv2_dropout(out)\n", " out = out.view(-1, 8 * 8 * self.n_chans1 // 2)\n", " out = torch.tanh(self.fc1(out))\n", " out = self.fc2(out)\n", " return out" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:14:42.863912 Epoch 1, Training loss 0.5800061457476039\n", "2020-01-16 23:14:47.868802 Epoch 10, Training loss 0.38074702850192976\n", "2020-01-16 23:14:53.145910 Epoch 20, Training loss 0.34908065987620385\n", "2020-01-16 23:14:58.056904 Epoch 30, Training loss 0.32977743029214773\n", "2020-01-16 23:15:03.131635 Epoch 40, Training loss 0.3125769621247699\n", "2020-01-16 23:15:08.321374 Epoch 50, Training loss 0.29207915010725616\n", "2020-01-16 23:15:13.535053 Epoch 60, Training loss 0.28212467301043737\n", "2020-01-16 23:15:18.876606 Epoch 70, Training loss 0.2723999054758412\n", "2020-01-16 23:15:24.114116 Epoch 80, Training loss 0.2627566327714616\n", "2020-01-16 23:15:29.342708 Epoch 90, Training loss 0.2537129214804643\n", "2020-01-16 23:15:34.594518 Epoch 100, Training loss 0.23995957129700168\n", "Accuracy train: 0.89\n", "Accuracy val: 0.88\n" ] } ], "source": [ "model = NetDropout(n_chans1=32).to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "all_acc_dict[\"dropout\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "class NetBatchNorm(nn.Module):\n", " def __init__(self, n_chans1=32):\n", " super().__init__()\n", " self.n_chans1 = n_chans1\n", " self.conv1 = nn.Conv2d(3, n_chans1, kernel_size=3, padding=1)\n", " self.conv1_batchnorm = nn.BatchNorm2d(num_features=n_chans1)\n", " self.conv2 = nn.Conv2d(n_chans1, n_chans1 // 2, kernel_size=3, \n", " padding=1)\n", " self.conv2_batchnorm = nn.BatchNorm2d(num_features=n_chans1 // 2)\n", " self.fc1 = nn.Linear(8 * 8 * n_chans1 // 2, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = self.conv1_batchnorm(self.conv1(x))\n", " out = F.max_pool2d(torch.tanh(out), 2)\n", " out = self.conv2_batchnorm(self.conv2(out))\n", " out = F.max_pool2d(torch.tanh(out), 2)\n", " out = out.view(-1, 8 * 8 * self.n_chans1 // 2)\n", " out = torch.tanh(self.fc1(out))\n", " out = self.fc2(out)\n", " return out" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:15:35.691938 Epoch 1, Training loss 0.4739942996744897\n", "2020-01-16 23:15:40.475810 Epoch 10, Training loss 0.25983829872243724\n", "2020-01-16 23:15:45.771541 Epoch 20, Training loss 0.19428231121058676\n", "2020-01-16 23:15:51.089952 Epoch 30, Training loss 0.14371838975863852\n", "2020-01-16 23:15:56.515419 Epoch 40, Training loss 0.101108748762376\n", "2020-01-16 23:16:01.824733 Epoch 50, Training loss 0.06699353904955706\n", "2020-01-16 23:16:07.094885 Epoch 60, Training loss 0.041509037291642965\n", "2020-01-16 23:16:12.655136 Epoch 70, Training loss 0.032447671671961525\n", "2020-01-16 23:16:18.188782 Epoch 80, Training loss 0.017081547878492788\n", "2020-01-16 23:16:23.578206 Epoch 90, Training loss 0.011301719506455076\n", "2020-01-16 23:16:28.884481 Epoch 100, Training loss 0.007566932796435371\n", "Accuracy train: 1.00\n", "Accuracy val: 0.89\n" ] } ], "source": [ "model = NetBatchNorm(n_chans1=32).to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "all_acc_dict[\"batch_norm\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [], "source": [ "class NetDepth(nn.Module):\n", " def __init__(self, n_chans1=32):\n", " super().__init__()\n", " self.n_chans1 = n_chans1\n", " self.conv1 = nn.Conv2d(3, n_chans1, kernel_size=3, padding=1)\n", " self.conv2 = nn.Conv2d(n_chans1, n_chans1 // 2, kernel_size=3,\n", " padding=1)\n", " self.conv3 = nn.Conv2d(n_chans1 // 2, n_chans1 // 2,\n", " kernel_size=3, padding=1)\n", " self.fc1 = nn.Linear(4 * 4 * n_chans1 // 2, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = F.max_pool2d(torch.relu(self.conv1(x)), 2)\n", " out = F.max_pool2d(torch.relu(self.conv2(out)), 2)\n", " out = F.max_pool2d(torch.relu(self.conv3(out)), 2)\n", " out = out.view(-1, 4 * 4 * self.n_chans1 // 2)\n", " out = torch.relu(self.fc1(out))\n", " out = self.fc2(out)\n", " return out" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:16:30.447670 Epoch 1, Training loss 0.6548013091087341\n", "2020-01-16 23:16:35.367838 Epoch 10, Training loss 0.34000502014236084\n", "2020-01-16 23:16:40.826647 Epoch 20, Training loss 0.30152006637138923\n", "2020-01-16 23:16:46.217950 Epoch 30, Training loss 0.2726998861618103\n", "2020-01-16 23:16:51.688735 Epoch 40, Training loss 0.24409755509180628\n", "2020-01-16 23:16:57.099919 Epoch 50, Training loss 0.21648093004515218\n", "2020-01-16 23:17:02.744809 Epoch 60, Training loss 0.19037676303629664\n", "2020-01-16 23:17:08.267520 Epoch 70, Training loss 0.16683378478713856\n", "2020-01-16 23:17:13.854005 Epoch 80, Training loss 0.14403212810777555\n", "2020-01-16 23:17:19.896823 Epoch 90, Training loss 0.12033685920819355\n", "2020-01-16 23:17:25.857992 Epoch 100, Training loss 0.09564469111668077\n", "Accuracy train: 0.95\n", "Accuracy val: 0.90\n" ] } ], "source": [ "model = NetDepth(n_chans1=32).to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "all_acc_dict[\"depth\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [], "source": [ "class NetRes(nn.Module):\n", " def __init__(self, n_chans1=32):\n", " super().__init__()\n", " self.n_chans1 = n_chans1\n", " self.conv1 = nn.Conv2d(3, n_chans1, kernel_size=3, padding=1)\n", " self.conv2 = nn.Conv2d(n_chans1, n_chans1 // 2, kernel_size=3,\n", " padding=1)\n", " self.conv3 = nn.Conv2d(n_chans1 // 2, n_chans1 // 2,\n", " kernel_size=3, padding=1)\n", " self.fc1 = nn.Linear(4 * 4 * n_chans1 // 2, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = F.max_pool2d(torch.relu(self.conv1(x)), 2)\n", " out = F.max_pool2d(torch.relu(self.conv2(out)), 2)\n", " out1 = out\n", " out = F.max_pool2d(torch.relu(self.conv3(out)) + out1, 2)\n", " out = out.view(-1, 4 * 4 * self.n_chans1 // 2)\n", " out = torch.relu(self.fc1(out))\n", " out = self.fc2(out)\n", " return out" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:17:26.950170 Epoch 1, Training loss 0.6650038665267313\n", "2020-01-16 23:17:32.211548 Epoch 10, Training loss 0.3292607384122861\n", "2020-01-16 23:17:37.607961 Epoch 20, Training loss 0.2860302617595454\n", "2020-01-16 23:17:43.125477 Epoch 30, Training loss 0.2551692724227905\n", "2020-01-16 23:17:48.706900 Epoch 40, Training loss 0.22809805450545753\n", "2020-01-16 23:17:54.233746 Epoch 50, Training loss 0.20181633408661862\n", "2020-01-16 23:17:59.702800 Epoch 60, Training loss 0.17625007239781368\n", "2020-01-16 23:18:05.151562 Epoch 70, Training loss 0.15140700171802454\n", "2020-01-16 23:18:10.695097 Epoch 80, Training loss 0.1257421809491838\n", "2020-01-16 23:18:16.346922 Epoch 90, Training loss 0.09920599323454177\n", "2020-01-16 23:18:22.144790 Epoch 100, Training loss 0.07639109212786528\n", "Accuracy train: 0.97\n", "Accuracy val: 0.90\n" ] } ], "source": [ "model = NetRes(n_chans1=32).to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=1e-2)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "all_acc_dict[\"res\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [], "source": [ "class ResBlock(nn.Module):\n", " def __init__(self, n_chans):\n", " super(ResBlock, self).__init__()\n", " self.conv = nn.Conv2d(n_chans, n_chans, kernel_size=3,\n", " padding=1, bias=False) # <1>\n", " self.batch_norm = nn.BatchNorm2d(num_features=n_chans)\n", " torch.nn.init.kaiming_normal_(self.conv.weight,\n", " nonlinearity='relu') # <2>\n", " torch.nn.init.constant_(self.batch_norm.weight, 0.5)\n", " torch.nn.init.zeros_(self.batch_norm.bias)\n", "\n", " def forward(self, x):\n", " out = self.conv(x)\n", " out = self.batch_norm(out)\n", " out = torch.relu(out)\n", " return out + x" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [], "source": [ "class NetResDeep(nn.Module):\n", " def __init__(self, n_chans1=32, n_blocks=10):\n", " super().__init__()\n", " self.n_chans1 = n_chans1\n", " self.conv1 = nn.Conv2d(3, n_chans1, kernel_size=3, padding=1)\n", " self.resblocks = nn.Sequential(\n", " *(n_blocks * [ResBlock(n_chans=n_chans1)]))\n", " self.fc1 = nn.Linear(8 * 8 * n_chans1, 32)\n", " self.fc2 = nn.Linear(32, 2)\n", " \n", " def forward(self, x):\n", " out = F.max_pool2d(torch.relu(self.conv1(x)), 2)\n", " out = self.resblocks(out)\n", " out = F.max_pool2d(out, 2)\n", " out = out.view(-1, 8 * 8 * self.n_chans1)\n", " out = torch.relu(self.fc1(out))\n", " out = self.fc2(out)\n", " return out\n", " \n" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2020-01-16 23:18:30.438073 Epoch 1, Training loss 2.2735002310412704\n", "2020-01-16 23:19:39.382842 Epoch 10, Training loss 0.3779076840847161\n", "2020-01-16 23:20:55.438525 Epoch 20, Training loss 0.3001826848763569\n", "2020-01-16 23:22:12.180387 Epoch 30, Training loss 0.24923191243296217\n", "2020-01-16 23:23:29.717063 Epoch 40, Training loss 0.20788565244834134\n", "2020-01-16 23:24:45.533130 Epoch 50, Training loss 0.15866709291745143\n", "2020-01-16 23:26:01.732320 Epoch 60, Training loss 0.12134665039599321\n", "2020-01-16 23:27:17.569136 Epoch 70, Training loss 0.08729177155787018\n", "2020-01-16 23:28:33.241105 Epoch 80, Training loss 0.07246267570740288\n", "2020-01-16 23:29:49.378612 Epoch 90, Training loss 0.05779321811156003\n", "2020-01-16 23:31:05.654037 Epoch 100, Training loss 0.06602069945222917\n", "Accuracy train: 0.97\n", "Accuracy val: 0.86\n" ] } ], "source": [ "model = NetResDeep(n_chans1=32, n_blocks=100).to(device=device)\n", "optimizer = optim.SGD(model.parameters(), lr=3e-3)\n", "loss_fn = nn.CrossEntropyLoss()\n", "\n", "training_loop(\n", " n_epochs = 100,\n", " optimizer = optimizer,\n", " model = model,\n", " loss_fn = loss_fn,\n", " train_loader = train_loader,\n", ")\n", "all_acc_dict[\"res deep\"] = validate(model, train_loader, val_loader)" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "trn_acc = [v['train'] for k, v in all_acc_dict.items()]\n", "val_acc = [v['val'] for k, v in all_acc_dict.items()]\n", "\n", "width =0.3\n", "plt.bar(np.arange(len(trn_acc)), trn_acc, width=width, label='train')\n", "plt.bar(np.arange(len(val_acc))+ width, val_acc, width=width, label='val')\n", "plt.xticks(np.arange(len(val_acc))+ width/2, list(all_acc_dict.keys()),\n", " rotation=60)\n", "plt.ylabel('accuracy')\n", "plt.legend(loc='lower right')\n", "plt.ylim(0.7, 1)\n", "plt.savefig('accuracy_comparison.png', bbox_inches='tight')\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Tags", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 2 }