Showing preview only (1,356K chars total). Download the full file or copy to clipboard to get everything.
Repository: deep-learning-indaba/indaba-2018
Branch: master
Commit: f9bb125948ac
Files: 8
Total size: 1.3 MB
Directory structure:
gitextract_p7frg7eu/
├── Mathematics_for_Machine_Learning_Examples.ipynb
├── Practical_0_5_Machine_Learning_Basics.ipynb
├── Practical_1_Deep_Feedforward_Networks.ipynb
├── Practical_2_Convolutional_Neural_Networks.ipynb
├── Practical_3_Recurrent_Neural_Networks.ipynb
├── Practical_4_Reinforcement_Learning.ipynb
├── README.md
└── practical0.ipynb
================================================
FILE CONTENTS
================================================
================================================
FILE: Mathematics_for_Machine_Learning_Examples.ipynb
================================================
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Mathematics for Machine Learning Examples",
"version": "0.3.2",
"provenance": [],
"collapsed_sections": []
},
"kernelspec": {
"name": "python2",
"display_name": "Python 2"
}
},
"cells": [
{
"metadata": {
"id": "ST8QJlxSdvMU",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"outputId": "7eae7c44-6007-47b5-bd59-cb4ca1df832c"
},
"cell_type": "code",
"source": [
"#@title Imports { display-mode: \"form\" }\n",
"from __future__ import print_function\n",
"from __future__ import division\n",
"from __future__ import absolute_import\n",
"\n",
"import numpy as np\n",
"import tensorflow as tf\n",
"import matplotlib.pyplot as plt\n",
"\n",
"try:\n",
" tf.enable_eager_execution()\n",
" print('Eager execution enabled')\n",
"except ValueError:\n",
" print('Already running in Eager mode')\n",
"\n",
"tfe = tf.contrib.eager\n",
" "
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"Already running in Eager mode\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "RgFS1eZOdws_",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Matrix Multiplication"
]
},
{
"metadata": {
"id": "E0TdsagndySr",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 85
},
"outputId": "535c541c-da43-4154-dae9-7198ba1e9ed0"
},
"cell_type": "code",
"source": [
"# Define matrix A\n",
"A = np.array(\n",
" [[1.0, 3.0],\n",
" [2.0, 1.0],\n",
" [4.0, 2.0]]\n",
")\n",
"\n",
"# Define matrix B\n",
"B = np.array(\n",
" [[6.0, 2.0, 1.0],\n",
" [3.0, 4.0, 5.0]]\n",
")\n",
"\n",
"# Define vector x\n",
"x = np.array([3.0, 2.0])\n",
"\n",
"print('A.shape is:', A.shape, 'B.shape is:', B.shape, 'x.shape is:', x.shape)\n",
"A"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"A.shape is: (3, 2) B.shape is: (2, 3) x.shape is: (2,)\n"
],
"name": "stdout"
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"array([[1., 3.],\n",
" [2., 1.],\n",
" [4., 2.]])"
]
},
"metadata": {
"tags": []
},
"execution_count": 56
}
]
},
{
"metadata": {
"id": "4xVzrzTskHqK",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Matrix-vector multiplication"
]
},
{
"metadata": {
"id": "ySFMEkRrkJ51",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 85
},
"outputId": "f52ddad3-c34a-4a07-8ec4-8682e1abcc4e"
},
"cell_type": "code",
"source": [
"# Using numpy dot\n",
"y = A.dot(x)\n",
"\n",
"print('Using dot:\\t y =', y, '\\t y.shape =', y.shape)\n",
"\n",
"# Using einsum\n",
"y = np.einsum('ij, j', A, x)\n",
"\n",
"print('Using einsum:\\t y =', y, '\\t y.shape =', y.shape)\n",
"\n",
"# Manual version 1\n",
"y = np.array([\n",
" A[0,0] * x[0] + A[0,1] * x[1],\n",
" A[1,0] * x[0] + A[1,1] * x[1],\n",
" A[2,0] * x[0] + A[2,1] * x[1],\n",
" ])\n",
"print('Manual 1:\\t y =', y, '\\t y.shape =', y.shape)\n",
"\n",
"# Manual version 2: \n",
"# Matrix-vector multiplication can be thought of as a linear combination of the columns of of the matrix\n",
"y = x[0] * A[:,0] + x[1] * A[:, 1]\n",
"\n",
"print('Manual 2:\\t y =', y, '\\t y.shape =', y.shape)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"Using dot:\t y = [ 9. 8. 16.] \t y.shape = (3,)\n",
"Using einsum:\t y = [ 9. 8. 16.] \t y.shape = (3,)\n",
"Manual 1:\t y = [ 9. 8. 16.] \t y.shape = (3,)\n",
"Manual 2:\t y = [ 9. 8. 16.] \t y.shape = (3,)\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "IXfRCQfglg7Y",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Matrix-matrix multiplication"
]
},
{
"metadata": {
"id": "CCw3o6GMeD1o",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 459
},
"outputId": "8f963951-8502-4b13-b858-fce70e4c6538"
},
"cell_type": "code",
"source": [
"# Using numpy dot\n",
"C = A.dot(B)\n",
"\n",
"print('Using DOT: C= \\n\\n', C, '\\n\\nC.shape =', C.shape)\n",
"\n",
"# Using einsum\n",
"C = np.einsum('ik, kj', A, B)\n",
"print('\\n\\nUsing einsum: C= \\n\\n', C, '\\n\\nC.shape =', C.shape)\n",
"\n",
"# Note, the above einsum notation is equivalent to the following\n",
"C = np.einsum('ik, kj -> ij', A, B)\n",
"\n",
"# And in Tensorflow\n",
"C = tf.matmul(A, B)\n",
"print('\\n\\nUsing Tensorflow: C= \\n\\n', C, '\\n\\nC.shape =', C.shape)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"Using DOT: C= \n",
"\n",
" [[15. 14. 16.]\n",
" [15. 8. 7.]\n",
" [30. 16. 14.]] \n",
"\n",
"C.shape = (3, 3)\n",
"\n",
"\n",
"Using einsum: C= \n",
"\n",
" [[15. 14. 16.]\n",
" [15. 8. 7.]\n",
" [30. 16. 14.]] \n",
"\n",
"C.shape = (3, 3)\n",
"\n",
"\n",
"Using Tensorflow: C= \n",
"\n",
" tf.Tensor(\n",
"[[15. 14. 16.]\n",
" [15. 8. 7.]\n",
" [30. 16. 14.]], shape=(3, 3), dtype=float64) \n",
"\n",
"C.shape = (3, 3)\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "o3U0Fc7mlxSd",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Matrix multiplication is not commutative"
]
},
{
"metadata": {
"id": "iiI6J7ZDj9Fl",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 102
},
"outputId": "1c0e575f-1b2c-4da6-aab1-7f1e5ed60f19"
},
"cell_type": "code",
"source": [
"# Matrix multiplication is not commutative:\n",
"C = B.dot(A)\n",
"print('C: \\n', C)\n",
"print()\n",
"print('C.shape:', C.shape)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"C: \n",
" [[14. 22.]\n",
" [31. 23.]]\n",
"\n",
"C.shape: (2, 2)\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "WxJ0muOj34SB",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Computing gradients with TensorFlow\n",
"$y = Ax$\n",
"\n",
"In the code below, we use Tensorflow to calculate the following derivatives:\n",
"\n",
"$\\frac{dy}{dx}$ \n",
"\n",
"and \n",
"\n",
"$\\frac{\\partial y}{\\partial A}$ "
]
},
{
"metadata": {
"id": "5wCGTn1s3zlV",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 119
},
"outputId": "2b250cbe-4c07-481d-ecf9-ed8d449cf921"
},
"cell_type": "code",
"source": [
"A_tensor = tfe.Variable(A)\n",
"x_tensor = tfe.Variable(x)\n",
"\n",
"with tf.GradientTape() as tape:\n",
" y = tf.einsum('ij,j', A_tensor, x_tensor)\n",
"\n",
"dydx, dydA = tape.gradient(y, [x_tensor, A_tensor])\n",
"\n",
"print('dy/dx =', dydx)\n",
"print()\n",
"print('dy/dA =', dydA)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"dy/dx = tf.Tensor([7. 6.], shape=(2,), dtype=float64)\n",
"\n",
"dy/dA = tf.Tensor(\n",
"[[3. 2.]\n",
" [3. 2.]\n",
" [3. 2.]], shape=(3, 2), dtype=float64)\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "btAykJ_oEZ-i",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"# Neural Network Gradient Example\n",
"In the following example, we compute the output of a 1 layer neural network and the gradients with respect to its parameters. We define an example input vector and parameters, but keep the computation generic. You can change the values and shapes of x, A and b below and run the rest of the code to compute the output and gradients for your own example."
]
},
{
"metadata": {
"id": "WRnif1ZP4kYQ",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"x = np.array([[-1.], [0.1], [2.1]]) # X has shape (3, 1)\n",
"A = np.array([ # A has shape (2, 3)\n",
" [ 1.1, -2.5, 0.3],\n",
" [-2.1, 0.2, -1.1]\n",
"]) \n",
"b = np.array([[-1.0], [2.0]]) # b has shape (2)"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "XaTm7-r9FBxl",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Compute the neural network output\n",
"$\\mathbf{f} = \\operatorname{tanh}(A\\mathbf{x} + \\mathbf{b})$"
]
},
{
"metadata": {
"id": "1HR6uCTjFAvV",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 51
},
"outputId": "ff5beb67-d370-4a70-a8ee-b6c4b64a585e"
},
"cell_type": "code",
"source": [
"M, N = A.shape\n",
"z = A.dot(x) + b\n",
"f = np.tanh(z)\n",
"\n",
"print('f =', f)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"f = [[-0.93786303]\n",
" [ 0.94783185]]\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "wQKVQ13jGkIH",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Compute the partial derivatives:\n",
"\n",
"\\begin{align}\n",
"\\frac{d\\mathbf{f}}{d\\mathbf{z}} ; \\frac{\\partial\\mathbf{z}}{\\partial\\mathbf{x}} ; \\frac{\\partial\\mathbf{z}}{\\partial\\mathbf{b}} ; \\frac{\\partial\\mathbf{z}}{\\partial\\mathbf{A}}\n",
"\\end{align}"
]
},
{
"metadata": {
"id": "sJF9p5lHE4Z_",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 425
},
"outputId": "3900b59e-ab3d-4f9d-caa4-dd79c7fd49c6"
},
"cell_type": "code",
"source": [
"# partial derivatives\n",
"dfdz = 1-f**2 # (derivative of tanh is 1-tanh^2)\n",
"print('df/dz =', dfdz, '\\nshape:', dfdz.shape)\n",
"print()\n",
"\n",
"dzdx = A\n",
"print('dz/dx =\\n', dzdx, '\\n\\nshape:', dzdx.shape)\n",
"print()\n",
"\n",
"dzdb = np.eye(M)\n",
"print('dz/db =\\n', dzdb, '\\n\\nshape:', dzdb.shape)\n",
"print()\n",
"\n",
"dzdA = np.zeros((M, M, N)) # Start with a tensor of zeros of the correct shape\n",
"for i in range(M): # Then set the diagonal elements of dzdA\n",
" dzdA[i,i,:] = x.T \n",
"\n",
"print('dz/dA =\\n', dzdA, '\\n\\nshape:', dzdA.shape)\n",
"\n"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"df/dz = [[0.12041293]\n",
" [0.10161478]] \n",
"shape: (2, 1)\n",
"\n",
"dz/dx =\n",
" [[ 1.1 -2.5 0.3]\n",
" [-2.1 0.2 -1.1]] \n",
"\n",
"shape: (2, 3)\n",
"\n",
"dz/db =\n",
" [[1. 0.]\n",
" [0. 1.]] \n",
"\n",
"shape: (2, 2)\n",
"\n",
"dz/dA =\n",
" [[[-1. 0.1 2.1]\n",
" [ 0. 0. 0. ]]\n",
"\n",
" [[ 0. 0. 0. ]\n",
" [-1. 0.1 2.1]]] \n",
"\n",
"shape: (2, 2, 3)\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "Gcw6bNirweZl",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Finally, we compute the gradients of the neural network output $f$ with respect to the parameters $A$ and $\\mathbf{b}$ and the input $\\mathbf{x}$ using the chain rule:\n",
"\n",
"\\begin{align}\n",
"\\frac{\\partial \\mathbf{f}}{\\partial \\mathbf{x}} &= \\frac{d \\mathbf{f}}{d \\mathbf{z}} \\frac{\\partial \\mathbf{z}}{\\partial \\mathbf{x}} \\ ; \\ \n",
"\\frac{\\partial \\mathbf{f}}{\\partial \\mathbf{b}} = \\frac{d \\mathbf{f}}{d \\mathbf{z}} \\frac{\\partial \\mathbf{z}}{\\partial \\mathbf{b}} \\ ; \\ \n",
"\\frac{\\partial \\mathbf{f}}{\\partial A} = \\frac{d \\mathbf{f}}{d \\mathbf{z}} \\frac{\\partial \\mathbf{z}}{\\partial A} \n",
"\\end{align}"
]
},
{
"metadata": {
"id": "o22q4uljzbpR",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 357
},
"outputId": "c07b47af-c680-4e0a-ef47-f9bf921a8346"
},
"cell_type": "code",
"source": [
"dfdx = np.einsum('il, lj', dfdz, dzdx)\n",
"print('df/dx =\\n', dfdx, '\\n\\nshape:', dfdx.shape)\n",
"print()\n",
"\n",
"dfdb = np.einsum('il, lj', dfdz, dzdb)\n",
"print('df/db =\\n', dfdb, '\\n\\nshape:', dfdb.shape)\n",
"print()\n",
"\n",
"dfdA = np.einsum('il, ljk', dfdz, dzdA)\n",
"print('df/dA =\\n', dfdA, '\\n\\nshape:', dfdA.shape)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"df/dx =\n",
" [[-0.12041293 -0.27694975 -0.09633035]\n",
" [-0.10161478 -0.233714 -0.08129183]] \n",
"\n",
"shape: (2, 3)\n",
"\n",
"df/db =\n",
" [[0.12041293 0.12041293]\n",
" [0.10161478 0.10161478]] \n",
"\n",
"shape: (2, 2)\n",
"\n",
"df/dA =\n",
" [[[-0.12041293 0.01204129 0.25286716]\n",
" [-0.12041293 0.01204129 0.25286716]]\n",
"\n",
" [[-0.10161478 0.01016148 0.21339105]\n",
" [-0.10161478 0.01016148 0.21339105]]] \n",
"\n",
"shape: (2, 2, 3)\n"
],
"name": "stdout"
}
]
}
]
}
================================================
FILE: Practical_0_5_Machine_Learning_Basics.ipynb
================================================
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Practical 0.5: Machine Learning Basics",
"version": "0.3.2",
"provenance": [],
"collapsed_sections": [
"RyJ1PgtEFpa7",
"sFJBmN5Hivhv",
"EgLuuVNRQHqy"
]
},
"kernelspec": {
"name": "python2",
"display_name": "Python 2"
}
},
"cells": [
{
"metadata": {
"id": "SB0EeXzyu_sz",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"# Practical 0.5: Machine Learning Basics"
]
},
{
"metadata": {
"id": "c9tLLZUyVwcV",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Introduction\n",
"In this practical, we introduce the idea of classification (sorting things into categories) using a machine-learning model. We explore the relationship between a classifier's parameters and the decision boundary (a line that separates categories) and also introduce the idea of a loss function. Finally, we briefly introduce Tensorflow.\n",
"\n",
"## Learning Objectives \n",
"* Understand the idea of **classification**\n",
"* Understand the concept of (linear) **separability** of a dataset.\n",
"* Understand what the **parameters** of a classifier are and how they relate to the **decision boundary**\n",
"* Be able to briefly explain what **Tensorflow** is."
]
},
{
"metadata": {
"id": "mHlHxAdBu7Dy",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 119
},
"outputId": "9b77f6e9-46c7-4004-f0bb-9d108bbffa95"
},
"cell_type": "code",
"source": [
"#@title [RUN ME!] Imports { display-mode: \"form\" }\n",
"!pip install -q moviepy\n",
"!pip install -q imageio\n",
"from __future__ import absolute_import, division, print_function\n",
"\n",
"import tensorflow as tf\n",
"import numpy as np # Numpy is an efficient linear algebra library.\n",
"import matplotlib.pyplot as plt # Matplotlib is used to generate plots of data.\n",
"from matplotlib import animation, rc\n",
"\n",
"from IPython import display\n",
"\n",
"try:\n",
" tf.enable_eager_execution()\n",
" print('Running eagerly')\n",
"except ValueError:\n",
" print('Already running eagerly')\n",
" \n",
"tfe = tf.contrib.eager"
],
"execution_count": 1,
"outputs": [
{
"output_type": "stream",
"text": [
"Imageio: 'ffmpeg-linux64-v3.3.1' was not found on your computer; downloading it now.\n",
"Try 1. Download from https://github.com/imageio/imageio-binaries/raw/master/ffmpeg/ffmpeg-linux64-v3.3.1 (43.8 MB)\n",
"Downloading: 8192/45929032 bytes (0.0%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b630784/45929032 bytes (1.4%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b1761280/45929032 bytes (3.8%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b3309568/45929032 bytes (7.2%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b5693440/45929032 bytes (12.4%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b9068544/45929032 bytes (19.7%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b13049856/45929032 bytes (28.4%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b17113088/45929032 bytes (37.3%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b21045248/45929032 bytes (45.8%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b24961024/45929032 bytes (54.3%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b28975104/45929032 bytes (63.1%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b33030144/45929032 bytes (71.9%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b37052416/45929032 bytes (80.7%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b41066496/45929032 bytes (89.4%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b45080576/45929032 bytes (98.2%)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b45929032/45929032 bytes (100.0%)\n",
" Done\n",
"File saved as /root/.imageio/ffmpeg/ffmpeg-linux64-v3.3.1.\n",
"Running eagerly\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "1xhQkS8A_KrJ",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Outline\n",
"In this practical, we tackle the task of **classification** of a simple, synthetic dataset. Classification in machine learning involves learning a labelling of examples into one (or more) discrete categories. This differs from another common task in machine learning called **regression**, which involves learning a mapping from inputs to a continuous-valued output. \n",
"\n",
"1. We begin by introducing a synthetic dataset of red and blue points which we want to separate\n",
"2. We introduce and explore the idea of **linear seperability**\n",
"3. We define a **loss** as a measure of how good of a seperator a particular line is\n",
"4. We briefly introduce TensorFlow and show how it can be used to automatically find the minimum of a loss function."
]
},
{
"metadata": {
"id": "H020s1EsB_9p",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"#@title [RUN ME!] Helper functions { display-mode: \"form\" }\n",
"def plot_dataset(inputs, labels):\n",
" # Plot the given 2D inputs and labels using Matplotlib. \n",
" plt.scatter(\n",
" inputs[:, 0], inputs[:, 1], \n",
" c=['red' if label > 0 else 'blue' for label in labels])\n",
"\n",
" plt.axis('equal')\n",
"\n",
" plt.xlabel('x1')\n",
" plt.ylabel('x2')"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "3l1rLP3HufZv",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## The Data"
]
},
{
"metadata": {
"id": "FCu4YZy-uj0v",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Run the code in the cell below, and look at the resulting plot. It should produce a simple 2-D data set consisting of 2 classes of points, the classes are represented by colours blue and red. Our task is to build a **binary classifier** that can distinguish between red and blue points (red and blue are referred to as the **classes** of the points), using only the 2-D coordinates of a point. In other words, we want a function that takes as input a 2-D vector representing the coordinates of a point and returns a value of 1 or 0 indicating whether the point is red or blue. Here we have **encoded** the colours red and blue into the numbers 1 and 0 (which make it easier to work with in maths and code!)\n",
"\n",
"Note: we have arbitrarily encoded red as 1 and blue as 0, you could do it the other way around too as long as you're consistent!"
]
},
{
"metadata": {
"id": "2SrsrFSTtrl6",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 361
},
"outputId": "73c152d0-097e-444b-ce34-dd483940c083"
},
"cell_type": "code",
"source": [
"#@title Generate the Dataset {run: \"auto\"}\n",
"# Define the centre(s) of the points\n",
"centre = 1 #@param {type:\"slider\", min:0, max:2, step:0.1}\n",
"\n",
"points_in_class = 20 # How many points we want per class\n",
"\n",
"# A fixed random seed is a common \"trick\" used in ML that allows us to recreate\n",
"# the same data when there is a random element involved. \n",
"np.random.seed(0) \n",
"\n",
"# Generate random points in the \"red\" class\n",
"red_inputs = np.random.normal(loc=centre, scale=1.0, size=[points_in_class, 2]) \n",
"# Generate random points in the \"blue\" class\n",
"blue_inputs = np.random.normal(loc=-centre, scale=1.0, size=[points_in_class, 2]) \n",
"# Put these together\n",
"inputs = np.concatenate((red_inputs, blue_inputs), axis=0) \n",
" \n",
"# The class (label) is 1 for red or 0 for blue\n",
"red_labels = np.ones(points_in_class) \n",
"blue_labels = np.zeros(points_in_class)\n",
"labels = np.concatenate((red_labels, blue_labels), axis=0)\n",
"\n",
"# num_data_points is the total data set size\n",
"num_data_points = 2 * points_in_class\n",
"\n",
"plot_dataset(inputs, labels)"
],
"execution_count": 3,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\nB/OXgJIZT2EKAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7f06f0e943d0>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"metadata": {
"id": "an9GF8nZWS4K",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"###What does the data look like? \n",
"The inputs are 2-dimensional vectors (points in a 2-D space). Here are the coordinates of 4 points, which we've deliberately chosen so that points 1 and 2 are \"red\" and points 3 and 4 are \"blue\". "
]
},
{
"metadata": {
"id": "5f8M-vQYWUuI",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"print('Input 1:\\t', inputs[0])\n",
"print('Input 2:\\t', inputs[1])\n",
"\n",
"print('Input 3:\\t', inputs[-1])\n",
"print('Input 4:\\t', inputs[-2])"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "E14elwRYWoxB",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"The labels are either 0 or 1. Here are the labels corresponding to the points above:"
]
},
{
"metadata": {
"id": "q4EJG8g4Wtih",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"print('Label 1:\\t', labels[0])\n",
"print('Label 2:\\t', labels[1])\n",
"\n",
"print('Label 3:\\t', labels[-1])\n",
"print('Label 4:\\t', labels[-2])"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "RyJ1PgtEFpa7",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Aside: Other Examples of Binary Classification Problems"
]
},
{
"metadata": {
"id": "7LAhNs_GFwOZ",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"In this practical, we are using a synthetic dataset where we have 2 classes of 2-D points that come from different distributions, distinguised by the colours, red and blue. To make this more concrete, here are some examples of more real-world binary classification problems.\n",
"\n",
"* Determine whether an email message (input) is SPAM or NOT SPAM (label)\n",
"* Determine whether an image, represented by its encoded pixel values (input) is a picture of a DOG or a CAT (label)\n",
"* Determine whether energy usage of a building will go UP or DOWN (label) next month, using a time series of past energy usage values (input)\n"
]
},
{
"metadata": {
"id": "qNuMy1XwIJ-z",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Linear separability\n",
"\n",
"Linear separability of a D-dimensional dataset with 2 classes means that there exists a single (D-1)-dimensional (hyper-)plane that separates the classes (a hyperplane is a generalisation of a straight line to many dimensions). In this case, the dataset is 2-dimensional and is **linearly separable** if it is possible to draw a (1-D) line between the red and blue points such that all of the red points lie on one side of the line and all of the blue points on the other. \n",
"\n",
"### Exploratory Task\n",
"In the code cell under the heading \"The Data\", change the slider for the ```centre``` value. This will automatically update the value in the code and will redraw the plot.\n",
"\n",
"* At what value of centre does the dataset become linearly separable?\n",
"\n",
"\n",
"### Question for discussion\n",
"Can you think of some 2-D, 2-class datasets, similar to the one above, that are separable (the points from the 2 classes don't overlap each other), but are not **linearly** separable? Draw some examples on paper or plot them using Matplotlib and discuss this with your neighbour and tutors. \n",
"\n"
]
},
{
"metadata": {
"id": "GV5plkAowLy8",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Drawing the line\n",
"\n",
"As you may recall from school, a line in 2 dimensions, with coordinate axes $x_1$ and $x_2$, which passes through the origin (0, 0) can be represented by the equation $w_1x_1 + w_2x_2 = 0$\n",
"\n",
"We can also write this in vector form as: $\\mathbf{w}^T\\mathbf{x} = 0$, where $\\mathbf{w}^T = [w_1, w_2]$ and $\\mathbf{x}^T = [x_1, x_2]$.\n",
"\n",
"When a line (or hyperplane) is defined this way, we call the **parameters**, $\\mathbf{w} = (w_1, w_2)$ a **normal vector** for the line. The normal vector is orthogonal (perpendicular) to the line. We want to construct such a line that separates red and blue points, which we will call a **decision boundary**. \n",
"\n",
"In the following cell, we plot our dataset along with a normal vector $\\mathbf{w}$ and decision boundary. You can adjust the values of $w_1$ and $w_2$ by using the sliders on the right. Observe the effect that the values have on the normal vector drawn in *red* and decision boundary in *black*. Adjust the values so that the black line separates the blue and red points (i.e. red points on one side and blue on the other). Your line should also have the normal vector pointing in the direction of the red points. The reason that direction is significant is that we want to eventually **classify** points on one side of the line as being red and the other as being blue. \n",
"\n",
"Is it possible to find a line through the origin that perfectly separates the points?\n",
"\n",
"**Note**: Each of our inputs is a 2-D vector, made up of two coordinate values. We refer to these 2 coordinate axes as $x_1$ and $x_2$. For example, if we have an input $(1, 2)$, then we would say $x_1 = 1$ and $x_2 = 2$ for that point."
]
},
{
"metadata": {
"id": "TAXUNshcvPsg",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 365
},
"outputId": "e8a20f5e-039b-4932-83f2-033d9513899b"
},
"cell_type": "code",
"source": [
"#@title Effect of parameters {run: \"auto\"}\n",
"\n",
"# Define the parameters\n",
"w1 = -1 #@param { type: \"slider\", min: -5, max: 5, step: 0.1 }\n",
"w2 = 1 #@param { type: \"slider\", min: -5, max: 5, step: 0.1 }\n",
"\n",
"plot_dataset(inputs, labels)\n",
"\n",
"# Add the weight vector to the plot. We plot it in red, as it has to \"point\"\n",
"# in the direction of the red points.\n",
"ax = plt.axes()\n",
"ax.arrow(0, 0, w1, w2, head_width=0.3, head_length=0.3, fc='r', ec='r')\n",
"\n",
"# Plot part of the decision boundary in black. It is orthogonal to the weight\n",
"# vector.\n",
"t = 2\n",
"plt.plot([-t * w2, t * w2], [t * w1, -t * w1], 'k-')\n",
"\n",
"plt.xlim([-4, 4])\n",
"plt.ylim([-4, 4])\n",
"\n",
"plt.show()"
],
"execution_count": 6,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\nx8PzCIMAAAAASUVORK5CYII=\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7f0707754dd0>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"metadata": {
"id": "igAjsyMldbMr",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Classification\n",
"Given a normal vector $\\mathbf{w}$, we can evaluate which side of the decision boundary a particular point $\\mathbf{x_i} = (x_{i,1}, x_{i, 2})$ lies by evaluating $\\mathbf{w^Tx_i}$. If $\\mathbf{w^Tx_i} > 0$, the point $\\mathbf{x_i}$ lies to one side of the boundary (in the direction of the normal vector), and we can classify that point as belonging to class 1 (in our case, \"red\"). If $\\mathbf{w^Tx_i} < 0$ the point lies on the other side and can be classified as class 0 (in our case, \"blue\"). Finally if $\\mathbf{w^Tx_i} = 0$ the point lies on the decision boundary and we can decide whether to classify it as either 0 or 1, or ignore it. "
]
},
{
"metadata": {
"id": "jqW7RpSTaRZH",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## How \"good\" is the line?\n",
"\n",
"If you've played around with the above code, you may have developed some intuition around how different settings of the parameters influence the final placement of the decision boundary. The purpose of machine learning is to *automatically* adjust the values of $w_1$ and $w_2$ to find a suitable decision boundary! But to do this, we need to mathematically specify some **loss** or **objective** function. The loss is a function of the parameters $w_1$ and $w_2$ and tells us how good a certain configuration of the parameter values are at classifying the data. This function is defined such that it reaches its optimum setting when it is minimised, i.e. the *smaller* its value, the *better* the separation between the classes. An additional property a loss function can have that is often crucial for machine learning is being *differentiable*. A differentiable loss function allows us to use *gradient-based optimisation* to find its minimum and the corresponding optimal values of $w_1$ and $w_2$. \n",
"\n",
"For this classification problem, we consider the **binary cross-entropy** loss function to measure how good the model's predictions are. This loss function compares the model's prediction for each example, $\\mathbf{x_i}$ to the true **target** $y_i$ (we often refer to the true label associated with an input as the \"target\"). It then applies the non-linear log function to penalise the model for being further from the true class. The equation for the binary cross entropy loss, on a dataset with $N$ points is:\n",
"\n",
"\\begin{align}\n",
"l(\\mathbf{w}) = -\\frac{1}{N}\\sum_{i=1}^N y_i log(\\hat{y}_i) + (1-y_i)log(1-\\hat{y}_i)\n",
"\\end{align}\n",
"\n",
"where $\\hat{y}_i = \\operatorname{sigmoid}(\\mathbf{w}^T\\mathbf{x_i})$ and the $\\operatorname{sigmoid}$ function is defined as:\n",
"\n",
"$$\n",
"\\mathrm{sigmoid}(a) = \\frac{1}{1 + e^{-a}} .\n",
"$$\n",
"\n",
"The reason we use the $\\operatorname{sigmoid}$ function is because our classifier can output any real value. The binary cross entropy loss function, however, expects the predictions made by a classifier to be between $0$ and $1$. The sigmoid function \"squashes\" any real number inputs to lie in the interval $(0, 1)$.\n",
"\n",
"Let's now wrap this in a Python function so that we can compute the loss for any values of $w_1$ and $w_2$:\n",
"\n"
]
},
{
"metadata": {
"id": "wKkpBZ6ZWLoF",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"def compute_loss(w1, w2):\n",
" \n",
" total_log_likelihood = 0 \n",
" \n",
" # Add the contribution of each datapoint to the loss\n",
" for (x1, x2), target in zip(inputs, labels):\n",
" # As our targets are 0 or 1, our prediction function must output a value between 0 and 1.\n",
" # The sigmoid function 'squashes' any value to lie between 0 and 1:\n",
" prediction = tf.sigmoid(w1*x1 + w2*x2) \n",
" \n",
" # Compute the local loss term\n",
" # We add 1e-10 to make the log operations numerically stable (i.e. avoid taking the log of 0.)\n",
" log_likelihood = target * tf.log(prediction + 1e-10) + (1.-target)*tf.log(1.-prediction + 1e-10)\n",
" total_log_likelihood += log_likelihood\n",
" \n",
" loss = -total_log_likelihood\n",
" average_loss = loss / len(inputs)\n",
" return average_loss"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "x2P-s50pgj-N",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### More on the sigmoid function"
]
},
{
"metadata": {
"id": "AQqQ_quqwCFF",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"\n",
"\n",
"The sigmoid function is defined as\n",
"$$\n",
"\\mathrm{sigmoid}(a) = \\frac{1}{1 + e^{-a}} .\n",
"$$\n",
"Can you show that\n",
"$$\n",
"1 - \\mathrm{sigmoid}(a) = \\frac{1}{1 + e^{a}} ,\n",
"$$\n",
"and draw both of these on a sheet of paper?\n",
"\n",
"* What is its value when $a = \\mathbf{w}^{T}\\mathbf{x}$ is positive? negative? and zero?\n",
"* What happends to its value when $a = \\mathbf{w}^{T}\\mathbf{x}$ becomes larger?\n",
"* What is the value of $\\mathrm{sigmoid}(\\mathbf{w^Tx})$ when $\\mathbf{w}^T\\mathbf{x} = 0$? How does this change how we classify points on either side of the decision boundary?\n",
"\n",
"After working through the above questions, explain to your neighbour why the binary cross-entropy loss function makes sense. \n",
"\n",
"**HINT**: Remember the idea of the loss function is to return small values when the classifier makes good predictions and large values when the classifier makes bad predictions. "
]
},
{
"metadata": {
"id": "x46fjqTUf4Dj",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Bonus Question\n",
"We derived the `compute_loss()` function above based on minimising the log-loss of the prediction error. This is related to a concept called 'cross-entropy'. But another way of deriving exactly the same loss function is by maximising the likelihood of the data under the model $P(y | x, w_1, w_2)$. If you are familiar with this concept (eg. from statistics), see if you can derive it this way as well.\n",
"\n",
"### Optional Further Reading\n",
"More information on the [cross-entropy loss](http://ml-cheatsheet.readthedocs.io/en/latest/loss_functions.html) and another interesting connection to [information theory](https://rdipietro.github.io/friendly-intro-to-cross-entropy-loss/)."
]
},
{
"metadata": {
"id": "0tJJrBynf6ms",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Loss value for your chosen $w_1$ and $w_2$\n"
]
},
{
"metadata": {
"id": "edKlqlACgFsE",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"The following line of code computes the loss value for your chosen values of $w_1$ and $w_2$. Try changing the values of $w_1$ and $w_2$ using the sliders above and rerun the line below. Can you see how a better separation results in a lower loss? \n",
"\n",
"Note: If you've used TensorFlow before, it might be confusing how this code cell works! We explain more about this later... "
]
},
{
"metadata": {
"id": "QyzwKx6ef_Vm",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"outputId": "4f013900-35c4-4d70-9a61-4e1677767c07"
},
"cell_type": "code",
"source": [
"compute_loss(w1, w2).numpy()"
],
"execution_count": 0,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"0.09962160420831814"
]
},
"metadata": {
"tags": []
},
"execution_count": 9
}
]
},
{
"metadata": {
"id": "Z9KAMYSUgmkM",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Visualising the loss function"
]
},
{
"metadata": {
"id": "ukphZS4_hMgN",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"We can visualise the loss function for our dataset by plotting its value at every point in a whole grid of $w_1$ and $w_2$ parameter values. We do this using a **contour plot**, which is a technique for visualising a 3-D function on a 2-D plot by letting colour represent the third dimension. All of the points with the same colour have the same loss value. "
]
},
{
"metadata": {
"id": "y4HZS5zZt3Pu",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 376
},
"outputId": "0befe58e-fc5e-42aa-aae9-49f9fe5cab8c"
},
"cell_type": "code",
"source": [
"# We define a function so we can re-use this code later\n",
"def plot_contours(): \n",
" # Generate a whole bunch of (w1, w2) points in a grid\n",
" ind = np.linspace(-5, 5, 50)\n",
" w1grid, w2grid = np.meshgrid(ind, ind)\n",
"\n",
" # Compute the loss for each point in the grid\n",
" losses = []\n",
" for w1s, w2s in zip(w1grid, w2grid):\n",
" loss = compute_loss(w1s, w2s)\n",
" losses.append(loss)\n",
"\n",
" # Pack the loss values for every value of w1 & w2 into one (50,50) array\n",
" losses_array = np.concatenate(losses).reshape(50,50)\n",
"\n",
" # Now plot the resulting loss function as a contour plot over the whole grid of (w1, w2) values.\n",
" fig = plt.figure()\n",
" plt.contourf(w1grid, w2grid, losses_array, 20, cmap=plt.cm.jet)\n",
" cbar = plt.colorbar()\n",
" cbar.ax.set_ylabel('Binary cross-entropy loss value')\n",
" plt.xlabel('w1 value')\n",
" plt.ylabel('w2 value')\n",
" plt.title('Total loss for different values of w1 and w2')\n",
"\n",
"plot_contours()"
],
"execution_count": 8,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\nCxfGy8uL0NBQtm/fDoC/vz/ffvstsbGxNGzYkFGjRuX5+qMcPHiQypUrU7t2bQA6dOjA9evXuXLl\nCgBPPPEEVatWzTHu3LlzZGZm0rhxYwBCQ0NV/UxZTp8+za1bt6zj6tevT9GiRTl8+DAARYoUoX79\n+gBs27aNJk2a8MQTTwD3K89Nmzah/O/k1wYNGlChQgUsFgvPPPOMde6P0rp1a44cOWKtKDdu3EiH\nDh3w8fFh9+7d1nvy9erVs1ayauzZs4fKlSvTqFEjALp27crp06e5du0apUqVYtu2bezfv5+CBQsy\na9YsSpcunW28rT+L3AQEBJCamkpCQgL79u2jefPmxMfHk5GRwf79+61/Pmr9+OOPtG/fPtefPz09\nnRdffBEg2+/zvn37aN++PV5eXvj7+9OyZctcr92wYUMOHTpEfHw8jz32GNWrV+fEiROcOnWKatWq\nUbRoUev3JiUlMXjwYN58803KlStn188ghBpyT9jAEhIS8Pb2pkiRItbXihUrRnx8fI7v3bp1K/Pn\nzychIQGLxQJgDQ9bbt68SbFixbJ9xs2bN4H74T5v3jxCQ0OpWLEi48aNo169eo98Pa/PKF68uPVr\ni8VC0aJFrT/Lg+89KCkpCT8/v2xzs8etW7e4c+eO9d4xwO3bt0lMTKRQoULZPjc5OZldu3Zl+94i\nRYqQlJQEkG0eBQoUICMjI8/P9vPzo2HDhmzbto2aNWty9+5dAgMDAVi4cCGrV68mLS2NP//8Ex8f\nH7t+pnPnzmWbZ+HChUlISKB///7A/Ya/uLg4Xn75Zd56661s4239WTxKgwYNOHz4MPv27aNt27ac\nO3eOkydPsn//fnr16qV6/gCrV69m6dKl3Llzh4yMDDIzM63v+fj4ULBgQQC8vLysv8+JiYnZ/gyK\nFy+e65wbNWrEwYMHyczMpG7dulSsWJEDBw7g4+OT7R8L165dY+DAgbRv356BAwfaNX8h1JIQNjB/\nf3/S09O5ffu29S+fxMRESpUqle370tLSGDp0KJ9++inNmzfn7t271ipHjVKlSlnvfT78GdWqVWP6\n9OlkZGQQHR3NiBEj+OWXXx75+qOULl0622dkZmaSlJSUo0p7WLFixbJ1iSckJKj+uQDKli1L8eLF\nWb9+fY73duzYke3rcuXK0bx5c2bOnGnXZ+QlJCSEn3/+mStXrlgrv71797Jw4UIiIyOpWLEiW7du\n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\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7f06ee305350>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"metadata": {
"id": "676bWBwTiXXD",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Optimising the loss using TensorFlow"
]
},
{
"metadata": {
"id": "MMLA-wk5xB7p",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Now that we have a function that gives us the loss for different values of $w_1$ and $w_2$, we want an automated method to find the values that minimise the loss function. This is where optimisation by **gradient descent** comes in. The idea is that for each (batch of) data points, we compute the loss using the current values of $w_1$ and $w_2$ on the data. We then compute the **gradient** (or derivative) of the loss function at the current values of $w_1$ and $w_2$. The negative of the gradient points in the direction of *steepest descent* along the loss function. By adjusting the values of $w_1$ and $w_2$ in the direction of the negative gradient, we move closer towards the minimum of the loss function (provided the loss function is \"well behaved\"). How big of a step we take is mediated by the **learning rate**. To do this more easily, we will use TensorFlow.\n",
"\n",
"Don't worry if you don't understand what's going on here, you will see this in a lot more detail during the **Mathematics for Machine Learning** lectures!\n",
"\n"
]
},
{
"metadata": {
"id": "sFJBmN5Hivhv",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Aside: TensorFlow"
]
},
{
"metadata": {
"id": "DRtDggkBi0X3",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"TensorFlow (TF) is an open source software library for numerical computation using the concept of Tensors. You can think of Tensors as being a generalisation of matrices to higher dimensions, or roughly equivalent to multi-dimensional arrays. Scalars are 0-dimensional tensors, vectors are 1-dimensional, standard matrices are 2-dimensional, and higher-dimensional tensors have 3 or more dimensions. You can think of dimensions as representing groups of numbers that mean the same thing. For example, for images, we often use 3-dimensional tensors where the first dimension represents the red, green, and blue color channels of the image, and the next two are the columns and rows of pixels of the image. \n",
"\n",
"**Note**: Don't be confused when people say \"2-D vector\" or \"3-D vector\", which refers to a 1-dimensional tensor that has size 2 or 3.\n",
"\n",
"The major advantage of using TensorFlow is that it can automatically derive the gradients of many mathematical expressions involving tensors. It achieves this through a process called \"automatic differentiation\". Tensorflow also supports multiple \"kernels\", allowing you to easily run your code on normal processors (CPUs), graphics cards (GPUs) and other more exotic hardware accelerators like Google's Tensor Processing Units (TPUs)\n",
"\n",
"Tensorflow actually provides **two modes of operation**, the first, called \"graph mode\", builds a computation graph upfront and then feeds data into the graph. By building the graph upfront, Tensorflow can apply optimisations to the graph that allow it to extract peak performance from the hardware you're running on. You will have encountered this mode if you used Tensorflow before or attended the Indaba last year! The second mode, called [\"Eager-mode\"](https://www.tensorflow.org/guide/eager), is a lot newer and evaluates Tensor operations imperatively (in the order you write them), similar to NumPy and PyTorch. Eager-mode is slightly less performant but a lot more intuitive, especially if you've never used a \"define-and-run\" programming style (like graph mode) before, and is therefore the mode we will use in these practicals. "
]
},
{
"metadata": {
"id": "eLVl2PhK2VpP",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Using Tensorflow to optimise the loss\n",
"We use TensorFlow to optimise the parameters of the model with gradient descent. We loop over the dataset multiple times (called \"epochs\") and plot the final decision boundary along with a plot showing how the parameters and loss changed over the epochs.\n",
"\n",
"**Note**: TensorFlow is probably overkill for this example, becaue the gradient is very easy to calculate, but we introduce it here because it will become essential to calculate the gradients of more complex models in later practicals! "
]
},
{
"metadata": {
"id": "cKre-CI8IG9z",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"lr = 0.25 # The learning rate\n",
"\n",
"# Initialise Tensorflow variables representing our parameters.\n",
"# We need to use TensorFlow variables here rather than Numpy or Python ones so \n",
"# that TensorFlow is able to compute gradients.\n",
"w1 = tfe.Variable(-2.0) \n",
"w2 = tfe.Variable(-4.0) \n",
"\n",
"plot_contours()\n",
"\n",
"# Loop over the dataset multiple times\n",
"parameter_values = []\n",
"for epoch in range(20):\n",
" plt.scatter(w1.numpy(), w2.numpy(), marker='o', color='black')\n",
" \n",
" with tf.GradientTape() as tape:\n",
" loss = compute_loss(w1, w2)\n",
" \n",
" # Now we take a step in parameter space in the direction of the gradient to move the parameters closer (hopefully!) to their optimum\n",
" dw1, dw2 = tape.gradient(loss, [w1, w2])\n",
" \n",
" # Step 'lr units' in the direction of the negative gradient\n",
" # We achieve this by subtracting lr * dw1 and lr * dw2 from the w1 and w2 variables\n",
" w1.assign_sub(lr*dw1)\n",
" w2.assign_sub(lr*dw2)\n",
" \n",
"print('Finished optimisation, the final values of w1 and w2 are:')\n",
"print(w1.numpy(), w2.numpy())\n",
"\n",
"# Plot the final point on the loss surface.\n",
"plt.scatter(w1.numpy(), w2.numpy(), marker='x', color='red')\n",
"plt.show()\n",
"\n",
"# Plot the final decision boundary\n",
"plot_dataset(inputs, labels)\n",
"ax = plt.axes()\n",
"ax.arrow(0, 0, w1.numpy(), w2.numpy(), head_width=0.3, head_length=0.3, fc='r', ec='r')\n",
"plt.plot([-2 * w2.numpy(), 2 * w2.numpy()], [2 * w1.numpy(), -2 * w1.numpy()], 'k-')\n",
"\n",
"plt.xlim([-4, 4])\n",
"plt.ylim([-4, 4])\n",
"\n",
"plt.show()"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "meoIDXSQjKeE",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"How did the final values of $w_1$ and $w_2$ found by Tensorflow correspond to the ones you found manually? \n",
"\n",
"## Optional Tasks\n",
"If you've worked through this practical, answered all the questions and feel you have a good understanding of what's going on, try the following tasks:\n",
"\n",
"1. Add a **bias** parameter to the equation for the decision boundary and visualise how that changes the decision boundary, the loss and the ultimate solution found by Tensorflow.\n",
"2. Add a **regulariser**, for example, the L2 regulariser (see the appendix below for more information) - how does it affect the contour plot of the parameters vs the loss? How does changing the strength of regularisation affect the loss? \n",
"\n",
"Note: The benefit of using regularisation will be discussed in the next practical! "
]
},
{
"metadata": {
"id": "SVFq4xvBmGQq",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"# Next Steps\n",
"Have a look at [last year's practical](https://github.com/deep-learning-indaba/practicals2017/blob/master/practical1.ipynb) which takes a more \"bottom-up\" approach, covers more detail on how gradients are computed and also looks at a multi-class classification problem with a non-linear decision boundary. \n",
"\n",
"Note: last year's practicals use Tensorflow's \"graph mode\" as opposed to \"Eager mode\" that we use here."
]
},
{
"metadata": {
"id": "4jpKVuEkQF46",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"# Appendix"
]
},
{
"metadata": {
"id": "EgLuuVNRQHqy",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### L1 and L2 Regularisation"
]
},
{
"metadata": {
"id": "SlO75RlmQKQF",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Two of the most simple regularization methods are L1 and L2 regularization (you may have heard of them as _Lasso_ and _Ridge_ regression if you've used linear regression before). Both of these methods regularize the model by adding a term to the loss that penalizes the model if it becomes too complex.\n",
"L1 regularization adds a term based on the L1 norm:\n",
"\n",
"$loss_{L1} = loss + \\lambda \\sum_i |w_i|$\n",
"\n",
"where $\\lambda$ is a parameter that controls the amount of regularization, and $w_i$ are the parameters of the model. L1 regularization has the effect of forcing some parameters to shrink to 0, effectively removing them from the model.\n",
"\n",
"L2 regularization similarly adds a term based on the L2 norm:\n",
"\n",
"$loss_{L2} = loss + \\lambda \\sum_i w_i^2$.\n",
"\n",
"L2 regularization has the effect of preventing any of the parameters from becoming too large and _overpowering_ the others. \n",
"\n",
"In some cases it can work well to use both L1 and L2 regularization. \n",
"\n",
"For more information see the articles [here](http://enhancedatascience.com/2017/07/04/machine-learning-explained-regularization/) and [here](https://towardsdatascience.com/l1-and-l2-regularization-methods-ce25e7fc831c)."
]
}
]
}
================================================
FILE: Practical_1_Deep_Feedforward_Networks.ipynb
================================================
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Practical 1: Deep Feedforward Networks",
"version": "0.3.2",
"provenance": [],
"collapsed_sections": [
"tHy4bjbTVCzV",
"SIUsSjNwVk_n",
"ot-FjimzV6op"
]
},
"kernelspec": {
"name": "python2",
"display_name": "Python 2"
}
},
"cells": [
{
"metadata": {
"id": "dYUH0qf8Dqkm",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"# Practical 1: Deep Feed-forward Networks"
]
},
{
"metadata": {
"id": "6hH4wd81A_P8",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## Introduction\n",
"In this practical, we implement and train a feed-forward neural network (also known as an \"MLP\" for \"multi-layer perceptron\") on a dataset called \"Fashion MNIST\", consisting of small greyscale images of items of fashion. We consider the practical issues around generalisation to out-of-sample data and introduce some important techniques for addressing this. \n",
"\n",
"## Learning Objectives \n",
"* Understand how to use **Tensorflow Eager** and **Keras Layers** to build a neural network architecture\n",
"* Understand how a model is trained and evaluated\n",
"* Be able to explain why there is a difference between **in-sample** and **out-of-sample** model performance\n",
"* Understand the concept of **train/validation/test split** and why it's useful\n",
"* Research at least 1 technique that can be used to improve model **generalisation**"
]
},
{
"metadata": {
"id": "NxSD3yPDfEIj",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"outputId": "6c6beb36-83c9-4658-c4d0-08dbdbbc6a0f"
},
"cell_type": "code",
"source": [
"#@title Imports (RUN ME!) { display-mode: \"form\" }\n",
"from __future__ import absolute_import, division, print_function\n",
"\n",
"import tensorflow as tf\n",
"import tensorflow.contrib.eager as tfe\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"\n",
"try:\n",
" tf.enable_eager_execution()\n",
" print('Running in Eager mode.')\n",
"except ValueError:\n",
" print('Already running Eagerly')"
],
"execution_count": 1,
"outputs": [
{
"output_type": "stream",
"text": [
"Running in Eager mode.\n"
],
"name": "stdout"
}
]
},
{
"metadata": {
"id": "sU33KeDUDomX",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"## The Data"
]
},
{
"metadata": {
"id": "nL0dFs-DD6sM",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"In this practical, we use the Fashion MNIST dataset consisting of 70,000 greyscale images and their labels. The dataset is divided\n",
" into 60,000 training images and 10,000 test images. The idea is to train a **classifier** to identify the class value (what type of fashion item it is) given the image. We train and *tune* a model on the 60,000 training images and then evaluate how well it classifies the 10,000 test images that the model did not see during training. This task is an example of a **supervised learning** problem, where we are given both input and labels (targets) to learn from. This is in contrast to **unsupervised learning** where we only have inputs from which to learn patterns or **reinforcement learning** where an agent learns how to maximise a reward signal through interaction with its environment. "
]
},
{
"metadata": {
"id": "3lEM3aBa2N63",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"###Aside: Train/Validation/Test Split\n",
"\n",
"When we build machine learning models, the goal is to build a model that will perform well on *future* data that we have not seen yet. We say that we want our models to be able to **generalise** well from whatever training data we can collect and do have available, to whatever data we will be applying them to in future. To do this, we split whatever data we have available into a **training set, a validation set and a test set**. The idea is that we train our model and use the performance on the validation set to make any adjustments to the model and its hyperparameters, but then we report the final accuracy on the test set. The test set (which we never train on), therefore acts as a proxy for our future data."
]
},
{
"metadata": {
"id": "9VRxcYWHfZJ5",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"# Tensorflow has convenient modules for loading a number of standard datasets\n",
"fashion_mnist = tf.keras.datasets.fashion_mnist\n",
"(train_and_validation_images, train_and_validation_labels), (test_images, test_labels) = fashion_mnist.load_data()\n",
"\n",
"text_labels = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "1Z_Ks31qEfUM",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Construct a validation set\n",
"Next, we remove 10,000 images and labels from the training set to use as a validation set. We will come back to the validation set later! "
]
},
{
"metadata": {
"id": "dZKEjjGM8I4t",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"# Construct a validation set from the last 10000 images and labels from \n",
"# train_and_validation_images and train_and_validation_labels\n",
"validation_images = train_and_validation_images[-10000:, :, :]\n",
"validation_labels = train_and_validation_labels[-10000:]\n",
"\n",
"# Construct a training set from the first 50000 images and labels.\n",
"train_images = train_and_validation_images[:50000, :, :]\n",
"train_labels = train_and_validation_labels[:50000]"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "fbWk7qJOEkl6",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### What does the data look like?\n",
"Each image in the dataset consists of a 28 x 28 matrix of greyscale pixels. The values are between 0 and 255 where 0 represents black, 255 represents white and there are many shades of grey in-between. Each image is assigned a corresponding numerical label, so the image in ```train_images[i]``` has its corresponding label stored in ```train_labels[i]```. We also have a lookup array called ```text_labels``` to associate a text description with each of the numerical labels. For example, the label 1 is associated with the text description \"Trouser\".\n",
"\n",
"The 2 cells below demonstrate how to visualise the input data. Make sure you understand what's happening, particularly how the indices correspond to individual items in the dataset. "
]
},
{
"metadata": {
"id": "PgfvNeX2gcAL",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 280
},
"outputId": "4b853a99-0389-4dc8-d163-0714ad00507b"
},
"cell_type": "code",
"source": [
"# We use the Matplotlib plotting library to visualise an image selected at random from the training set \n",
"plt.figure()\n",
"random_index = np.random.randint(0, len(train_images))\n",
"plt.imshow(train_images[random_index], cmap='gray')\n",
"plt.colorbar()\n",
"numerical_label = train_labels[random_index]\n",
"text_description = text_labels[numerical_label]\n",
"plt.title('True Class: {} (\"{}\")'.format(numerical_label, text_description))\n",
"\n",
"plt.gca().grid(False)"
],
"execution_count": 4,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\nAYPHSa3T0HhhAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7f67cfc18790>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"metadata": {
"id": "-utfMlxhhL3b",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 589
},
"outputId": "18781e96-bf98-4a18-8e3e-3149fac0df80"
},
"cell_type": "code",
"source": [
"# Another view, showing 25 randomly selected images at a time\n",
"plt.figure(figsize=(10,10))\n",
"for i in range(25):\n",
" plt.subplot(5,5,i+1)\n",
" plt.xticks([])\n",
" plt.yticks([])\n",
" plt.grid('off')\n",
" \n",
" img_index = np.random.randint(0, 50000)\n",
" plt.imshow(train_images[img_index], cmap=plt.cm.gray)\n",
" plt.xlabel(text_labels[train_labels[img_index]])"
],
"execution_count": 5,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\n/N1sTp4c5mQAlzvnjkdp8Xy9/O9/AXCzc24EgH8DqHFxzwLwgHNuBUrutXHe+w+cc/8D4GrnXE07\n7SY9WQXkAAAXOedeALAMwIcouVOfBrAtSj+M6wG4w3v/uHPuVQD/dM49AuBxlLTg/3PO7Q7gPgBP\nO+cOWtPsD7FWtHXOTWMKIDIAACAASURBVEBpnlqjtO5OQukve+YsAFc55yai9ON3RfkHcbW1CWAO\ngHHOueNQuibmoDTfYt2htVk8qvJ3s0mmkAshhBBCrC3NVa4SQgghhMiihxwhhBBCFBI95AghhBCi\nkOghRwghhBCFRA85QgghhCgkesgRQgghRCHJ1slp0aJFk84vb9GiRfQ6lQ5/9NFHR6+/+MUvBvu5\n554L9osvvhiN69y5c7AHDRoU7NatW0fjttlmm2Cfcsop0baJEyfWekw5PvvssxafP2rNWZfzOXTo\n0GDfd9990bYHH3ww2Outt6p6/PLlcWubDz/8MNj/+c+qQpqffBI3M15//VWXMe/v/fffj8aVy5AD\nAO66665gX3nllYlvUT80xHw21trs2rVr9LpXr17BXrJkSbA//fTTaByv1U6dOgV70003jcZtuGEo\nuIotttgi2K1axa2rzjnnnGD/97+27mDDUYS1yfDaAeK1NWDAgGD/5S9/icadddZZwb799tuT++fr\n449//GOwTzrppGjcjBkzKjvgeqZIa7NHj7he5tlnnx3sbbfdNthPPBF3XliwYEGwP/7442B/4Qux\nD6R3797B3mOPPYJ92223ReP++te/BnvhwoUVHXulv+U5UnMpT44QQgghCokecoQQQghRSJprWwcA\nlbu4dt111+g1u+fYxbfPPvtE45599tlgL1q0qjdghw4donHnnntusPv06RNte+mll4K9bNmyYFtX\n4Lp0ua8LunfvHuyPPvoo2savN9988+Q+WHrabLPNgm1lLT6X9rMYfl+3bt2S46oRPoe5a5ElByCW\nkT744INgd+zYMRrHa5Wlx7Zt20bjVqxYEWxec6NGjYrG8XXz4x//OHm8Ik9OFnjvvfeCbSV6lqt+\n97vfBXvp0qXRuJdffjnY06dPD7a9/1U7lf6WsQQFAGeccUaw33777WgbS8abbLJJsIcPH17n46xh\n5cqVwT7ttNOibT/60Y+CzSEHhx9+eDTu8cdXdWppyM4LutKEEEIIUUj0kCOEEEKIQqKHHCGEEEIU\n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\nEEIIUUr+P9rPn3cslCmKAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7f67cef7f090>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"metadata": {
"id": "qMwKN4DHcqXV",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Exploratory Task\n",
"Run the above cells multiple times to get a good sense of the dataset. Look at the general structure of the images and their corresponding labels. Can you spot some classes that might be difficult for a classifier to distinguish? If so, why do you think they would be difficult to distinguish? Chat to your neighbour about this. \n"
]
},
{
"metadata": {
"id": "S6U63sTpGYvg",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"### Preparing the data with TensorFlow\n",
"At the moment, our training data consists of two large tensors. The images are stored in a tensor of shape $[50000, 28, 28]$, consisting of all the $28 \\times 28$ images matrices stacked together. The labels are stored in a 1D vector of shape $[50000]$. We wish to train a model using **mini-batch stochastic gradient descent**. In order to do so, we need to shuffle the data and split it into smaller (mini-)batches. We also convert the data from numpy arrays to TensorFlow Tensors.\n",
"\n",
"#### Questions\n",
"* Can you explain what the difference is between normal stochastic gradient descent and \"batched\" stochastic gradient descent? What is the purpose of chunking data into batches during training? Are there any trade-offs? What are they? **HINT**: Speak to your neighbours and tutors about this. You can also read [this blog post](https://machinelearningmastery.com/gentle-introduction-mini-batch-gradient-descent-configure-batch-size/) for more details.\n",
"* Why is it important to randomise the data before chunking it into batches? \n",
"\n",
"In order to do this batching (and shuffling) we will use the Tensorflow [Dataset API](https://www.tensorflow.org/api_docs/python/tf/data/Dataset), which is a set of simple reusable components that allow you to build efficient data pipelines. Data is said to \"stream\" through the pipeline, meaning that when something at the output of the pipeline wants data, the pipeline will provide that data as soon as it has enough, rather than waiting to process all the data. This allows you to easily build pipelines that work on large datasets without having to load it all into memory in one go!\n",
"\n",
"We build this pipeline step-by-step:"
]
},
{
"metadata": {
"id": "HO8Z6SImg_7W",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"We being by defining the ```batch_size``` hyperparameter of our model. This hyperparameter controls the sizes of the mini-batches (chunks) of data that we use to train the model. The value you use will affect the memory usage, speed of convergence and potentially also the performance of the model. It also interacts with the *learning rate* used in gradient descent. "
]
},
{
"metadata": {
"id": "x7VwqreOhbfv",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"batch_size = 128"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "3CaT9bWFheRw",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"The first component we add will group the image and label tensors together into a tuple and then split them into individual entries - ie. 50000 tuples containing a (28, 28) dimensional image and 1D label associated with that image. The following line adds this splitting component to the pipeline."
]
},
{
"metadata": {
"id": "7wITDBK8h5Z6",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"train_ds = tf.data.Dataset.from_tensor_slices((train_images, train_labels))"
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "VNVG8Kb3h_CW",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"The next thing we do is apply a map operation. This lets us run an arbitrary function on each element. The function we provide returns the image values divided by 255 and converted ('cast') to a float and the label converted to a 32-bit integer.\n",
"\n",
"**NOTE**: \"Lambda\" functions are just one-line, anonymous functions. In this case, it defines a function that takes arguments x and y (before the colon), and outputs their manipulated values (after the colon)."
]
},
{
"metadata": {
"id": "4fcE7eTviBOi",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"# Divide image values and cast to float so that they end up as a floating point number between 0 and 1\n",
"train_ds = train_ds.map(lambda x, y: (tf.cast(x, tf.float32) / 255.0, tf.cast(y, tf.int32))) "
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "gm5iOdU0iD_0",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"Then we add a **shuffle** component. This returns a random element from the pipeline. Can you spot a potential problem here? \n",
"\n",
"**QUESTION**: What might happen if the shuffle component didn't have a *buffer*? **HINT**: Refer back to the discussion about the data pipeline and \"data streaming through it\" above."
]
},
{
"metadata": {
"id": "bvr5r8k6iJGI",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"# Shuffle the examples.\n",
"train_ds = train_ds.shuffle(buffer_size=batch_size * 10) "
],
"execution_count": 0,
"outputs": []
},
{
"metadata": {
"id": "OlGI65QIjOgp",
"colab_type": "text"
},
"cell_type": "markdown",
"source": [
"The final component in our pipeline is the batch component. This just requests `batch_size` elements from the previous pipeline component, groups them together into a single tensor and returns that."
]
},
{
"metadata": {
"id": "PB8CZrsmjR7Z",
"colab_type": "code",
"colab": {}
},
"cell_type": "code",
"source": [
"# Now \"chunk\" the examples into batches\n",
"train_ds = train_ds.batch(batch_
gitextract_p7frg7eu/ ├── Mathematics_for_Machine_Learning_Examples.ipynb ├── Practical_0_5_Machine_Learning_Basics.ipynb ├── Practical_1_Deep_Feedforward_Networks.ipynb ├── Practical_2_Convolutional_Neural_Networks.ipynb ├── Practical_3_Recurrent_Neural_Networks.ipynb ├── Practical_4_Reinforcement_Learning.ipynb ├── README.md └── practical0.ipynb
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,408K chars).
[
{
"path": "Mathematics_for_Machine_Learning_Examples.ipynb",
"chars": 16491,
"preview": "{\n \"nbformat\": 4,\n \"nbformat_minor\": 0,\n \"metadata\": {\n \"colab\": {\n \"name\": \"Mathematics for Machine Learning"
},
{
"path": "Practical_0_5_Machine_Learning_Basics.ipynb",
"chars": 99692,
"preview": "{\n \"nbformat\": 4,\n \"nbformat_minor\": 0,\n \"metadata\": {\n \"colab\": {\n \"name\": \"Practical 0.5: Machine Learning "
},
{
"path": "Practical_1_Deep_Feedforward_Networks.ipynb",
"chars": 115528,
"preview": "{\n \"nbformat\": 4,\n \"nbformat_minor\": 0,\n \"metadata\": {\n \"colab\": {\n \"name\": \"Practical 1: Deep Feedforward Ne"
},
{
"path": "Practical_2_Convolutional_Neural_Networks.ipynb",
"chars": 509015,
"preview": "{\n \"nbformat\": 4,\n \"nbformat_minor\": 0,\n \"metadata\": {\n \"colab\": {\n \"name\": \"Practical 2: Convolutional Neura"
},
{
"path": "Practical_3_Recurrent_Neural_Networks.ipynb",
"chars": 390773,
"preview": "{\n \"nbformat\": 4,\n \"nbformat_minor\": 0,\n \"metadata\": {\n \"colab\": {\n \"name\": \"Practical 3: Recurrent Neural Ne"
},
{
"path": "Practical_4_Reinforcement_Learning.ipynb",
"chars": 48488,
"preview": "{\n \"nbformat\": 4,\n \"nbformat_minor\": 0,\n \"metadata\": {\n \"colab\": {\n \"name\": \"Practical 4: Reinforcement Learn"
},
{
"path": "README.md",
"chars": 272,
"preview": "# Deep Learning Indaba 2018\n \nThis repository contains the practical notebooks for the Deep Learning Indaba\n2018, held "
},
{
"path": "practical0.ipynb",
"chars": 173896,
"preview": "{\n \"nbformat\": 4,\n \"nbformat_minor\": 0,\n \"metadata\": {\n \"colab\": {\n \"name\": \"practical0.ipynb\",\n \"versio"
}
]
About this extraction
This page contains the full source code of the deep-learning-indaba/indaba-2018 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (1.3 MB), approximately 713.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.