Skip to content

Instantly share code, notes, and snippets.

@mdvsh
Created May 21, 2020 05:08
Show Gist options
  • Save mdvsh/ae94cc895a1c9302853306abdf99a49b to your computer and use it in GitHub Desktop.
Save mdvsh/ae94cc895a1c9302853306abdf99a49b to your computer and use it in GitHub Desktop.
A NumPy implementation of a Convolutional Model
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline"
]
},
{
"attachments": {
"image.png": {
"image/png": "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"
}
},
"cell_type": "markdown",
"metadata": {},
"source": [
"### An attempt at implementing a CNN to from scratch using NumPy to better understand its working.\n",
"TODO:\n",
"- Convolution Functions\n",
" - Zero padding\n",
" - Convolve window\n",
" - Forward convolution\n",
" - Backward Convolution\n",
"- Pooling Function\n",
" - Forward pool\n",
" - Mask creation\n",
" - Value distribution\n",
" - Backward Pool\n",
"---\n",
"\n",
"<center>Basic structure of CNN</center>\n",
"\n",
"![image.png](attachment:image.png)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Zero Padding\n",
"To add zeros around the image matrix to prevent loss of features due to scaling down after one step of a convolution.\n",
"*Same Convolution*: padding such that h-w of original image preserved after one layer."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def zero_pad(X, p):\n",
" \"\"\"\n",
" params\n",
" X: (n, nH, nW, nC) dims array representing a batch of images\n",
" p: int, amount of padding around each image\n",
" \"\"\"\n",
" pad_width = ((0, 0), (p, p), (p, p), (0, 0))\n",
" X_p = np.pad(X, pad_width, mode='constant', constant_values=(0, 0))\n",
" return X_p"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An example of padding some sample data and demonstrating."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"X.shape =\n",
" (1, 3, 3, 2)\n",
"x_p.shape =\n",
" (1, 7, 7, 2)\n"
]
},
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x7f33b5942bd0>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"np.random.seed(0)\n",
"x = np.random.randn(1, 3, 3, 2)\n",
"x_p = zero_pad(x, 2)\n",
"print (\"X.shape =\\n\", x.shape)\n",
"print (\"x_p.shape =\\n\", x_p.shape)\n",
"fig, axarr = plt.subplots(1, 2)\n",
"axarr[0].set_title('X: Original Image Matrix')\n",
"axarr[0].imshow(x[0,:,:,0])\n",
"axarr[1].set_title('X_p: Padded Image Matrix')\n",
"axarr[1].imshow(x_p[0,:,:,0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Convolution\n",
"\n",
"1. `conv_one_part()`\n",
" - TODO: Take input volume (matrix by no. of channels) and **convolve** filter against it to output new volume with features (hopefully) identified.\n",
"\n",
"`conv_one_part()` will apply convolution to a part of the given image matrix (X) of dimensions filter_h x filter_w, taking steps of value *stride* after each iteration of the function.\n",
"To be implemented in the next function."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def conv_one_part(a_slice, W, b):\n",
" \"\"\"\n",
" params\n",
" m_slice: slice of input matrix; dims --> (f_h, f_w, nC_prev)\n",
" W: Weight params contained in a window; dims --> (f_h, f_w, nC_prev)\n",
" b: Bias params contained in a window; dims --> (1, 1, 1) : scalar\n",
" \"\"\"\n",
" Z = float(np.add(np.sum(np.multiply(a_slice, W)), b))\n",
" return Z"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2. `forward_conv()`\n",
" - TODO: Take multiple filters and convolve all of them on the input. Stack 2D Matrix outputs to produce output volume giving result of a single forward pass of convolution."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"def forward_conv(A_prev, W, b, hparams):\n",
" \"\"\"\n",
" params\n",
" A_prev: previous layer activation; dims --> (n, nH, nW, nC_prev)\n",
" W: Weight params contained in a window; dims --> (f_h, f_w, nC_prev, nC)\n",
" b: Bias params contained in a window; dims --> (1, 1, 1, nC) : scalar\n",
" hparams: dict containing values for stride and padding\n",
" \n",
" return\n",
" Z: conv step output; dims --> (n, nH, nW, nC)\n",
" cache: for calculating derivatives in backward_conv()\n",
" \"\"\"\n",
" # Init: Dimensions, hparams\n",
" (n, nH_prev, nW_prev, nC_prev) = np.shape(A_prev)\n",
" (f, f, nC_prev, nC) = np.shape(W)\n",
" s = hparams['stride']\n",
" pad = hparams['padding']\n",
" nH = int((nH_prev-f+2*pad)/s)+1\n",
" nW = int((nW_prev-f+2*pad)/s)+1\n",
" Z = np.zeros((n, nH, nW, nC))\n",
" \n",
" # Applying padding to prev layer activation\n",
" A_prev_p = zero_pad(A_prev, pad)\n",
" \n",
" # Loop (Vectorization >>>>>>> Loops) to apply convolution operation.\n",
" for i in range(n):\n",
" a_prev_p = A_prev_p[i, :, :, :]\n",
" for h in range(nH):\n",
" for w in range(nW):\n",
" vert1_f, vert2_f = h*s, h*s+f\n",
" hori1_f, hori2_f = w*s, w*s+f\n",
" for c in range (nC):\n",
" # slice\n",
" a_slice = a_prev_p[vert1_f:vert2_f, hori1_f:hori2_f, :]\n",
" Z[i, h, w, c] = conv_one_part(a_slice, W[:, :, :, c], b[:, :, :, c])\n",
" # for backward_conv() \n",
" cache = (A_prev, W, b, hparams)\n",
"# assert(Z.shape == (n, nH, nW, nC))\n",
"\n",
" return (Z, cache)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Testing one iteration of `forward_conv()` on sample data."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Z's mean =\n",
" -0.1282614539128993\n",
"Z[3,2,1] =\n",
" [ 4.98925312 -0.12934609 6.77487928 -6.44934224 1.80531313 8.75470928\n",
" -2.85387942 -2.65858316]\n",
"cache_conv[0][1][2][3] = [-0.9970198 -0.10679399 1.45142926 -0.61803685]\n"
]
}
],
"source": [
"np.random.seed(1)\n",
"A_prev = np.random.randn(10,8,8,4)\n",
"W = np.random.randn(3,3,4,8) # channels of A_prev and W has to be the same (here, 4)\n",
"b = np.random.randn(1,1,1,8)\n",
"hparams = {\"padding\" : 2, \"stride\": 2}\n",
"\n",
"Z, cache_conv = forward_conv(A_prev, W, b, hparams)\n",
"print(\"Z's mean =\\n\", np.mean(Z))\n",
"print(\"Z[3,2,1] =\\n\", Z[3,2,1])\n",
"print(\"cache_conv[0][1][2][3] =\", cache_conv[0][1][2][3])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Pooling\n",
"Pooling operation after convolution to keep strong features by taking the maximum / average value contained in a sub-matrix of dims of the filter. Pooling helps reduce computation, as well as helps make feature detectors more invariant to its position in the input. \n",
"`forward_pool()` implments a forward pass of the pooling layer. By default, *maxpool*."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"def forward_pool(A_prev, hparams, mode=\"maxpool\"):\n",
" \"\"\"\n",
" params\n",
" A_prev: previous layer activation; dims --> (n, nH, nW, nC_prev)\n",
" hparams: dict containing values for filter_size and padding\n",
" mode: pooling to perform; default --> maxpool\n",
" \n",
" return\n",
" A: pool step output; dims --> (n, nH, nW, nC)\n",
" cache: for calculating derivatives in backward_pool()\n",
" \"\"\"\n",
" # Init: Dimensions, hparams\n",
" (n, nH_prev, nW_prev, nC_prev) = np.shape(A_prev)\n",
" s = hparams['stride']\n",
" fs = hparams['filt_size']\n",
" nH = int((nH_prev-fs)/s)+1\n",
" nW = int((nW_prev-fs)/s)+1\n",
" nC = nC_prev\n",
" A = np.zeros((n, nH, nW, nC))\n",
" \n",
" # Loop (Vectorization >>>>>>> Loops) to apply pooling operation.\n",
" for i in range(n):\n",
" for h in range(nH):\n",
" for w in range(nW):\n",
" for c in range(nC):\n",
" vert1_f, vert2_f = h*s, h*s+fs\n",
" hori1_f, hori2_f = w*s, w*s+fs\n",
" a_slice = A_prev[i, vert1_f:vert2_f, hori1_f:hori2_f, c]\n",
" if mode == 'maxpool': A[i, h, w, c] = np.max(a_slice)\n",
" elif mode == 'avrgpool': A[i, h, w, c] = np.mean(a_slice)\n",
" # for backward_conv() \n",
" cache = (A_prev, hparams)\n",
"# assert(A.shape == (n, nH, nW, nC))\n",
" return (A, cache)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Testing one iteration of `forward_pool(mode='maxpool')` on sample data."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A_prev.shape = (1, 5, 5, 3)\n",
"A = \n",
" [[[[ 1.62434536 -0.61175641 -0.52817175]\n",
" [-1.07296862 0.86540763 -2.3015387 ]\n",
" [ 1.74481176 -0.7612069 0.3190391 ]\n",
" [-0.24937038 1.46210794 -2.06014071]\n",
" [-0.3224172 -0.38405435 1.13376944]]\n",
"\n",
" [[-1.09989127 -0.17242821 -0.87785842]\n",
" [ 0.04221375 0.58281521 -1.10061918]\n",
" [ 1.14472371 0.90159072 0.50249434]\n",
" [ 0.90085595 -0.68372786 -0.12289023]\n",
" [-0.93576943 -0.26788808 0.53035547]]\n",
"\n",
" [[-0.69166075 -0.39675353 -0.6871727 ]\n",
" [-0.84520564 -0.67124613 -0.0126646 ]\n",
" [-1.11731035 0.2344157 1.65980218]\n",
" [ 0.74204416 -0.19183555 -0.88762896]\n",
" [-0.74715829 1.6924546 0.05080775]]\n",
"\n",
" [[-0.63699565 0.19091548 2.10025514]\n",
" [ 0.12015895 0.61720311 0.30017032]\n",
" [-0.35224985 -1.1425182 -0.34934272]\n",
" [-0.20889423 0.58662319 0.83898341]\n",
" [ 0.93110208 0.28558733 0.88514116]]\n",
"\n",
" [[-0.75439794 1.25286816 0.51292982]\n",
" [-0.29809284 0.48851815 -0.07557171]\n",
" [ 1.13162939 1.51981682 2.18557541]\n",
" [-1.39649634 -1.44411381 -0.50446586]\n",
" [ 0.16003707 0.87616892 0.31563495]]]]\n",
"\n",
"Pooling type : Max Pooling\n",
"A.shape = (1, 2, 2, 3)\n",
"A =\n",
" [[[[1.74481176 0.90159072 1.65980218]\n",
" [1.74481176 1.6924546 1.65980218]]\n",
"\n",
" [[1.13162939 1.51981682 2.18557541]\n",
" [1.13162939 1.6924546 2.18557541]]]]\n",
"\n",
"Pooling type : Average Pooling\n",
"A.shape = (1, 2, 2, 3)\n",
"A =\n",
" [[[[-0.03010467 -0.00324021 -0.33629886]\n",
" [ 0.12893444 0.22242847 0.1250676 ]]\n",
"\n",
" [[-0.38268052 0.23257995 0.6259979 ]\n",
" [-0.09525515 0.268511 0.46605637]]]]\n"
]
}
],
"source": [
"np.random.seed(1)\n",
"A_prev = np.random.randn(1, 5, 5, 3)\n",
"hparams = {\"stride\" : 2, \"filt_size\": 3}\n",
"\n",
"print('A_prev.shape = ' + str(A_prev.shape))\n",
"print(\"A = \\n\", A_prev)\n",
"print()\n",
"A, cache = forward_pool(A_prev, hparams)\n",
"print(\"Pooling type : Max Pooling\")\n",
"print(\"A.shape = \" + str(A.shape))\n",
"print(\"A =\\n\", A)\n",
"print()\n",
"A, cache = forward_pool(A_prev, hparams, mode = \"avrgpool\")\n",
"print(\"Pooling type : Average Pooling\")\n",
"print(\"A.shape = \" + str(A.shape))\n",
"print(\"A =\\n\", A)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Convolution Layer - Backward Pass\n",
"*Note: $dZ_{hw}$ is a scalar corresponding to the gradient of the cost with respect to the output of the conv layer Z at the hth row and wth column (corresponding to the dot product taken at the ith stride left and jth stride down).*\n",
"\n",
"Further, We need to compute :\n",
"1. $dA$ (w.r.t cost for a certain filter $W_{c}$)\n",
" $$ dA += \\sum _{h=0} ^{n_H} \\sum_{w=0} ^{n_W} W_c \\times dZ_{hw} \\tag{1}$$\n",
" \n",
" - Notice, how everytime the same filter is multiplied by a different derivative of cost w.r.t output of conv layer Z ($dZ$)\n",
"2. $dW$ (derivative of one filter w.r.t to the loss)\n",
" $$ dW_c += \\sum _{h=0} ^{n_H} \\sum_{w=0} ^ {n_W} a_{slice} \\times dZ_{hw} \\tag{2}$$\n",
" - Where, $a_{slice}$ is the slice of original matrix used to generate activation $Z_{ij}$. This follows from the fact that the filter matrix can also learn (from backprop) optimal values. \n",
"3. $db$ ( w.r.t to the cost of a certain filter $dW_{c}$)\n",
" $$ db = \\sum_h \\sum_w dZ_{hw} \\tag{3}$$\n",
" \n",
" - summing over all the gradients of the conv output (Z) with respect to the cost.\n",
" \n",
"#### `backward_conv()` : To implement the backward propagation for a convolution function"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"def backward_conv(dZ, cache):\n",
" \"\"\"\n",
" params\n",
" dZ: gradient of cost w.r.t conv layer output (Z); dims --> (n, nH, nW, nC)\n",
" cache: cache of values needed for backward_conv(); i.e. output of forward_conv()\n",
" \n",
" returns\n",
" see above (markdown)\n",
" \"\"\"\n",
" # Init: Dimensions, hparams\n",
" (A_prev, W, b, hparams) = cache\n",
" (n, nH_prev, nW_prev, nC_prev) = np.shape(A_prev)\n",
" (f, f, nC_prev, nC) = np.shape(W)\n",
" s = hparams['stride']\n",
" pad = hparams['padding']\n",
" (n, nH, nW, nC) = np.shape(dZ)\n",
" \n",
" dA_prev = np.zeros_like(A_prev)\n",
" dW = np.zeros_like(W)\n",
" db = np.zeros_like(b)\n",
" \n",
" A_prev_p = zero_pad(A_prev, pad)\n",
" dA_prev_p = zero_pad(dA_prev, pad)\n",
" \n",
" # Loop (Vectorization >>>>>>> Loops) for backward convolution step.\n",
" for i in range(n):\n",
" a_prev_p = A_prev_p[i, :, :, :]\n",
" da_prev_p = dA_prev_p[i, :, :, :]\n",
" for h in range(nH):\n",
" for w in range(nW):\n",
" for c in range(nC):\n",
" vert1_f, vert2_f = h*s, h*s+f\n",
" hori1_f, hori2_f = w*s, w*s+f\n",
" # slice\n",
" a_slice = a_prev_p[vert1_f:vert2_f, hori1_f:hori2_f, :]\n",
" # updating gradients\n",
" da_prev_p[vert1_f:vert2_f, hori1_f:hori2_f, :] += W[:, :, :, c] * dZ[i, h, w, c]\n",
" dW[:, :, :, c] += a_slice * dZ[i, h, w, c]\n",
" db[:, :, :, c] += dZ[i, h, w, c]\n",
" dA_prev[i, :, :, :] = da_prev_p[pad:-pad, pad:-pad, :]\n",
" \n",
"# assert(dA_prev.shape == (m, nH_prev, nW_prev, nC_prev))\n",
" return dA_prev, dW, db"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Testing `backward_conv()` on sample data."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"dA_mean = -0.9683520023516613\n",
"dW_mean = -3.028451139022465\n",
"db_mean = 41.04575496729348\n"
]
}
],
"source": [
"# We'll run conv_forward to initialize the 'Z' and 'cache_conv\",\n",
"# which we'll use to test the conv_backward function\n",
"np.random.seed(1)\n",
"A_prev = np.random.randn(10,4,4,3)\n",
"W = np.random.randn(2,2,3,6) # six filters\n",
"b = np.random.randn(1,1,1,6)\n",
"hparameters = {\"padding\" : 2, \"stride\": 2}\n",
"Z, cache_conv = forward_conv(A_prev, W, b, hparameters)\n",
"# Testing backward_conv()\n",
"dA, dW, db = backward_conv(Z, cache_conv)\n",
"print(\"dA_mean =\", np.mean(dA))\n",
"print(\"dW_mean =\", np.mean(dW))\n",
"print(\"db_mean =\", np.mean(db))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Pooling Layer - Backward Pass\n",
"Although, pooling layer has no learnable parameters for backpropagation, we still need to go through the pooling layer to complete gradient computation for layers that come before pooling layer.\n",
"\n",
"To compute backward pooling, we would need a function `mask_window()` to create a matrix which keeps track of where the maximum of the matrix is. \n",
"\n",
"$$ X = \\begin{bmatrix}\n",
"1 && 2 \\\\\n",
"3 && 4\n",
"\\end{bmatrix} \\quad \\rightarrow \\quad M =\\begin{bmatrix}\n",
"0 && 0 \\\\\n",
"0 && 1\n",
"\\end{bmatrix}$$\n",
"\n",
"#### But, why do we keep track of the position of the max? \n",
"\n",
"It's because this is the input value that ultimately influenced the output, and therefore the cost. Backprop is computing gradients with respect to the cost, so anything that influences the ultimate cost should have a non-zero gradient. So, backprop will \"propagate\" the gradient back to this particular input value that had influenced the cost."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"def max_mask(x):\n",
" \"\"\"\n",
" params\n",
" x: input matrix to be masked\n",
" \n",
" returns\n",
" m_x: masked matrix, same dims as x, 1 / True at max elem position\n",
" \"\"\"\n",
" m_x = (x == np.max(x))\n",
" return m_x"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x = [[5 8 9]\n",
" [5 0 0]\n",
" [1 7 6]]\n",
"m_z = [[False False True]\n",
" [False False False]\n",
" [False False False]]\n"
]
}
],
"source": [
"np.random.seed(1)\n",
"x = np.random.randint(10, size=(3, 3))\n",
"print('x = ', x)\n",
"print('m_x = ', max_mask(x))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We would also need a similar mask function for average pooling as well. \n",
"\n",
"In case of average pooling, every elem of the sliced (window) matrix has equal influence on the output *unlike* max pooling where maximum influence is by the largest element."
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"def avrg_mask(x, dims):\n",
" \"\"\"\n",
" params\n",
" x: input scalar to be masked\n",
" dims: dims of array we want to distribute x to. \n",
" \n",
" returns\n",
" m_x: masked matrix, same dims as x with x distributed among it\n",
" \"\"\"\n",
" (nH, nW) = dims\n",
" avg = x/(nH*nW)\n",
" m_x = avg * np.ones((nH, nW))\n",
" return m_x"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Value to be Distributed: 25 \n",
"Distributed / Average Mask:\n",
" [[2.77777778 2.77777778 2.77777778]\n",
" [2.77777778 2.77777778 2.77777778]\n",
" [2.77777778 2.77777778 2.77777778]]\n"
]
}
],
"source": [
"print('Value to be Distributed: ', 25,'\\nDistributed / Average Mask:\\n', avrg_mask(25, (3, 3)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now with our helper functions in place, we can proceed towards writing our final function of the day `backward_pool()`."
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [],
"source": [
"def backward_pool(dA, cache, mode='maxpool'):\n",
" \"\"\"\n",
" params\n",
" dA: gradient of cost w.r.t output of pooling layer; dims --> like A\n",
" cache: cache output from forward step of pooling layer; contains inputs and hparams\n",
" moode: max/average pool\n",
" \n",
" returns\n",
" dA_prev: gradient of cost w.r.t input of pooling layer; dims --> like A_prev\n",
" \"\"\"\n",
" # Init; Dimensions and hparams\n",
" (A_prev, hparams) = cache\n",
" s = hparams['stride']\n",
" fs = hparams['filt_size']\n",
" (n, nH, nW, nC) = np.shape(dA)\n",
" (n, nH_prev, nW_prev, nC_prev) = np.shape(A_prev)\n",
" dA_prev = np.zeros_like(A_prev)\n",
" \n",
" # Loop (Vectorization >>>>>>> Loops) for backward pooling step.\n",
" for i in range(n):\n",
" a_prev = A_prev[i, :, :, :]\n",
" for h in range(nH):\n",
" for w in range(nW):\n",
" for c in range(nC):\n",
" vert1_f, vert2_f = h*s, h*s+fs\n",
" hori1_f, hori2_f = w*s, w*s+fs\n",
" if mode=='maxpool':\n",
" a_prev_slice = a_prev[vert1_f:vert2_f, hori1_f:hori2_f, c]\n",
" # create mask from a_prev_slice\n",
" mask = max_mask(a_prev_slice)\n",
" dA_prev[i, vert1_f:vert2_f, hori1_f:hori2_f, c] += mask * dA[i, h, w, c]\n",
" elif mode=='avrgpool':\n",
" da = dA[i, h, w, c]\n",
" dims = (fs, fs)\n",
" dA_prev[i, vert1_f:vert2_f, hori1_f:hori2_f, c] += avrg_mask(da, dims)\n",
" \n",
"# assert(dA_prev.shape == A_prev.shape)\n",
" \n",
" return dA_prev"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Testing `backward_pool()` on sample data."
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pooling type : Max Pooling\n",
"mean of dA = 0.14571390272918056\n",
"dA_prev[1,1] = [[ 0. 0. ]\n",
" [ 5.05844394 -1.68282702]\n",
" [ 0. 0. ]]\n",
"\n",
"Pooling type : Average Pooling\n",
"mean of dA = 0.14571390272918056\n",
"dA_prev[1,1] = [[ 0.08485462 0.2787552 ]\n",
" [ 1.26461098 -0.25749373]\n",
" [ 1.17975636 -0.53624893]]\n"
]
}
],
"source": [
"np.random.seed(1)\n",
"A_prev = np.random.randn(5, 5, 3, 2)\n",
"hparameters = {\"stride\" : 1, \"filt_size\": 2}\n",
"A, cache = forward_pool(A_prev, hparameters)\n",
"dA = np.random.randn(5, 4, 2, 2)\n",
"\n",
"dA_prev = backward_pool(dA, cache, mode = \"maxpool\")\n",
"print(\"Pooling type : Max Pooling\")\n",
"print('mean of dA = ', np.mean(dA))\n",
"print('dA_prev[1,1] = ', dA_prev[1,1]) \n",
"print()\n",
"dA_prev = backward_pool(dA, cache, mode = \"avrgpool\")\n",
"print(\"Pooling type : Average Pooling\")\n",
"print('mean of dA = ', np.mean(dA))\n",
"print('dA_prev[1,1] = ', dA_prev[1,1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"With this, we have completed all the basic building ~~blocks~~ functions required to build a Convolutional Model.\n",
"\n",
"While coding thihs out, I was able to greatly increase my understanding about the mathematical working beneath both convolution and pooling operations. \n",
"\n",
"With deeplearning libraries such as PyTorch and Tensorflow making such things a breeze, (only 10 lines of pytorch code to do all things I've done in this notebook) it's not practical to define CNN models from scratch using numpy since tensors (numpy arrays + GPU support) are the go-to. Still, this endeavour turned out to be extremely knowledgable and *EPIC*.\n",
"\n",
"*kthnxbye*"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"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.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment