├── DeepLearningDemo_CNN_GaussParams.ipynb └── README.md /DeepLearningDemo_CNN_GaussParams.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "bhWV8oes-wKR" 7 | }, 8 | "source": [ 9 | "# COURSE: A deep understanding of deep learning\n", 10 | "### Demo: Use a CNN to discover 2D Gaussian parameters\n", 11 | "#### TEACHER: Mike X Cohen, sincxpress.com\n", 12 | "##### COURSE URL: https://www.udemy.com/course/deeplearning_x/?couponCode=202306" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": { 19 | "id": "YeuAheYyhdZw" 20 | }, 21 | "outputs": [], 22 | "source": [ 23 | "# import libraries\n", 24 | "import numpy as np\n", 25 | "\n", 26 | "import torch\n", 27 | "import torch.nn as nn\n", 28 | "import torch.nn.functional as F\n", 29 | "from torch.utils.data import DataLoader,TensorDataset\n", 30 | "from sklearn.model_selection import train_test_split\n", 31 | "\n", 32 | "# model summary info\n", 33 | "from torchsummary import summary\n", 34 | "\n", 35 | "import matplotlib.pyplot as plt\n", 36 | "from IPython import display\n", 37 | "display.set_matplotlib_formats('svg')" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": { 43 | "id": "0HOkOefftqyg" 44 | }, 45 | "source": [ 46 | "# Create Gaussian blurs with different widths" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": { 53 | "id": "MU7rvmWuhjud" 54 | }, 55 | "outputs": [], 56 | "source": [ 57 | "nGauss = 1000\n", 58 | "imgSize = 91\n", 59 | "\n", 60 | "x = np.linspace(-4,4,imgSize)\n", 61 | "X,Y = np.meshgrid(x,x)\n", 62 | "\n", 63 | "# initialize tensors containing images and labels\n", 64 | "images = torch.zeros(nGauss,1,imgSize,imgSize)\n", 65 | "labels = torch.zeros(nGauss,3)\n", 66 | "\n", 67 | "for i in range(nGauss):\n", 68 | "\n", 69 | " # location and width parameters\n", 70 | " loc = np.max(x)/2 * np.random.randn(2) # center coordinate\n", 71 | " wid = np.random.rand()*10 + 5 # width of Gaussian\n", 72 | "\n", 73 | " # create the gaussian with random centers\n", 74 | " G = np.exp( -( (X-loc[0])**2 + (Y-loc[1])**2) / wid )\n", 75 | " G = G + np.random.randn(imgSize,imgSize)/10\n", 76 | " \n", 77 | " # add to the tensor\n", 78 | " images[i,:,:,:] = torch.Tensor(G).view(1,imgSize,imgSize)\n", 79 | " labels[i,:] = torch.Tensor( [loc[0],loc[1],wid] )" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "metadata": { 86 | "id": "4rsf92yfrGoC" 87 | }, 88 | "outputs": [], 89 | "source": [ 90 | "# visualize some images\n", 91 | "fig,axs = plt.subplots(3,7,figsize=(15,7))\n", 92 | "\n", 93 | "for i,ax in enumerate(axs.flatten()):\n", 94 | " whichpic = np.random.randint(nGauss)\n", 95 | " G = np.squeeze( images[whichpic,:,:] )\n", 96 | " ax.imshow(G,vmin=-1,vmax=1,cmap='jet',extent=[-4,4,-4,4],origin='top')\n", 97 | " ax.set_title(f'XY=({labels[whichpic,0]:.0f},{labels[whichpic,1]:.0f}), W={labels[whichpic,2]:.0f}')\n", 98 | " ax.plot([-4,4],[0,0],'w--')\n", 99 | " ax.plot([0,0],[-4,4],'w--')\n", 100 | " ax.set_xticks([])\n", 101 | " ax.set_yticks([])\n", 102 | "\n", 103 | "plt.tight_layout()\n", 104 | "plt.show()" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": { 110 | "id": "OhLQ2YSvpiGj" 111 | }, 112 | "source": [ 113 | "# Create train/test groups using DataLoader" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": null, 119 | "metadata": { 120 | "id": "Y_tZ1ymVp0Sf" 121 | }, 122 | "outputs": [], 123 | "source": [ 124 | "# use scikitlearn to split the data\n", 125 | "train_data,test_data, train_labels,test_labels = train_test_split(images, labels, test_size=.1)\n", 126 | "\n", 127 | "# convert into PyTorch Datasets\n", 128 | "train_data = TensorDataset(train_data,train_labels)\n", 129 | "test_data = TensorDataset(test_data,test_labels)\n", 130 | "\n", 131 | "# translate into dataloader objects\n", 132 | "batchsize = 16\n", 133 | "train_loader = DataLoader(train_data,batch_size=batchsize,shuffle=True,drop_last=True)\n", 134 | "test_loader = DataLoader(test_data,batch_size=test_data.tensors[0].shape[0])" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": { 141 | "id": "Zhsr13r2rk8I" 142 | }, 143 | "outputs": [], 144 | "source": [ 145 | "# check size (should be images X channels X width X height\n", 146 | "print( train_loader.dataset.tensors[0].shape )\n", 147 | "print( train_loader.dataset.tensors[1].shape )" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": { 153 | "id": "OK8Opkhgp0bO" 154 | }, 155 | "source": [ 156 | "# Create the DL model" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": { 163 | "id": "JK3OO3tAtZkA" 164 | }, 165 | "outputs": [], 166 | "source": [ 167 | "# create a class for the model\n", 168 | "def makeTheNet():\n", 169 | "\n", 170 | " class gausnet(nn.Module):\n", 171 | " def __init__(self):\n", 172 | " super().__init__()\n", 173 | " \n", 174 | " # all layers in one go using nn.Sequential\n", 175 | " self.enc = nn.Sequential(\n", 176 | " \n", 177 | " # conv/pool block 1\n", 178 | " nn.Conv2d(1,6,3,padding=1), # output size: (91+2*1-3)/1 + 1 = 91\n", 179 | " nn.ReLU(), # \n", 180 | " nn.AvgPool2d(2,2), # output size: 91/2 = 45\n", 181 | " \n", 182 | " # conv/pool block 2\n", 183 | " nn.Conv2d(6,4,3,padding=1), # output size: (45+2*1-3)/1 + 1 = 45\n", 184 | " nn.ReLU(), # \n", 185 | " nn.AvgPool2d(2,2), # output size: 45/2 = 22\n", 186 | " \n", 187 | " # linear decision layer\n", 188 | " nn.Flatten(), # vectorize conv2 block output\n", 189 | " nn.Linear(22*22*4,50), # output size: 50\n", 190 | " nn.Linear(50,3), # output size: 3\n", 191 | " )\n", 192 | " \n", 193 | " def forward(self,x):\n", 194 | " return self.enc(x)\n", 195 | " \n", 196 | " # create the model instance\n", 197 | " net = gausnet()\n", 198 | " \n", 199 | " # loss function\n", 200 | " lossfun = nn.MSELoss()\n", 201 | "\n", 202 | " # optimizer\n", 203 | " optimizer = torch.optim.Adam(net.parameters(),lr=.001)\n", 204 | "\n", 205 | " return net,lossfun,optimizer" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": { 212 | "id": "y6icEJcXp0el" 213 | }, 214 | "outputs": [], 215 | "source": [ 216 | "# test the model with one batch\n", 217 | "net,lossfun,optimizer = makeTheNet()\n", 218 | "\n", 219 | "X,y = iter(train_loader).next()\n", 220 | "yHat = net(X)\n", 221 | "\n", 222 | "# check size of output\n", 223 | "print(yHat)\n", 224 | "print(' ')\n", 225 | "print(yHat.shape)\n", 226 | "\n", 227 | "# # now let's compute the loss\n", 228 | "loss = lossfun(yHat,y)\n", 229 | "print(' ')\n", 230 | "print('Loss:')\n", 231 | "print(loss)" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": { 238 | "id": "vLP6nMVUEews" 239 | }, 240 | "outputs": [], 241 | "source": [ 242 | "# count the total number of parameters in the model\n", 243 | "summary(net,(1,imgSize,imgSize))" 244 | ] 245 | }, 246 | { 247 | "cell_type": "markdown", 248 | "metadata": { 249 | "id": "dvfGQIRGp0ht" 250 | }, 251 | "source": [ 252 | "# Create a function that trains the model" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": null, 258 | "metadata": { 259 | "id": "IblJo1NCp0kl" 260 | }, 261 | "outputs": [], 262 | "source": [ 263 | "# a function that trains the model\n", 264 | "\n", 265 | "def function2trainTheModel():\n", 266 | "\n", 267 | " # number of epochs\n", 268 | " numepochs = 30\n", 269 | " \n", 270 | " # create a new model\n", 271 | " net,lossfun,optimizer = makeTheNet()\n", 272 | "\n", 273 | " # initialize losses\n", 274 | " trainLoss = torch.zeros(numepochs)\n", 275 | " testLoss = torch.zeros(numepochs)\n", 276 | "\n", 277 | "\n", 278 | " # loop over epochs\n", 279 | " for epochi in range(numepochs):\n", 280 | "\n", 281 | " # loop over training data batches\n", 282 | " batchLoss = []\n", 283 | " for X,y in train_loader:\n", 284 | "\n", 285 | " # forward pass and loss\n", 286 | " yHat = net(X)\n", 287 | " loss = lossfun(yHat,y)\n", 288 | "\n", 289 | " # backprop\n", 290 | " optimizer.zero_grad()\n", 291 | " loss.backward()\n", 292 | " optimizer.step()\n", 293 | "\n", 294 | " # loss from this batch\n", 295 | " batchLoss.append(loss.item())\n", 296 | " # end of batch loop...\n", 297 | "\n", 298 | " # and get average losses across the batches\n", 299 | " trainLoss[epochi] = np.mean(batchLoss)\n", 300 | "\n", 301 | " # test accuracy\n", 302 | " X,y = next(iter(test_loader)) # extract X,y from test dataloader\n", 303 | " with torch.no_grad(): # deactivates autograd\n", 304 | " yHat = net(X)\n", 305 | " loss = lossfun(yHat,y)\n", 306 | " \n", 307 | " # extract the loss for this test epoch\n", 308 | " testLoss[epochi] = loss.item()\n", 309 | "\n", 310 | " # end epochs\n", 311 | "\n", 312 | " # function output\n", 313 | " return trainLoss,testLoss,net" 314 | ] 315 | }, 316 | { 317 | "cell_type": "markdown", 318 | "metadata": { 319 | "id": "XpGm9xdQ27Ob" 320 | }, 321 | "source": [ 322 | "# Run the model and show the results!" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": null, 328 | "metadata": { 329 | "id": "l9pCC1R2p0nu" 330 | }, 331 | "outputs": [], 332 | "source": [ 333 | "trainLoss,testLoss,net = function2trainTheModel()" 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": null, 339 | "metadata": { 340 | "id": "gHzKOZjnp0qn" 341 | }, 342 | "outputs": [], 343 | "source": [ 344 | "plt.plot(trainLoss,'s-',label='Train')\n", 345 | "plt.plot(testLoss,'o-',label='Test')\n", 346 | "plt.xlabel('Epochs')\n", 347 | "plt.ylabel('Loss (MSE)')\n", 348 | "plt.legend()\n", 349 | "plt.title('Model loss (final test loss: %.2f)'%testLoss[-1])\n", 350 | "\n", 351 | "plt.show()" 352 | ] 353 | }, 354 | { 355 | "cell_type": "code", 356 | "execution_count": null, 357 | "metadata": { 358 | "id": "9SnUUHPm7xQE" 359 | }, 360 | "outputs": [], 361 | "source": [ 362 | "# visualize some images\n", 363 | "\n", 364 | "X,Y = next(iter(test_loader)) # extract X,y from test dataloader\n", 365 | "yHat = net(X)\n", 366 | "\n", 367 | "fig,axs = plt.subplots(2,10,figsize=(16,4))\n", 368 | "\n", 369 | "th = np.linspace(0,2*np.pi)\n", 370 | "\n", 371 | "for i,ax in enumerate(axs.flatten()):\n", 372 | "\n", 373 | " # get the Gaussian and draw it, and draw the white guide-lines\n", 374 | " G = torch.squeeze( X[i,0,:,:] ).detach()\n", 375 | " ax.imshow(G,vmin=-1,vmax=1,cmap='jet',extent=[-4,4,-4,4],origin='top')\n", 376 | " ax.plot([-4,4],[0,0],'w--')\n", 377 | " ax.plot([0,0],[-4,4],'w--')\n", 378 | "\n", 379 | " # compute the model's prediction\n", 380 | " cx = yHat[i][0].item() # center X\n", 381 | " cy = yHat[i][1].item() # center Y\n", 382 | " rd = yHat[i][2].item() # radius\n", 383 | "\n", 384 | " # and draw it\n", 385 | " x = cx + np.cos(th)*np.sqrt(rd)\n", 386 | " y = cy + np.sin(th)*np.sqrt(rd)\n", 387 | " ax.plot(x,y,'b')\n", 388 | " ax.plot(cx,cy,'bo')\n", 389 | " \n", 390 | " # some final plotting niceties\n", 391 | " ax.set_xticks([])\n", 392 | " ax.set_yticks([])\n", 393 | " ax.set_xlim([-4,4])\n", 394 | " ax.set_ylim([-4,4])\n", 395 | "\n", 396 | "plt.tight_layout()\n", 397 | "plt.show()" 398 | ] 399 | }, 400 | { 401 | "cell_type": "code", 402 | "execution_count": null, 403 | "metadata": { 404 | "id": "7hA3XiiaZhzU" 405 | }, 406 | "outputs": [], 407 | "source": [ 408 | "fig = plt.figure(figsize=(5,5))\n", 409 | "\n", 410 | "paramNames = ['Cx','Cy','rad.']\n", 411 | "\n", 412 | "for i in range(3):\n", 413 | " \n", 414 | " # extract parameters and compute correlation\n", 415 | " yy = Y[:,i].detach()\n", 416 | " yh = yHat[:,i].detach()\n", 417 | " cr = np.corrcoef(yy,yh)[0,1]\n", 418 | "\n", 419 | " # plot with label\n", 420 | " plt.plot(yy,yh,'o',label=f'{paramNames[i]}, r={cr:.3f}')\n", 421 | "\n", 422 | "\n", 423 | "plt.legend()\n", 424 | "plt.xlabel('True values')\n", 425 | "plt.ylabel('Predicted values')\n", 426 | "plt.grid()\n", 427 | "plt.show()" 428 | ] 429 | } 430 | ], 431 | "metadata": { 432 | "colab": { 433 | "collapsed_sections": [], 434 | "name": "DUDL_CNN_findGauss.ipynb", 435 | "provenance": [] 436 | }, 437 | "kernelspec": { 438 | "display_name": "Python 3", 439 | "language": "python", 440 | "name": "python3" 441 | }, 442 | "language_info": { 443 | "codemirror_mode": { 444 | "name": "ipython", 445 | "version": 3 446 | }, 447 | "file_extension": ".py", 448 | "mimetype": "text/x-python", 449 | "name": "python", 450 | "nbconvert_exporter": "python", 451 | "pygments_lexer": "ipython3", 452 | "version": "3.7.4" 453 | } 454 | }, 455 | "nbformat": 4, 456 | "nbformat_minor": 1 457 | } 458 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deep learning demos 2 | 3 | This code accompanies a youtube video highlighting a use-case of deep convolutional neural networks for identifying generating parameters of 2D Gaussian parameters. 4 | 5 | The accompanying video is here: https://youtu.be/-IziAW9AN-w 6 | --------------------------------------------------------------------------------