diff --git a/lab1/Part1_tensorflow.ipynb b/lab1/Part1_tensorflow.ipynb deleted file mode 100644 index ef3d41bc..00000000 --- a/lab1/Part1_tensorflow.ipynb +++ /dev/null @@ -1,506 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Part1_tensorflow.ipynb", - "version": "0.3.2", - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 2", - "language": "python", - "name": "python2" - } - }, - "cells": [ - { - "metadata": { - "id": "57knM8jrYZ2t", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "# Lab 1: Intro to TensorFlow and Music Generation with RNNs\n", - "# Part 1: Intro to TensorFlow" - ] - }, - { - "metadata": { - "id": "OhuYRQfjYZ2v", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 0.1 Install TensorFlow\n", - "\n", - "TensorFlow is a software library extensively used in machine learning. Here we'll learn how computations are represented and how to define a simple neural network in TensorFlow.\n", - "\n", - "Let's install TensorFlow and a couple of dependencies: \n" - ] - }, - { - "metadata": { - "id": "LkaimNJfYZ2w", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "3oWpEMtmYZ3I", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We'll then check to make sure things installed properly:" - ] - }, - { - "metadata": { - "id": "zLLaY8hvdbvQ", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "is_correct_tf_version = '1.14.' in tf.__version__\n", - "assert is_correct_tf_version, \"Wrong tensorflow version {} installed\".format(tf.__version__)\n", - "\n", - "is_eager_enabled = tf.executing_eagerly()\n", - "assert is_eager_enabled, \"Tensorflow eager mode is not enabled\"" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "vDJGsR2NoYtu", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "TensorFlow is set to release the next major version of TensorFlow, [TensorFlow 2.0](https://www.tensorflow.org/community/roadmap#tensorflow_20_is_coming), very soon. In this set of labs we'll be working in TensorFlow 1.14.0. The 6.S191 team is **Eager** to show you this version, as it features a (relatively) new imperative programming style called Eager execution. Under Eager execution, TensorFlow operations execute immediately as they're called from Python (which wasn't always the case!). This allows for fast debugging and a more intuitive way to get started with TensorFlow.\n", - "\n" - ] - }, - { - "metadata": { - "id": "iD3VO-LZYZ2z", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.1 The computation graph\n", - "\n", - "TensorFlow is called TensorFlow because it handles the flow (node/mathematical operation) of Tensors (data), which you can think of as multidimensional arrays. In TensorFlow, computations can be thought of as graphs. First, we'll explore defining a computational graph with Tensors and mathematical operations before diving in to how we can build deep learning models in TensorFlow. \n", - "\n", - "Let's look at a simple example, and define this computation using TensorFlow:\n", - "\n", - "![alt text](img/add-graph.png \"Computation Graph\")\n", - "\n", - "\n", - "\n" - ] - }, - { - "metadata": { - "id": "X_YJrZsxYZ2z", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Create the nodes in the graph, and initialize values\n", - "a = tf.constant(15, name=\"a\")\n", - "b = tf.constant(61, name=\"b\")\n", - "\n", - "# Add them!\n", - "c = tf.add(a,b, name=\"c\")\n", - "print(c)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mjYCF0EdYZ22", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Notice how we've created a computation graph consisting of TensorFlow operations, and how the output is a Tensor with value 76 -- we've just created a computation graph consisting of operations, and it's executed them and given us back the result. That's because of Eager!" - ] - }, - { - "metadata": { - "id": "Mbfv_QOiYZ23", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Building a computation graph\n", - "\n", - "Now let's consider a slightly more complicated computation graph:\n", - "![alt text](img/computation-graph.png \"Computation Graph\")\n", - "\n", - "This graph takes two inputs, `a, b`, and computes an output `e`. Each node in the graph is an operation that takes some input, does some computation, and passes its output to another node.\n", - "\n", - "Let's define a simple function in TensorFlow to construct this computation graph:" - ] - }, - { - "metadata": { - "scrolled": true, - "id": "PJnfzpWyYZ23", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Construct a simple computation graph\n", - "def graph(a,b):\n", - " '''TODO: Define the operation for c, d, e (use tf.add, tf.subtract, tf.multiply).'''\n", - " c = # TODO\n", - " d = # TODO\n", - " e = # TODO\n", - " return e" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "AwrRfDMS2-oy", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, we can call this function to execute the computation graph given some inputs `a,b`:" - ] - }, - { - "metadata": { - "id": "pnwsf8w2uF7p", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Consider example values for a,b\n", - "a, b = 1.5, 2.5\n", - "# Execute the computation\n", - "e_out = graph(a,b)\n", - "print e_out" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "6HqgUIUhYZ29", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Again, notice how our output is a Tensor with value defined by the output of the computation (thanks to Eager!)." - ] - }, - { - "metadata": { - "id": "1h4o9Bb0YZ29", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.2 Neural networks in TensorFlow\n", - "We can also define neural networks in TensorFlow, and it's often helpful to think about this using the idea of computation graphs. TensorFlow uses a high-level API called [Keras](https://www.tensorflow.org/guide/keras) that provides a powerful, intuitive framework for building and training deep learning models. In the 6.S191 labs we'll be using the Keras API to build and train our models.\n", - "\n", - "Let's consider this example of a very simple neural network of just one dense layer:\n", - "\n", - "![alt text](img/computation-graph-2.png \"Computation Graph\")\n", - "\n", - "This graph takes an input `x` and computes an output `out`. It does so how we learned in lecture today: `out = sigmoid(W*x+b)`.\n", - "\n", - "First, let's define this computation graph in TensorFlow via a simple function, as we did before:" - ] - }, - { - "metadata": { - "id": "ToJIeFqNcLAR", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# n_in: number of inputs\n", - "# n_out: number of outputs\n", - "def our_dense_layer(x, n_in, n_out):\n", - " # Define and initialize parameters, a weight matrix W and biases b\n", - " W = tf.Variable(tf.ones((n_in, n_out)))\n", - " b = tf.Variable(tf.zeros((1, n_out)))\n", - " \n", - " '''TODO: define the operation for z (hint: use tf.matmul)'''\n", - " z = # TODO\n", - " \n", - " '''TODO: define the operation for out (hint: use tf.sigmoid)'''\n", - " out = # TODO\n", - " return out" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "OgSBEuEtwb2e", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As before, we can define an example input, feed it into `our_dense_layer` function, and immediately execute:" - ] - }, - { - "metadata": { - "id": "PSI3I0CFcxnv", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: define an example input x_input'''\n", - "x_input = # TODO\n", - "'''TODO: call `our_dense_layer` to get the output of the network and print the result!'''\n", - "# our_dense_layer() # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "Jt1FgM7qYZ3D", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, instead of explicitly defining a simple function, we'll use the Keras API to define our neural network. This will be especially important as we move on to more complicated network architectures. \n", - "\n", - "Specifically, for this network we'll use the Keras [`Sequential`](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/Sequential) model from the `tf.keras` API to define our network. The `tf.keras.Sequential` model lets us conveniently define a linear stack of network layers. We'll use [`tf.keras.layers.Dense` ](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/layers/Dense) to define our single fully connected network layer. " - ] - }, - { - "metadata": { - "id": "7WXTpmoL6TDz", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Import relevant packages\n", - "from tensorflow.keras import Sequential\n", - "from tensorflow.keras.layers import Dense\n", - "\n", - "# Define the number of inputs and outputs\n", - "n_input_nodes = 2\n", - "n_output_nodes = 3\n", - "\n", - "# First define the model \n", - "model = Sequential()\n", - "\n", - "\n", - "'''TODO: Define a dense (fully connected) layer to compute z'''\n", - "# Remember: dense layers are defined by the parameters W and b!\n", - "# You can read more about the initialization of W and b in the TF documentation :) \n", - "dense_layer = # TODO\n", - "\n", - "# Add the dense layer to the model\n", - "model.add(dense_layer)\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HDGcwYfUyR-U", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "That's it! We've defined our model. Now, we can test it out using an example input:" - ] - }, - { - "metadata": { - "id": "sg23OczByRDb", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Test model with example input\n", - "x_input = tf.constant([[1,2.]], shape=(1,2))\n", - "\n", - "'''TODO: feed input into the model and predict the output!'''\n", - "# print # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "dQwDhKn8kbO2", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.3 Automatic differentiation\n", - "\n", - "[Automatic differentiation](https://en.wikipedia.org/wiki/Automatic_differentiation)\n", - "is one of the most important parts of TensorFlow and is the backbone of training with \n", - "[backpropagation](https://en.wikipedia.org/wiki/Backpropagation). During Eager execution, use `tf.GradientTape` to trace operations for computing gradients later. \n", - "\n", - "All forward-pass operations get recorded to a \"tape\"; then, to compute the gradient, the tape is played backwards and then discarded. A particular `tf.GradientTape` can only\n", - "compute one gradient; subsequent calls throw a runtime error.\n", - "\n", - "Let's take a look at a simple example! We can use automatic differentiation and stochastic gradient descent (SGD) to find the minimum of $y=(x-1)^2$. While we can clearly solve this problem analytically ($x_{min}=1$), solving this simple example sets us up nicely for future labs where we use gradient descent to optimize entire neural network losses. " - ] - }, - { - "metadata": { - "attributes": { - "classes": [ - "py" - ], - "id": "" - }, - "colab_type": "code", - "id": "7g1yWiSXqEf-", - "outputId": "cbcd5f61-570e-47c9-ab07-dc7ab4db2fa5", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 395 - } - }, - "cell_type": "code", - "source": [ - "x = tf.Variable([tf.random.normal([1])])\n", - "print \"Initializing x={}\".format(x.numpy())\n", - "learning_rate = 1e-2\n", - "history = []\n", - "\n", - "for i in range(500):\n", - " with tf.GradientTape() as tape:\n", - " y = (x - 1)**2 # record the forward pass on the tape\n", - "\n", - " grad = tape.gradient(y, x) # compute the gradient of y with respect to x\n", - " new_x = x - learning_rate*grad # sgd update\n", - " x.assign(new_x) # update the value of x\n", - " history.append(x.numpy()[0])\n", - "\n", - "plt.plot(history)\n", - "plt.plot([0, 500],[1,1])\n", - "plt.legend(('Predicted', 'True'))\n", - "plt.xlabel('Iteration')\n", - "plt.ylabel('x value')" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Initializing x=[[0.8079531]]\n" - ], - "name": "stdout" - }, - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "Text(0,0.5,'x value')" - ] - }, - "metadata": { - "tags": [] - }, - "execution_count": 50 - }, - { - "output_type": "display_data", - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfsAAAFYCAYAAABUA1WSAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAIABJREFUeJzt3Xl0VPX9//HnTCaThSSQgZkAYQ+r\nIFsRFQQEA18F61bFiIgIiopSbati44JWwaXqr4JrFU+tosYiVmoVUiq2KjEUQZYgAhFCCCGZyb6v\n9/dHYAQFApmZTDJ5Pc5R5s6d+5l33mJecz/3zr0mwzAMREREJGCZ/V2AiIiI+JbCXkREJMAp7EVE\nRAKcwl5ERCTAKexFREQCnMJeREQkwFn8XYAvOJ0lXh8zOjqcgoJyr4/blqiHnlMPPaceek499A5v\n99FujzzpOu3ZnyaLJcjfJbR66qHn1EPPqYeeUw+9ozn7qLAXEREJcAp7ERGRAKewFxERCXAKexER\nkQCnsBcREQlwCnsREZEAp7AXEREJcAp7ERGRAOfTsN+9ezfx8fG8/fbbP1u3YcMGrr76aq699lpe\nfPFF9/NLlizh2muvJSEhgW3btgGQnZ3NDTfcwIwZM7jrrruorq72ZdkiIiIBxWdhX15ezmOPPcb5\n559/wvWPP/44y5Yt49133+Wrr75i7969bNy4kYyMDJKSkli8eDGLFy8GYOnSpcyYMYN33nmHnj17\nsnLlSl+VLSIiEnB8dm18q9XKa6+9xmuvvfazdZmZmbRv354uXboAMGHCBFJSUsjPzyc+Ph6AuLg4\nioqKKC0tJTU1lUcffRSAiRMn8sYbbzBjxgxflf4zq/Z+zLavd1BXbzTbewaiILNJPfSQeug5j3po\nGPx0S+MUQxlH/32S15zwaaOR9cc8e6r3PpWTbnaa45nMJoxT9PDnXTpDp7l5a/4/ISQ4iHG9R3Fx\n7JRmeT+fhb3FYsFiOfHwTqcTm83mXrbZbGRmZlJQUMDgwYOPe97pdFJRUYHVagWgY8eOOJ3OU753\ndHS4V685HJ7V8N5BZpPXxmyr1EPPteYeGkf+ZWBgHM1A48fHxtEwPXbd0W2PrDgacMeO9eP6hjGO\nX3/cAMcsHxebx41x7PZHl1pzsEjLdaqb13hTi77rnXGCj60neu6nvH03potjp3DD8F/55G56bYnd\nHqkeeqi5emgYBtU19ZRX1VJeWUNldR2VNXVUVtVRWV1LVU1dw3PVDcuV1XVUHVmuqq6lsqaOmtp6\nqmvqqamto6au4bE/ZiWCzCZMJhNBZhNmMwSZzZhMYDaZMJtNR/48Zvnoc+7lhnVHxzm6vmEZ9/LR\nMTGBCRNmEw2PTSZMNPzZ8FzDa48+5/7TxJF/TvAcph/XHbvtcc/9uI4jYwAcfXB02WQ6/sOi6Sfr\njz5xqu0jIkIpLa08yetMx4378/cx/eT1p7v9T+r6ybg/X3Oi15xg3clXNfoCU2Nbn2S12WRiQPcO\ndIvt4NX/n0/1wcEvYe9wOHC5XO7lnJwcHA4HwcHBxz2fm5uL3W4nPDycyspKQkND3a8VkdNTU1tP\nSXk1JeU1FJdXU1xWTWlFDWWVDUFeXlnrfux+rqqW2rqmBbMJsAYHYQ02Y7WYCQsNpr2l4XGwxYw1\nOKjhT4uZYEuQ+/lj1wUHmQkKMmExH/kzyIwlyESQ+cifJ1o2//j80e2OBvSx9KHTc+ph6+OXsO/W\nrRulpaUcPHiQzp07s379ep555hkKCgpYtmwZCQkJpKWl4XA4iIiIYMyYMaxdu5bLL7+c5ORkxo0b\n54+yRVoMwzCoqKqjoLSKgpJKCoqrKCiporCsIcyLy6spKaumuLyGiqra0xozyGwiPNRCeGgwnTqE\nER5qoV1oMOEhFkKtQYRYgwi1Njw++k9I8E+fsxAcbG7YwxWRFsNnYb9jxw6eeuopsrKysFgsrF27\nlkmTJtGtWzcmT57MI488wu9+9zsApk6dSu/evenduzeDBw8mISEBk8nEokWLAFiwYAELFy4kKSmJ\nrl27csUVV/iqbJEWwTAMisuqcRZWkltYjrOwEldRBWWVdeTkl5FfUkVVdd1JtzeZIDLcSseoECLD\nI4lqZyUyPJiocCtR7axEhAXT7kiwN/xpISQ46Gd7wSISGEzG6RwEb2V8Mb2kaSvPqYc/V1JezSFX\nGdl55RzOL8dZWEFuYQXOwgqqa+pPuE1EWDDRkSE/+8cWGUqHiIYwbxcWrL3rk9DfQ8+ph97h7T62\nuGP2Im1NaUUNmTklHDwS7IdcZRxylVFaUfOz14Zag+gcHY69Qxj26DDsHcJwdAijU/tQ+vXpRHGh\nd09AFZHAp7AX8bLC0ioyDpdwIKeEjJxSMg6XkFdcedxrTIC9Qxh9Y9vTpVM4XTu2o3PHcBwdwogI\nCz7pdHpIsPe+UioibYfCXsQDtXX1HHSWsudgEelZRezNKiK/uOq410SGBzOkt40eMZF0c7RrCHZb\nOFYFt4g0E4W9yBmoqa3nh0NF7NxfwJ6DhfyQXXzcsfXI8GCG9+1Er86R9IiJpGfnSDpEWHXim4j4\nlcJe5BTqDYODuaXs3F/Azv357M4spLq2IdxNQFd7O/rFticutj19u7XH0SFMwS4iLY7CXuQnqmrq\n+G5/Ad/udbF1r4uish/vshjbqR2DekVzVi8b/bu1Jzw02I+VioicHoW9CA1ny2/e7eTbPS527s93\n771HhgczZkhnBve2MahnNB0iQvxcqYjImVPYS5tVUVXLt3tcpH6XQ9q+fPd127t0DGd4v06M6Gun\nT9cozK34xjMiIqCwlzamvt5g5/58vtiWzda9LvcefI+YCM4dFMPI/nZibOF+rlJExLsU9tIm5BdX\n8uW2bL7Ylu3+znuMLZxzBzk496wYunRs5+cKRUR8R2EvAcswDHbuL+BfmzLZ/kMehtFwUZrxw7ow\nbmhX+nSN0pnzItImKOwl4NTU1vF1Wg7JmzLJcpYB0KdrFOOHdeWcgQ7CQvTXXkTaFv3Wk4BRXlnD\nuk0H+WzzQYrLawgymzjvrBgmn9Od3l2i/F2eiIjfKOyl1SuvrCH5f5n8a9NBKqpqCQ+xcMl5Pbho\nZDdsUaH+Lk9ExO8U9tJq/TTkI8KCuWZiHBNHxBJq1V9tEZGj9BtRWp3auno+25zFP77aR1mlQl5E\npDH6zSithmEYfPO9k5Wfp5NbWEFYiIWrL4xj0kiFvIjIqeg3pLQKWc5S3kreze7MQoLMJuJ/0Y1f\nju1FZLjV36WJiLR4Cntp0apq6vjHV/tZu/EAdfUGw/t2YvqkvnTWVe5ERE6bwl5arG3pebyd/D2u\noko6RoVy/ZT+DO/byd9liYi0Ogp7aXEqqmp59997+HJbNkFmE5ec14PLxvQmxBrk79JERFolhb20\nKN9lFPDGP3eSV1xFD0cEcy89i+6OCH+XJSLSqinspUWoqa3nb5/vZd2mg5hNJn45phe/HNsLS5DZ\n36WJiLR6CnvxO2dhBS/9fQcZh0vobAvn5kvPok9XXd5WRMRbFPbiV1t2O3n9n99RUVXL2LM7M3PK\nAEKCdWxeRMSbFPbiF3X19fxtfTrJ/8vEajFz09SBjBva1d9liYgEJIW9NLvyyhpe/iiNtH35dLaF\nM/+KIXTTSXgiIj7j07BfsmQJW7duxWQykZiYyNChQ93r1q1bx8svv4zVamXatGnMnDmTv/3tb6xe\nvdr9mh07drBlyxZuuOEGysvLCQ9vuJDKwoULGTJkiC9LFx/JKShn6cptZOeVMzSuI7deNlj3lxcR\n8TGf/ZbduHEjGRkZJCUlkZ6eTmJiIklJSQDU19fz2GOP8eGHH9KhQwduueUW4uPjueaaa7jmmmvc\n23/66afu8Z544gn69+/vq3KlGWzb62TJm5soq6zl4tE9uPrCOMxmk7/LEhEJeD77XlNKSgrx8fEA\nxMXFUVRURGlpKQAFBQVERUVhs9kwm82cd955bNiw4bjtX3zxRebPn++r8qSZfb3zMA+/mkJldR03\nXTKQ6ZP6KuhFRJqJz8Le5XIRHR3tXrbZbDidTvfjsrIy9u/fT01NDampqbhcLvdrt23bRpcuXbDb\n7e7nli5dyvXXX8/DDz9MZWWlr8oWH/hs80FeW72TEGsQ9yQMZ9wwnYgnItKcmu1gqWEY7scmk4kn\nn3ySxMREIiMj6dat23GvXblyJVdeeaV7edasWQwYMIAePXqwaNEiVqxYwdy5c0/6XtHR4Vgs3v/6\nlt0e6fUxA5lhGCSt282K5N10iAzh0VvOp09se3+X1erp76Hn1EPPqYfe0Vx99FnYOxyO4/bWc3Nz\nj9tTHz16NO+88w4Azz77LLGxse51qampPPjgg+7lyZMnux9PmjSJTz755JTvXVBQ7nH9P2W3R+J0\nlnh93EBVbxgk/Xsv/9qUSaf2ofwuYTh9Yturhx7S30PPqYeeUw+9w9t9PNUHB59N448dO5a1a9cC\nkJaWhsPhICLix69X3XzzzeTl5VFeXs769es5//zzAcjJyaFdu3ZYrQ33KTcMg9mzZ1NcXAw0fBDo\n16+fr8oWLzAMgxXJu/nXpkxiO7Xj9zN/QUy0bkkrIuIvPtuzHzlyJIMHDyYhIQGTycSiRYtYtWoV\nkZGRTJ48menTpzNnzhxMJhPz5s3DZrMB4HQ63Y+hYcp/+vTpzJ49m7CwMGJiYliwYIGvyhYPGYbB\nO+v2sH5LFt3sEdw3YwQRYcH+LktEpE0zGcceTA8Qvphe0rRV4wzD4L0jU/ex9nbce90IosKt7vXq\noefUQ8+ph55TD70jIKbxpe1Z9d8f+NemTLp2ase9CccHvYiI+I/CXrziX5sy+WdKBo7oMO5NGE5U\nOwW9iEhLobAXj3298zDvrttD+3ZWfnftcNpHhPi7JBEROYbCXjyyY18eyz/+jrAQC7+9djj2DmH+\nLklERH5CYS9NluUs5aUPd2Aymfj1r86mu+5cJyLSIinspUmKy6t5fuU2KqvrmDttEAN6RDe+kYiI\n+IXCXs5YTW09L6zajquokssv6M25Z8X4uyQRETkFhb2cEcMw+OuaXew9WMToQQ4uG9vL3yWJiEgj\nFPZyRtZvyeKrHYfp3SWKOVMHYTLpNrUiIi2dwl5OW3pWEe+u20NEWDB3XDkEa7D37ywoIiLep7CX\n01JcXs1Lf99BvWFw2+WDsUWF+rskERE5TQp7aVR9vcGfV6dRUFLFleP6cFYvW+MbiYhIi6Gwl0Z9\n8nUGO/cXMCyuI1PP7+nvckRE5Awp7OWUfjhUzEdf7iM6MoS5l56FWSfkiYi0Ogp7OamKqlr+vDqN\n+nqDm6cN0n3pRURaKYW9nNQ763aTW1jBxef2YJCO04uItFoKezmhTbty+Wr7YXp2juTK8X38XY6I\niHhAYS8/U1xezVvJ3xNsMTPvl2dhCdJfExGR1ky/xeVn3l23h5LyGq4c14cuHdv5uxwREfGQwl6O\ns2W3k9SdOfTpGsWUc7r7uxwREfEChb24lVbU8Ne132MJMnHT1EGYzfqanYhIIFDYi9v7n+2lqKya\nyy/oTWwnTd+LiAQKhb0AsDuzkC+3Z9PdEcHF5/bwdzkiIuJFCnuhtq6et5K/B+CG/xtAkFl/LURE\nAol+qwv//uYgWc4yxg/rQt/Y9v4uR0REvExh38YVlFTx9y/3EREWzNUX9vV3OSIi4gMK+zbuvX/v\noaq6jqsvjNO170VEApTFl4MvWbKErVu3YjKZSExMZOjQoe5169at4+WXX8ZqtTJt2jRmzpxJamoq\nd911F/369QOgf//+PPTQQ2RnZ3PfffdRV1eH3W7nj3/8I1ar1Zeltwm7Mwv5365c+nSN4oKhXfxd\njoiI+IjPwn7jxo1kZGSQlJREeno6iYmJJCUlAVBfX89jjz3Ghx9+SIcOHbjllluIj48HYPTo0Sxd\nuvS4sZYuXcqMGTO45JJLeO6551i5ciUzZszwVeltQr1h8N6/9wBw3UX9dOtaEZEA5rNp/JSUFHeA\nx8XFUVRURGlpKQAFBQVERUVhs9kwm82cd955bNiw4aRjpaamctFFFwEwceJEUlJSfFV2m5G6M4f9\nh0sYPchBnE7KExEJaD4Le5fLRXR0tHvZZrPhdDrdj8vKyti/fz81NTWkpqbicrkA2Lt3L7fddhvX\nXXcdX331FQAVFRXuafuOHTu6x5Gmqa6p44P/pGMJMnP1hDh/lyMiIj7m02P2xzIMw/3YZDLx5JNP\nkpiYSGRkJN26dQOgV69e3HnnnVxyySVkZmYya9YskpOTTzrOyURHh2OxBHn3BwDs9kivj+kP76/b\nTX5xFb+a2JdB/RzN+t6B0kN/Ug89px56Tj30jubqo8/C3uFwuPfWAXJzc7Hb7e7l0aNH88477wDw\n7LPPEhsbS0xMDFOnTgWgR48edOrUiZycHMLDw6msrCQ0NJScnBwcjlMHVEFBudd/Hrs9EqezxOvj\nNreismre//duIsKCmTisa7P+TIHSQ39SDz2nHnpOPfQOb/fxVB8cfDaNP3bsWNauXQtAWloaDoeD\niIgI9/qbb76ZvLw8ysvLWb9+Peeffz6rV69m+fLlADidTvLy8oiJiWHMmDHusZKTkxk3bpyvyg54\nn6RkUFVdx+UX9CY8tNkmdkRExI989tt+5MiRDB48mISEBEwmE4sWLWLVqlVERkYyefJkpk+fzpw5\nczCZTMybNw+bzcakSZO45557+Pe//01NTQ2PPPIIVquVBQsWsHDhQpKSkujatStXXHGFr8oOaPnF\nlazfkkXHqFDGD+vq73JERKSZmIzTOQjeyvhieikQpq3+umYXn397iJsuGcg4P4R9IPTQ39RDz6mH\nnlMPvSMgpvGlZcktrOCLbdnERIcx5uzO/i5HRESakcK+jfjHl/uoqze4fFxv3dVORKSN0W/9NiA7\nr4wNaYeJtbdj9KAYf5cjIiLNTGHfBny8IQPDgCsu6KPL4oqItEEK+wCXW1hB6s4cYu3tGNG/k7/L\nERERP1DYB7g1qQeoNwymnddTe/UiIm2Uwj6AFZZW8eW2Q9g7hHLOoOa9LK6IiLQcCvsAlrwxk9o6\ng0vO66kz8EVE2jAlQIAqrahh/ZYsOkRYGTuki7/LERERP1LYB6h/f3OQqpo6Lh7dg2CL/jOLiLRl\nSoEAVFNbx2ebD9Iu1ML44boGvohIW6ewD0ApaTmUlNcwYXgsoVbd2U5EpK1T2AcYwzD416ZMgswm\nJo2M9Xc5IiLSAijsA8zOjAKynGWMGujAFhXq73JERKQFUNgHmH/9LxOAyaO6+7kSERFpKRT2ASQ7\nr4xt6Xn0jW1Pn65R/i5HRERaCIV9AFm36SAAk8/RXr2IiPxIYR8gyitr+WpHNh2jQhipG96IiMgx\nFPYBIiXtMNU19Vw4IlaXxhURkeMoFQKAYRh8/m0WQWYTFwzVRXREROR4CvsAsDeriCxnGSP722nf\nzurvckREpIVR2AeAz7ccAuDCEbqIjoiI/JzCvpUrrajhf7tyibGFM7BHB3+XIyIiLZDCvpX7ans2\ntXX1TBzeFZPJ5O9yRESkBVLYt2KGYfD5liwsQWbGnK171ouIyIkp7Fux3ZmF5BRUcM5AOxFhwf4u\nR0REWiiFfSv25fZsAMYP09ftRETk5Hx6s/MlS5awdetWTCYTiYmJDB061L1u3bp1vPzyy1itVqZN\nm8bMmTMBePrpp/nmm2+ora3l1ltvZcqUKdx///2kpaXRoUPDCWhz587lwgsv9GXpLV5ldS2bdjnp\n1D6Uft11Yp6IiJycz8J+48aNZGRkkJSURHp6OomJiSQlJQFQX1/PY489xocffkiHDh245ZZbiI+P\nZ//+/ezZs4ekpCQKCgq48sormTJlCgC//e1vmThxoq/KbXW++d5JVU0d/zekO2admCciIqfgs7BP\nSUkhPj4egLi4OIqKiigtLSUiIoKCggKioqKw2WwAnHfeeWzYsIHLL7/cvfcfFRVFRUUFdXV1viqx\nVfvqyBS+TswTEZHG+OyYvcvlIjo62r1ss9lwOp3ux2VlZezfv5+amhpSU1NxuVwEBQURHh4OwMqV\nKxk/fjxBQUEAvP3228yaNYvf/OY35Ofn+6rsVsFZWMGuA4UM6N4BR4cwf5cjIiItnE+P2R/LMAz3\nY5PJxJNPPkliYiKRkZF069btuNeuW7eOlStX8sYbbwBw+eWX06FDBwYNGsSf//xnXnjhBR5++OGT\nvld0dDgWS5DXfwa7PdLrYzbFuiNXzLt4TO8WU9Ppam31tkTqoefUQ8+ph97RXH30Wdg7HA5cLpd7\nOTc3F7vd7l4ePXo077zzDgDPPvsssbENl3r94osveOWVV3j99deJjGxowvnnn+/ebtKkSTzyyCOn\nfO+CgnJv/RhudnskTmeJ18c9U/WGQfLX+7EGm+nftWXUdLpaSg9bM/XQc+qh59RD7/B2H0/1wcFn\n0/hjx45l7dq1AKSlpeFwOIiIiHCvv/nmm8nLy6O8vJz169dz/vnnU1JSwtNPP82rr77qPvMeYMGC\nBWRmZgKQmppKv379fFV2i7cnsxBXUSWjBjgIC2m2iRkREWnFfJYWI0eOZPDgwSQkJGAymVi0aBGr\nVq0iMjKSyZMnM336dObMmYPJZGLevHnYbDb3Wfh33323e5ynnnqK66+/nrvvvpuwsDDCw8N54okn\nfFV2i/f1zhwAxgzp7OdKRESktTAZxx5MDxC+mF5qCdNWtXX1/GbZl1iCzDx7x1jM5tb1lbuW0MPW\nTj30nHroOfXQOwJiGl+8b+f+fMoqazlnoKPVBb2IiPiPwr4VSd2ZC8C5Z8X4uRIREWlNFPatRHVN\nHVv2NFwet0/XKH+XIyIirYjCvpXYlp5HZXUdowfF6L71IiJyRhT2rcTG7xrOwh89yOHnSkREpLVR\n2LcCFVW1bE3Po0vHcLo7IhrfQERE5BinFfa7d+9m3bp1ABQXF/u0IPm5b/e4qKmt51xN4YuISBM0\nelGdv/zlL3z88cdUV1cTHx/PSy+9RFRUFPPnz2+O+gT4366Gs/DP0RS+iIg0QaN79h9//DHvv/8+\n7du3B+C+++7j888/93VdckRFVS079uXTzd6OLh3b+bscERFphRoN+3bt2mE2//gys9l83LL41vYf\n8qitq2dkf3vjLxYRETmBRqfxe/TowQsvvEBxcTHJycl88sknxMXFNUdtAmze7QRQ2IuISJM1uov+\n8MMPExYWRkxMDKtXr2bYsGEsWrSoOWpr82pq69mWnken9qE6C19ERJqs0T37oKAgbrrpJm666abm\nqEeO8V1GPpXVdUwY3lVn4YuISJM1GvZnnXXWcUFjMpmIjIwkNTXVp4UJfPO9pvBFRMRzjYb9rl27\n3I+rq6tJSUnh+++/92lRAvX1Blv2uGjfzkpcbHt/lyMiIq3YGZ1Wb7VamTBhAl999ZWv6pEj9hws\npLSihhH9OmHWFL6IiHig0T37lStXHrd8+PBhcnJyfFaQNPjm6Fn4AzSFLyIinmk07L/55pvjliMi\nIvjTn/7ks4IEDMNgy24XYSEWBvaI9nc5IiLSyjUa9k888URz1CHHyHKWkVdcyehBDixBuoCRiIh4\n5qRhP2HChFN+3UuXzPWdrekuAIb17eTnSkREJBCcNOzfeeedk26kO9/51rb0PEwmOLtPR3+XIiIi\nAeCkYR8bG+t+vHfvXgoKCoCGr989/vjjfPrpp76vrg0qrahhb1YRcV3bExEW7O9yREQkADR6zP7x\nxx/nq6++wuVy0aNHDzIzM5kzZ05z1NYm7fghD8OAoXHaqxcREe9o9Oyv7du38+mnnzJw4EA++OAD\n3njjDSoqKpqjtjZpW3oeoLAXERHvaTTsrVYrADU1NRiGwZAhQ9i8ebPPC2uL6usNtv+QR3RkiG58\nIyIiXtPoNH7v3r1ZsWIFo0aN4qabbqJ3796UlJQ0R21tTvqhIsoqazlnoEM3vhEREa9pNOz/8Ic/\nUFhYSFRUFB9//DH5+fnceuutzVFbm7N179EpfH3lTkREvKfRsJ8+fTqXX34506ZN47LLLjujwZcs\nWcLWrVsxmUwkJiYydOhQ97p169bx8ssvY7VamTZtGjNnzjzpNtnZ2dx3333U1dVht9v54x//6D68\nEEi2pbuwBJkZ1FNXzRMREe9p9Jj9woUL2bdvH1deeSW33347a9asobq6utGBN27cSEZGBklJSSxe\nvJjFixe719XX1/PYY4/x2muvsWLFCtavX8/hw4dPus3SpUuZMWMG77zzDj179vzZ9foDQX5xJQed\nZQzqGU2INcjf5YiISABpNOx/8Ytf8OCDD/LZZ58xe/ZsvvjiC8aPH9/owCkpKcTHxwMQFxdHUVER\npaWlABQUFBAVFYXNZsNsNnPeeeexYcOGk26TmprKRRddBMDEiRNJSUlp8g/cUu3Ylw/AkD42P1ci\nIiKB5rQuvF5cXMyHH37I8uXL2bx5M9dee22j27hcLqKjf5yOttlsOJ1O9+OysjL2799PTU0Nqamp\nuFyuk25TUVHhnrbv2LGje5xAsnN/Q9gP7qWwFxER72r0mP3cuXPZs2cPkydP5rbbbmPkyJFNeiPD\nMNyPTSYTTz75JImJiURGRtKtW7dGtznVcz8VHR2OxeL9qXC7PdLrY0LDV+6+yyikU/tQhg6MCegz\n8X3Vw7ZEPfSceug59dA7mquPjYb9rFmzuOCCCwgKOrPwdDgcuFwu93Jubi52+4/3Zh89erT7+vvP\nPvsssbGxVFVVnXCb8PBwKisrCQ0NJScnB4fDccr3LigoP6NaT4fdHonT6ZuvHO4/XExJeTXDzu6C\ny1Xqk/doCXzZw7ZCPfSceug59dA7vN3HU31waHQaf8KECWcc9ABjx45l7dq1AKSlpeFwOIiI+PFC\nMTfffDN5eXmUl5ezfv16zj///JNuM2bMGPfzycnJjBs37ozracnSjhyvH9xbU/giIuJ9je7ZN9XI\nkSMZPHgwCQkJmEwmFi1axKpVq4iMjGTy5MlMnz6dOXPmYDKZmDdvHjabDZvN9rNtABYsWMDChQtJ\nSkqia9euXHHFFb4q2y927m+4ydCgXvrKnYiIeJ/JaOQgeHl5OeHh4cc9l5OTQ0xMjE8L84Qvppd8\nNW1VVVPHgj/9l66d2vHITaPewU3SAAAczklEQVS9Pn5Loqk/z6mHnlMPPaceekeLmsb/1a9+xaZN\nm9zLH330kfsCOOK53ZmF1NYZmsIXERGfaXQa/8UXX+QPf/gDAwYMIDs7m+DgYN57773mqK1NcB+v\n11fuRETERxrds+/Tpw+//vWv+fTTT9mzZw+//vWv6dhRt1/1lrT9+QRbzPTr1t7fpYiISIBqdM/+\noYceYv/+/bz99tsUFhbym9/8hsmTJ3P77bc3R30BrbC0iixnGUN62wj2wXUBRERE4DT27OPi4vjr\nX/9Kjx49GDp0KO+++677srfimaNXzTtLU/giIuJDje7Zz549+7jlkJAQ7r33Xl/V06bsOlAIoLvc\niYiIT53WtfHFN74/UEC7UAvdYyIaf7GIiEgTKez9JK+oEmdhJf27d8AcwNfCFxER/1PY+8n3mQ1X\nzRvQQ1P4IiLiWwp7Pzl6vH5gjw5+rkRERAKdwt5Pjh6v7+bQ8XoREfEthb0f6Hi9iIg0J4W9H+h4\nvYiINCeFvR/oeL2IiDQnhb0f6Hi9iIg0J4V9M9PxehERaW4K+2am4/UiItLcFPbN7Ojx+gHddbxe\nRESah8K+me05WERYSBDddbxeRESaicK+GRWXV5OTX06fru0xm3W8XkREmofCvhmlHywCoF9sez9X\nIiIibYnCvhntyWoI+77dFPYiItJ8FPbNaO/BIswmE326Rvm7FBERaUMU9s2kpraO/YeL6e6IINRq\n8Xc5IiLShijsm8n+wyXU1hmawhcRkWansG8me4+enKewFxGRZqawbyZ7joR9X52JLyIizcynB4+X\nLFnC1q1bMZlMJCYmMnToUPe6FStWsHr1asxmM0OGDOGBBx7g5ZdfZsOGDQDU19fjcrlYu3YtkyZN\nonPnzgQFBQHwzDPPEBMT48vSvcowDPZmFdExKgRbVKi/yxERkTbGZ2G/ceNGMjIySEpKIj09ncTE\nRJKSkgAoLS1l+fLlJCcnY7FYmDNnDt9++y233347t99+OwAffvgheXl57vFee+012rVr56tyfepw\nfjmlFTUM7t16PqCIiEjg8Nk0fkpKCvHx8QDExcVRVFREaWkpAMHBwQQHB1NeXk5tbS0VFRW0b//j\n9HZtbS3vvvsuM2fO9FV5zWqvpvBFRMSPfLZn73K5GDx4sHvZZrPhdDqJiIggJCSEO+64g/j4eEJC\nQpg2bRq9e/d2vzY5OZkLLriA0NAfp7wXLVpEVlYWv/jFL/jd736HqRXdHvboxXR0cp6IiPhDs33h\n2zAM9+PS0lJeffVV1qxZQ0REBDfeeCO7du1i4MCBAHzwwQc8+uij7tf/+te/Zty4cbRv35477riD\ntWvXcvHFF5/0vaKjw7FYgrz+M9jtkU3abv/hEsJCLAw/qwtBbfya+E3tofxIPfSceug59dA7mquP\nPgt7h8OBy+VyL+fm5mK32wFIT0+ne/fu2Gw2AEaNGsWOHTsYOHAg5eXlHD58mG7durm3veKKK9yP\nx48fz+7du08Z9gUF5d7+cbDbI3E6S854u7LKGg7mljKoZzT5eaVer6s1aWoP5UfqoefUQ8+ph97h\n7T6e6oODz47Zjx07lrVr1wKQlpaGw+EgIqLhtq6xsbGkp6dTWVkJwI4dO+jVqxcAu3btok+fPu5x\nSkpKmDt3LtXV1QD873//o1+/fr4q2+v2Zzf8h9QlckVExF98tmc/cuRIBg8eTEJCAiaTiUWLFrFq\n1SoiIyOZPHkyc+fOZdasWQQFBTFixAhGjRoFgNPpdO/xA0RGRjJ+/HiuvfZaQkJCOOuss065V9/S\n/JBdDECfLgp7ERHxD5Nx7MH0AOGL6aWmTrcsXbmNb/e6eO7OsXSICPF6Xa2Jpv48px56Tj30nHro\nHQExjS8NJyX+kF2MLSqkzQe9iIj4j8Leh/KKKykuq9YUvoiI+JXC3of2HTk5r7dOzhMRET9S2PvQ\nvkM6OU9ERPxPYe9DPxwqwmSCnp118QkREfEfhb2P1NXXsz+nhNhO7Qi1NtuFCkVERH5GYe8jWc4y\nqmvqdTEdERHxO4W9j+w7cjGd3jpeLyIifqaw95EfDinsRUSkZVDY+8i+7GKswWZi7e38XYqIiLRx\nCnsfqKyuJctVRq+YSILMarGIiPiXksgHDuSUYhjQS1P4IiLSAijsfSDjcMOV83rp+/UiItICKOx9\nICOnIex1MR0REWkJFPY+kJFTQkhwEDHR4f4uRURERGHvbVU1dRxyldEjJgKz2eTvckRERBT23nYw\nt+HkvJ4xmsIXEZGWQWHvZTpeLyIiLY3C3suOnomvPXsREWkpFPZelpFTQrDFTJdOOjlPRERaBoW9\nF9XU1pPlLKO7I0JXzhMRkRZDieRFWa5S6uoNTeGLiEiLorD3Ivfxep2cJyIiLYjC3osyckoBnZwn\nIiIti8LeizIOlxBkNum2tiIi0qIo7L2ktq6ezNxSutkjsASprSIi0nIolbwkO6+c2rp6enaO8Hcp\nIiIix7H4cvAlS5awdetWTCYTiYmJDB061L1uxYoVrF69GrPZzJAhQ3jggQdYtWoVzz//PD169ABg\nzJgx3H777ezatYtHHnkEgAEDBvDoo4/6suwm0cV0RESkpfJZ2G/cuJGMjAySkpJIT08nMTGRpKQk\nAEpLS1m+fDnJyclYLBbmzJnDt99+C8DUqVNZuHDhcWMtXrzY/WHhd7/7Hf/5z3+YMGGCr0pvkoPO\nhpPzuivsRUSkhfHZNH5KSgrx8fEAxMXFUVRURGlpQyAGBwcTHBxMeXk5tbW1VFRU0L59+xOOU11d\nTVZWlntWYOLEiaSkpPiq7CbLzG342WI76eQ8ERFpWXwW9i6Xi+joaPeyzWbD6XQCEBISwh133EF8\nfDwTJ05k2LBh9O7dG2iYEZg7dy433ngjO3fupKCggKioKPc4HTt2dI/TUhiGQWZuKY4OYYSF+PTI\niIiIyBlrtmQyDMP9uLS0lFdffZU1a9YQERHBjTfeyK5duxg2bBg2m40LL7yQLVu2sHDhQl5//fWT\njnMy0dHhWCxBXv8Z7PYTT9HnF1dSWlHD2X07nfQ10kD98Zx66Dn10HPqoXc0Vx99FvYOhwOXy+Ve\nzs3NxW63A5Cenk737t2x2WwAjBo1ih07dnD11VcTFxcHwIgRI8jPzyc6OprCwkL3ODk5OTgcjlO+\nd0FBubd/HOz2SJzOkhOu2/5DXsNrokJO+ho5dQ/l9KiHnlMPPaceeoe3+3iqDw4+m8YfO3Ysa9eu\nBSAtLQ2Hw0FERMPX0mJjY0lPT6eyshKAHTt20KtXL1577TU+/vhjAHbv3o3NZsNqtdKnTx82bdoE\nQHJyMuPGjfNV2U1y8Mjx+u4Ofe1ORERaHp/t2Y8cOZLBgweTkJCAyWRi0aJFrFq1isjISCZPnszc\nuXOZNWsWQUFBjBgxglGjRtGtWzfuvfde3nvvPWpra1m8eDEAiYmJPPzww9TX1zNs2DDGjBnjq7Kb\nJNOpsBcRkZbLZJzOQfBWxhfTS6eabnloeSquwkpe/O14zCaT1987UGjqz3PqoefUQ8+ph94RENP4\nbUVNbT2H88rpZm+noBcRkRZJYe+h7Lwy6uoNumkKX0REWiiFvYcydXKeiIi0cAp7Dx29TG43u8Je\nRERaJoW9h45+7U5hLyIiLZXC3kOZuaV0ah9KeKgukysiIi2Twt4DRWXVFJfXaK9eRERaNIW9B9xT\n+Do5T0REWjCFvQd0Jr6IiLQGCnsPZLpPztM97EVEpOVS2HvgkKsMS5CZmOhwf5ciIiJyUgr7Jqo3\nDLLzyujSMRyzWZfJFRGRlkth30Suokqqa+uJ7aQpfBERadkU9k10yFkGQBeFvYiItHAK+yY6lNcQ\n9tqzFxGRlk5h30RZToW9iIi0Dgr7Jjp6Jr69Q5i/SxERETklhX0T6Ex8ERFpTRT2TaAz8UVEpDVR\n2DfB0TPxuyrsRUSkFVDYN8HRM/EV9iIi0hoo7JtAZ+KLiEhrorBvgkOuMoItOhNfRERaB4X9GXKf\niW/TmfgiItI6KOzP0NEz8XW8XkREWguF/RnSmfgiItLaKOzPkK6JLyIirY3C/gxlac9eRERaGYsv\nB1+yZAlbt27FZDKRmJjI0KFD3etWrFjB6tWrMZvNDBkyhAceeIDa2loeeOABDhw4QF1dHffddx+j\nRo3ihhtuoLy8nPDwcAAWLlzIkCFDfFn6SelMfBERaW18FvYbN24kIyODpKQk0tPTSUxMJCkpCYDS\n0lKWL19OcnIyFouFOXPm8O2335Kenk5YWBjvvvsue/bs4fe//z0rV64E4IknnqB///6+Kve01BsG\n2flldNaZ+CIi0or4LOxTUlKIj48HIC4ujqKiIkpLS4mIiCA4OJjg4GD33npFRQXt27fnsssu49JL\nLwXAZrNRWFjoq/KapLCkiuqaejrbwv1dioiIeEF29iFmzUpgwICBAFRXV3P99TcyYcLEMxrngw+S\nKCwsZPz4C/nvfz9n7txbT/i6L7/8D+eeO4bg4OBGx/zhh70899zTvPDCn8+olhPxWdi7XC4GDx7s\nXrbZbDidTiIiIggJCeGOO+4gPj6ekJAQpk2bRu/evY/b/s0333QHP8DSpUspKCggLi6OxMREQkND\nT/re0dHhWCxBXv+ZKuoMAOK6R2O3R3p9/LZAffOceug59dBzgdLDqqp29OnTm6SkdwEoLCzkyiuv\n5NJLp5wyZ34qIiKUmpoQxowZxZgxo076ulWrkpgyZSLt2jWc93WqPhYUtMNqtXil1z49Zn8swzDc\nj0tLS3n11VdZs2YNERER3HjjjezatYuBAxs+Wa1YsYK0tDReeeUVAGbNmsWAAQPo0aMHixYtYsWK\nFcydO/ek71VQUO71+u32SHb9kAdAVGgQTmeJ198j0Nntkeqbh9RDz6mHngukHubnl1FbW3/MzxNE\nhw42Fi5MJDjYSnFxIX/4w5M8/fRiDh3Kora2lptvvo1f/OIcNm3ayNKlz2KzdaRjx0507RrL2rXr\nWbXqfR5//GnWrPknK1cmYTKZSEi4npqaGr799ltmz57D88+/zPr1n/Lhh3/HZDIzbtyFXHfdTHJz\nc3joofsJDg6mb9/+VFfXnnavT/WhwGdh73A4cLlc7uXc3FzsdjsA6enpdO/eHZvNBsCoUaPYsWMH\nAwcO5G9/+xufffYZL730knuaY/Lkye5xJk2axCeffOKrsk/pcF7Dh4guHXUmvoiIN73/2V7+tyvX\nq2OeM9DB9El9z2ib7OxDFBcXUV9fT1RUFAsXPsCaNf+kY8dO/P73D1NYWMhdd93Gm2++x6uvvsBD\nDz1Gv379ueeeX9O1a6x7nPLyMv7yl9d58813qa6uYfHiRTz55HO8/vorPPPMUpzOXNasWcNLLy0H\n4Pbb5zJxYjyrViVx0UVTmD79Ot5++y/s3bvbK73wWdiPHTuWZcuWkZCQQFpaGg6Hg4iICABiY2NJ\nT0+nsrKS0NBQduzYwYQJE8jMzOS9997j7bffJiQkBGiYEbjppptYunQpUVFRpKam0q9fP1+VfUrZ\n+Q1fu4ux6Ux8EZFAceBABnfeOQ8Aq9XKgw8+ykcfreKssxoORe/YsY2tW7ewbdu3AFRVVVFTU0N2\ndjb9+jWcOD58+EiqqqrcY+7fv48ePXoREhJKSEgoTz753HHv+d13aWRkZLBgQcOx/fLyMg4fPsT+\n/fuYOLHhfLcRI0bx9dcbvPIz+izsR44cyeDBg0lISMBkMrFo0SJWrVpFZGQkkydPZu7cucyaNYug\noCBGjBjBqFGjeO655ygsLGTevHnucZYvX8706dOZPXs2YWFhxMTEsGDBAl+VfUqH88uJjgwh1Nps\nRz9ERNqE6ZP6nvFeuLf06NHzZyfBffTRKiyWhtlliyWYWbPmMHnyxce9xmz+8VI1xx6qblgXhGHU\nn/Q9LZZgLrzwQhYsuPe451eseBOTyXxkzJNvf6Z8mlr33HPPcctHj8kDJCQkkJCQcNz63/72t/z2\nt7/92ThTp05l6tSpvinyNFVW1ZJfXMWgntF+rUNERJrXWWcN4csv/8PkyRdTUJDP+++/y6233kGn\nTnYOHNhP9+492bLlGwYPPtu9Tc+evThwIIPy8nKCgoJYuPA3/L//9yImk5m6ujoGDBjEa6+9yC23\nVBISEsLzzz/L7bffSY8ePdm1aycDBw5i8+ZNXvsZtIt6mrKcpQB07qiv3YmItCWTJsWzefP/uO22\nOdTV1TFnTsPs87x583nwwYV07twFhyPmuG3CwsKYO/c27r57PgDXXjsDk8nEiBEjmT9/LsuW/ZlZ\ns2Zxxx23YDabGT/+QkJCQrnmmut46KH7+e9/1xMX571D1ibjp3MPAcAXZ4l+d7CIP779DTPi+xE/\nqrvXx28LAukMXn9RDz2nHnpOPfQOb/fxVGfj69r4p+lgrvbsRUSkdVLYn6aso2Gvq+eJiEgro7A/\nTQdzS7FazNiiTv+KSiIiIi2Bwv401BsGWa5SYmzhmE26AY6IiLQuCvvTUFhSRVV1HV10vF5ERFoh\nhf1pyD5ymVwdrxcRkdZI37M/DYfzFfYiIoFo2bL/x/fff0d+fh6VlZV07RpLVFR7liz5o79L8yqF\n/WnIzmu4Jr5ugCMiElgWLPgNAJ988g9++CGdO++8288V+Yam8U/D0T173QBHRCTwbd68ifvuu5s7\n75zHrl3fMW3aRe51Dz54H5s3b6K8vIwHH7yPu+66nTvvnMfevXv8WHHjtGd/GrLzyunUPlQ3wBER\n8ZFVez9mS+52r445wnE2V/W9tEnbpqfv5d13V2G1Wk+4/v333+Xcc8fwy19ewb59P/D888/wpz+9\n5Em5PqX0akRVdR0FJVUM69fJ36WIiEgz6du330mDHmD79m0UFhawdu0nAFRVVTZXaU2isD8N7UIt\nDOtn93cZIiIB66q+lzZ5L9wXgoODT/h8bW3tkfUWfvObexkyZGhzltVkOmbfiBBrEP9vwQVcc1F/\nf5ciIiJ+YDKZqKyspLKykt27vwcabnv73/9+DsC+fT/w3ntv+7HCxmnP/jRYgvSZSESkrbriiquZ\nN+9GevXqw4ABgwC4+uprWbz4EebPv5n6+nruvvseP1d5arrF7WnSLR09px56Tj30nHroOfXQO3SL\nWxEREfEahb2IiEiAU9iLiIgEOIW9iIhIgFPYi4iIBDiFvYiISIBT2IuIiAQ4hb2IiEiAU9iLiIgE\nOIW9iIhIgAvIy+WKiIjIj7RnLyIiEuAU9iIiIgFOYS8iIhLgFPYiIiIBTmEvIiIS4BT2IiIiAc7i\n7wJauiVLlrB161ZMJhOJiYkMHTrU3yW1aLt372b+/PnMnj2bmTNnkp2dzX333UddXR12u50//vGP\nWK1WVq9ezZtvvonZbGb69Olcc801/i69xXj66af55ptvqK2t5dZbb+Xss89WD89ARUUF999/P3l5\neVRVVTF//nwGDhyoHjZBZWUll156KfPnz+f8889XD89Qamoqd911F/369QOgf//+3Hzzzf7poyEn\nlZqaasybN88wDMPYu3evMX36dD9X1LKVlZUZM2fONB588EHjrbfeMgzDMO6//37jk08+MQzDMJ59\n9lljxYoVRllZmTFlyhSjuLjYqKioMKZNm2YUFBT4s/QWIyUlxbj55psNwzCM/Px8Y8KECerhGfrn\nP/9p/PnPfzYMwzAOHjxoTJkyRT1soueee8646qqrjA8++EA9bIKvv/7aWLBgwXHP+auPmsY/hZSU\nFOLj4wGIi4ujqKiI0tJSP1fVclmtVl577TUcDof7udTUVC666CIAJk6cSEpKClu3buXss88mMjKS\n0NBQRo4cyebNm/1Vdotyzjnn8PzzzwMQFRVFRUWFeniGpk6dyi233AJAdnY2MTEx6mETpKens3fv\nXi688EJA/y97i7/6qLA/BZfLRXR0tHvZZrPhdDr9WFHLZrFYCA0NPe65iooKrFYrAB07dsTpdOJy\nubDZbO7XqK8/CgoKIjw8HICVK1cyfvx49bCJEhISuOeee0hMTFQPm+Cpp57i/vvvdy+rh02zd+9e\nbrvtNq677jq++uorv/VRx+zPgKErC3vkZP1TX39u3bp1rFy5kjfeeIMpU6a4n1cPT997773Hd999\nx7333ntcf9TDxv39739n+PDhdO/e/YTr1cPT06tXL+68804uueQSMjMzmTVrFnV1de71zdlHhf0p\nOBwOXC6Xezk3Nxe73e7Hilqf8PBwKisrCQ0NJScnB4fDccK+Dh8+3I9VtixffPEFr7zyCq+//jqR\nkZHq4RnasWMHHTt2pEuXLgwaNIi6ujratWunHp6Bzz//nMzMTD7//HMOHz6M1WrV38MmiImJYerU\nqQD06NGDTp06sX37dr/0UdP4pzB27FjWrl0LQFpaGg6Hg4iICD9X1bqMGTPG3cPk5GTGjRvHsGHD\n2L59O8XFxZSVlbF582ZGjRrl50pbhpKSEp5++mleffVVOnToAKiHZ2rTpk288cYbQMOhuPLycvXw\nDP3pT3/igw8+4P333+eaa65h/vz56mETrF69muXLlwPgdDrJy8vjqquu8ksfdde7RjzzzDNs2rQJ\nk8nEokWLGDhwoL9LarF27NjBU089RVZWFhaLhZiYGJ555hnuv/9+qqqq6Nq1K0888QTBwcGsWbOG\n5cuXYzKZmDlzJpdddpm/y28RkpKSWLZsGb1793Y/9+STT/Lggw+qh6epsrKSBx54gOzsbCorK7nz\nzjsZMmQICxcuVA+bYNmyZcTGxnLBBReoh2eotLSUe+65h+LiYmpqarjzzjsZNGiQX/qosBcREQlw\nmsYXEREJcAp7ERGRAKewFxERCXAKexERkQCnsBcREQlwCnsRYcCAAdTW1gLw0UcfeW3cf/zjH9TX\n1wNwww03HHf1MBFpPgp7EXGrq6vjpZde8tp4y5Ytc4f9W2+9RVBQkNfGFpHTp8vliohbYmIiWVlZ\nzJkzhzfeeINPPvmEt99+G8MwsNlsPP7440RHRzNy5Eiuvvpq6uvrSUxMZNGiRfzwww9UV1czbNgw\nHnzwQZYuXUpGRgazZ8/mhRde4NxzzyUtLY3q6moeeughDh8+TG1tLZdffjkzZsxg1apVbNiwgfr6\nevbt20dsbCzLli3DZDL5uy0irZ9Xb5grIq1S//79jZqaGiMzM9MYN26cYRiGcejQIeOXv/ylUVVV\nZRiGYfzlL38xnnjiCcMwDGPAgAHGl19+aRiGYeTn5xtvvfWWe6z/+7//M77//vvjxj328SuvvGI8\n8sgjhmEYRkVFhTFx4kTjwIEDxgcffGBMmjTJqKioMOrr642LLrrISEtLa54GiAQ47dmLyAlt2bIF\np9PJ3LlzAaiurqZbt25Aw125Ro4cCUBUVBTZ2dlce+21WK1WnE4nBQUFJx1369atXHXVVQCEhoYy\nZMgQ0tLSABg6dKj7NsldunShqKjIZz+fSFuisBeRE7JarQwdOpRXX331hOuDg4MB+Oc//8n27dtZ\nsWIFFovFHeQn89NpecMw3M/99Ji+oat5i3iFTtATETez2ew+K//ss89m27ZtOJ1OAD799FPWrVv3\ns23y8vLo3bs3FouFHTt2cODAAaqrq4GGYD863lHDhg3jiy++AKC8vJy0tDQGDx7syx9LpM1T2IuI\nm8PhoFOnTlx11VVERkbywAMPcOutt3L99dezcuXKE95j++KLL+bbb79l5syZJCcnM2fOHB5//HGK\niooYN24cv/rVrzhw4ID79TfccANlZWVcf/313HjjjcyfP999eEBEfEN3vRMREQlw2rMXEREJcAp7\nERGRAKewFxERCXAKexERkQCnsBcREQlwCnsREZEAp7AXEREJcAp7ERGRAPf/Afinh+aA0BYJAAAA\nAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "metadata": { - "collapsed": true, - "id": "UxBEH9__YZ3G", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.4 Control flow\n", - "\n", - "As you've seen, TensorFlow now an imperative programming style, and that's all because of Eager. \n", - "\n", - "As another example of the power of Eager, let's take a look at how we can build a dynamic model that uses Python flow control. Here's an example of the [Collatz conjecture](https://en.wikipedia.org/wiki/Collatz_conjecture) using TensorFlow’s arithmetic operations. Such dynamic behavior is not possible in past versions of TensorFlow (up to v1.4)!" - ] - }, - { - "metadata": { - "id": "LCfX4kfRYZ3W", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "a = tf.constant(12)\n", - "counter = 0\n", - "while not tf.equal(a, 1):\n", - " if tf.equal(a % 2, 0):\n", - " a = a / 2\n", - " else:\n", - " a = 3 * a + 1\n", - " print(a)" - ], - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/lab1/Part1_tensorflow_solution.ipynb b/lab1/Part1_tensorflow_solution.ipynb deleted file mode 100644 index 0407f9fb..00000000 --- a/lab1/Part1_tensorflow_solution.ipynb +++ /dev/null @@ -1,590 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Part1_tensorflow_solution.ipynb", - "version": "0.3.2", - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 2", - "language": "python", - "name": "python2" - } - }, - "cells": [ - { - "metadata": { - "id": "57knM8jrYZ2t", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "# Lab 1: Intro to TensorFlow and Music Generation with RNNs\n", - "# Part 1: Intro to TensorFlow" - ] - }, - { - "metadata": { - "id": "OhuYRQfjYZ2v", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 0.1 Install TensorFlow\n", - "\n", - "TensorFlow is a software library extensively used in machine learning. Here we'll learn how computations are represented and how to define a simple neural network in TensorFlow.\n", - "\n", - "Let's install TensorFlow and a couple of dependencies: \n" - ] - }, - { - "metadata": { - "id": "LkaimNJfYZ2w", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "3oWpEMtmYZ3I", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We'll then check to make sure things installed properly:" - ] - }, - { - "metadata": { - "id": "zLLaY8hvdbvQ", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "is_correct_tf_version = '1.14.' in tf.__version__\n", - "assert is_correct_tf_version, \"Wrong tensorflow version {} installed\".format(tf.__version__)\n", - "\n", - "is_eager_enabled = tf.executing_eagerly()\n", - "assert is_eager_enabled, \"Tensorflow eager mode is not enabled\"" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "vDJGsR2NoYtu", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "TensorFlow is set to release the next major version of TensorFlow, [TensorFlow 2.0](https://www.tensorflow.org/community/roadmap#tensorflow_20_is_coming), very soon. In this set of labs we'll be working in TensorFlow 1.14.0. The 6.S191 team is **Eager** to show you this version, as it features a (relatively) new imperative programming style called Eager execution. Under Eager execution, TensorFlow operations execute immediately as they're called from Python (which wasn't always the case!). This allows for fast debugging and a more intuitive way to get started with TensorFlow.\n", - "\n" - ] - }, - { - "metadata": { - "id": "iD3VO-LZYZ2z", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.1 The computation graph\n", - "\n", - "TensorFlow is called TensorFlow because it handles the flow (node/mathematical operation) of Tensors (data), which you can think of as multidimensional arrays. In TensorFlow, computations can be thought of as graphs. First, we'll explore defining a computational graph with Tensors and mathematical operations before diving in to how we can build deep learning models in TensorFlow. \n", - "\n", - "Let's look at a simple example, and define this computation using TensorFlow:\n", - "\n", - "![alt text](img/add-graph.png \"Computation Graph\")\n", - "\n", - "\n", - "\n" - ] - }, - { - "metadata": { - "id": "X_YJrZsxYZ2z", - "colab_type": "code", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - }, - "outputId": "3465850f-20ad-4a90-aec1-2c3e382bc0c0" - }, - "cell_type": "code", - "source": [ - "# Create the nodes in the graph, and initialize values\n", - "a = tf.constant(15, name=\"a\")\n", - "b = tf.constant(61, name=\"b\")\n", - "\n", - "# Add them!\n", - "c = tf.add(a,b, name=\"c\")\n", - "print(c)" - ], - "execution_count": 3, - "outputs": [ - { - "output_type": "stream", - "text": [ - "tf.Tensor(76, shape=(), dtype=int32)\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "id": "mjYCF0EdYZ22", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Notice how we've created a computation graph consisting of TensorFlow operations, and how the output is a Tensor with value 76 -- we've just created a computation graph consisting of operations, and it's executed them and given us back the result. That's because of Eager!" - ] - }, - { - "metadata": { - "id": "Mbfv_QOiYZ23", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Building a computation graph\n", - "\n", - "Now let's consider a slightly more complicated computation graph:\n", - "![alt text](img/computation-graph.png \"Computation Graph\")\n", - "\n", - "This graph takes two inputs, `a, b`, and computes an output `e`. Each node in the graph is an operation that takes some input, does some computation, and passes its output to another node.\n", - "\n", - "Let's define a simple function in TensorFlow to construct this computation graph:" - ] - }, - { - "metadata": { - "scrolled": true, - "id": "PJnfzpWyYZ23", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Construct a simple computation graph\n", - "def graph(a,b):\n", - " '''TODO: Define the operation for c, d, e (use tf.add, tf.subtract, tf.multiply).'''\n", - " c = tf.add(a, b)\n", - " d = tf.subtract(b, 1)\n", - " e = tf.multiply(c, d)\n", - " return e" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "AwrRfDMS2-oy", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, we can call this function to execute the computation graph given some inputs `a,b`:" - ] - }, - { - "metadata": { - "id": "pnwsf8w2uF7p", - "colab_type": "code", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - }, - "outputId": "23191b02-eef8-4d89-8b6f-f11d02a95a98" - }, - "cell_type": "code", - "source": [ - "# Consider example values for a,b\n", - "a, b = 1.5, 2.5\n", - "# Execute the computation\n", - "e_out = graph(a,b)\n", - "print e_out" - ], - "execution_count": 5, - "outputs": [ - { - "output_type": "stream", - "text": [ - "tf.Tensor(6.0, shape=(), dtype=float32)\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "id": "6HqgUIUhYZ29", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Again, notice how our output is a Tensor with value defined by the output of the computation (thanks to Eager!)." - ] - }, - { - "metadata": { - "id": "1h4o9Bb0YZ29", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.2 Neural networks in TensorFlow\n", - "We can also define neural networks in TensorFlow, and it's often helpful to think about this using the idea of computation graphs. TensorFlow uses a high-level API called [Keras](https://www.tensorflow.org/guide/keras) that provides a powerful, intuitive framework for building and training deep learning models. In the 6.S191 labs we'll be using the Keras API to build and train our models.\n", - "\n", - "Let's consider this example of a very simple neural network of just one dense layer:\n", - "\n", - "![alt text](img/computation-graph-2.png \"Computation Graph\")\n", - "\n", - "This graph takes an input `x` and computes an output `out`. It does so how we learned in lecture today: `out = sigmoid(W*x+b)`.\n", - "\n", - "First, let's define this computation graph in TensorFlow via a simple function, as we did before:" - ] - }, - { - "metadata": { - "id": "ToJIeFqNcLAR", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# n_in: number of inputs\n", - "# n_out: number of outputs\n", - "def our_dense_layer(x, n_in, n_out):\n", - " # Define and initialize parameters, a weight matrix W and biases b\n", - " W = tf.Variable(tf.ones((n_in, n_out)))\n", - " b = tf.Variable(tf.zeros((1, n_out)))\n", - " \n", - " '''TODO: define the operation for z (hint: use tf.matmul)'''\n", - " z = tf.matmul(x,W) + b\n", - " \n", - " '''TODO: define the operation for out (hint: use tf.sigmoid)'''\n", - " out = tf.sigmoid(z)\n", - " return out" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "OgSBEuEtwb2e", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As before, we can define an example input, feed it into `our_dense_layer` function, and immediately execute:" - ] - }, - { - "metadata": { - "id": "PSI3I0CFcxnv", - "colab_type": "code", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 105 - }, - "outputId": "13722bb9-083b-4289-b30c-76118951c20b" - }, - "cell_type": "code", - "source": [ - "'''TODO: define an example input x_input'''\n", - "x_input = tf.constant([[1,2.]], shape=(1,2))\n", - "'''TODO: call `our_dense_layer` to get the output of the network!'''\n", - "print our_dense_layer(x_input, n_in=2, n_out=3)" - ], - "execution_count": 7, - "outputs": [ - { - "output_type": "stream", - "text": [ - "WARNING:tensorflow:From /usr/local/lib/python2.7/dist-packages/tensorflow/python/ops/resource_variable_ops.py:642: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n", - "Instructions for updating:\n", - "Colocations handled automatically by placer.\n", - "tf.Tensor([[0.95257413 0.95257413 0.95257413]], shape=(1, 3), dtype=float32)\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "id": "Jt1FgM7qYZ3D", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, instead of explicitly defining a simple function, we'll use the Keras API to define our neural network. This will be especially important as we move on to more complicated network architectures. \n", - "\n", - "Specifically, for this network we'll use the Keras [`Sequential`](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/Sequential) model from the `tf.keras` API to define our network. The `tf.keras.Sequential` model lets us conveniently define a linear stack of network layers. We'll use [`tf.keras.layers.Dense` ](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/layers/Dense) to define our single fully connected network layer. " - ] - }, - { - "metadata": { - "id": "7WXTpmoL6TDz", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Import relevant packages\n", - "from tensorflow.keras import Sequential\n", - "from tensorflow.keras.layers import Dense\n", - "\n", - "# Define the number of inputs and outputs\n", - "n_input_nodes = 2\n", - "n_output_nodes = 3\n", - "\n", - "# First define the model \n", - "model = Sequential()\n", - "\n", - "\n", - "'''TODO: Define a dense (fully connected) layer to compute z'''\n", - "# Remember: dense layers are defined by the parameters W and b!\n", - "# You can read more about the initialization of W and b in the TF documentation :) \n", - "dense_layer = Dense(n_output_nodes, input_shape=(n_input_nodes,),activation='sigmoid')\n", - "\n", - "# Add the dense layer to the model\n", - "model.add(dense_layer)\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HDGcwYfUyR-U", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "That's it! We've defined our model. Now, we can test it out using an example input:" - ] - }, - { - "metadata": { - "id": "sg23OczByRDb", - "colab_type": "code", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - }, - "outputId": "f40aacac-fe8a-453c-dd40-deba8777a2ef" - }, - "cell_type": "code", - "source": [ - "# Test model with example input\n", - "x_input = tf.constant([[1,2.]], shape=(1,2))\n", - "\n", - "'''TODO: feed input into the model and predict the output!'''\n", - "print model(x_input)" - ], - "execution_count": 22, - "outputs": [ - { - "output_type": "stream", - "text": [ - "tf.Tensor([[0.31025296 0.48313126 0.7821198 ]], shape=(1, 3), dtype=float32)\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "id": "dQwDhKn8kbO2", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.3 Automatic differentiation\n", - "\n", - "[Automatic differentiation](https://en.wikipedia.org/wiki/Automatic_differentiation)\n", - "is one of the most important parts of TensorFlow and is the backbone of training with \n", - "[backpropagation](https://en.wikipedia.org/wiki/Backpropagation). During Eager execution, use `tf.GradientTape` to trace operations for computing gradients later. \n", - "\n", - "All forward-pass operations get recorded to a \"tape\"; then, to compute the gradient, the tape is played backwards and then discarded. A particular `tf.GradientTape` can only\n", - "compute one gradient; subsequent calls throw a runtime error.\n", - "\n", - "Let's take a look at a simple example! We can use automatic differentiation and stochastic gradient descent (SGD) to find the minimum of $y=(x-1)^2$. While we can clearly solve this problem analytically ($x_{min}=1$), solving this simple example sets us up nicely for future labs where we use gradient descent to optimize entire neural network losses. " - ] - }, - { - "metadata": { - "attributes": { - "classes": [ - "py" - ], - "id": "" - }, - "colab_type": "code", - "id": "7g1yWiSXqEf-", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 395 - }, - "outputId": "a1f9e6db-84e7-459a-bc4c-a8486f298f52" - }, - "cell_type": "code", - "source": [ - "x = tf.Variable([tf.random.normal([1])])\n", - "print \"Initializing x={}\".format(x.numpy())\n", - "learning_rate = 1e-2\n", - "history = []\n", - "\n", - "for i in range(500):\n", - " with tf.GradientTape() as tape:\n", - " y = (x - 1)**2 # record the forward pass on the tape\n", - "\n", - " grad = tape.gradient(y, x) # compute the gradient of y with respect to x\n", - " new_x = x - learning_rate*grad # sgd update\n", - " x.assign(new_x) # update the value of x\n", - " history.append(x.numpy()[0])\n", - "\n", - "plt.plot(history)\n", - "plt.plot([0, 500],[1,1])\n", - "plt.legend(('Predicted', 'True'))\n", - "plt.xlabel('Iteration')\n", - "plt.ylabel('x value')" - ], - "execution_count": 23, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Initializing x=[[1.5673906]]\n" - ], - "name": "stdout" - }, - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "Text(0,0.5,'x value')" - ] - }, - "metadata": { - "tags": [] - }, - "execution_count": 23 - }, - { - "output_type": "display_data", - "data": { - "image/png": "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\ndkFVVRUWLFiAwsJC1NTUYM6cOejfvz972A3V1dW49dZbMWfOHIwaNYo97IIDBw7g6aefRkxMDACg\nX79+eOSRR+TpoeRmDhw4IM2ePVuSJElKTU2Vpk2bJnNFzq2yslKaMWOGtGjRImnNmjWSJEnSggUL\npO+//16SJEl65513pHXr1kmVlZXS5MmTpbKyMqmqqkq65ZZbpOLiYjlLdxr79u2THnnkEUmSJKmo\nqEgaN24ce9hF27Ztkz755BNJkiQpMzNTmjx5MnvYTe+++640depUadOmTexhF+3fv1966qmnLnlN\nrh663WHzffv2YeLEiQCA6OholJaWoqKiQuaqnJdWq8WqVatgMplaXjtw4AAmTJgAABg/fjz27duH\no0ePYvDgwTAYDNDpdIiPj0diYqJcZTuVESNG4K9//SsAwMfHB1VVVexhF91888149NFHAQA5OTkI\nCgpiD7vh7NmzSE1NxY033giA/y/bg1w9dLvwLigogJ+fX8tzf39/mM1mGStybqIoQqfTXfJaVVUV\ntFotACAgIABmsxkFBQXw9/dvWYd9/Z1arYZerwcAbNy4EWPHjmUPu+mee+7Bc889h4ULF7KH3bBi\nxQosWLCg5Tl72HWpqal4/PHHce+992Lv3r2y9dAtx7wvJnF2WJu01T/29Uo7d+7Exo0bsXr1akye\nPLnldfaw89avX4+TJ0/iL3/5yyX9YQ879u2332LYsGHo3bt3q8vZw4716dMHc+fOxR/+8AdkZGTg\ngQceQENDQ8vynuyh24W3yWRCQUFBy/P8/HwYjUYZK1IevV6P6upq6HQ65OXlwWQytdrXYcOGyVil\nc9mzZw8++ugjfPrppzAYDOxhFyUnJyMgIAAhISEYMGAAGhoa4OXlxR52wa5du5CRkYFdu3YhNzcX\nWq2W/x12UVBQEG6++WYAQEREBAIDA5GUlCRLD93usPkNN9yAHTt2AACOHz8Ok8kEb29vmatSluuv\nv76lhz/++CPGjBmDoUOHIikpCWVlZaisrERiYiKuueYamSt1DuXl5XjzzTfx8ccfo1evXgDYw646\ndOgQVq9eDaBx6MtisbCHXfTee+9h06ZN2LBhA+6++27MmTOHPeyiLVu24LPPPgMAmM1mFBYWYurU\nqbL00C3vKvb222/j0KFDEAQBS5YsQf/+/eUuyWklJydjxYoVyMrKgiiKCAoKwttvv40FCxagpqYG\noaGheP3116HRaLB9+3Z89tlnEAQBM2bMwO233y53+U7hm2++wcqVKxEVFdXy2htvvIFFixaxh51U\nXV2Nl156CTk5OaiursbcuXMRFxeHF154gT3shpUrVyIsLAyjR49mD7ugoqICzz33HMrKylBXV4e5\nc+diwIABsvTQLcObiIhIydzusDkREZHSMbyJiIgUhuFNRESkMAxvIiIihWF4ExERKQzDm8gFxcbG\nor6+HgDw3Xff2W27//znP2G1WgEAM2fOvGR2KSLqOQxvIhfW0NCADz/80G7bW7lyZUt4r1mzBmq1\n2m7bJqLOc7vpUYncycKFC5GVlYWHHnoIq1evxvfff4+1a9dCkiT4+/tj+fLl8PPzQ3x8PP70pz/B\narVi4cKFWLJkCc6dO4fa2loMHToUixYtwvvvv48LFy5g1qxZ+OCDDzBy5EgcP34ctbW1WLx4MXJz\nc1FfX4877rgD9913HzZv3oxffvkFVqsVaWlpCAsLw8qVKyEIgtxtIVI+u95glIicQr9+/aS6ujop\nIyNDGjNmjCRJkpSdnS3ddtttUk1NjSRJkvTFF19Ir7/+uiRJkhQbGyv9/PPPkiQ13nO8+d7tkiRJ\nN910k3T69OlLtnvxnz/66CNp6dKlkiRJUlVVlTR+/HgpPT1d2rRpk5SQkCBVVVVJVqtVmjBhgnT8\n+PGeaQCRi+OeN5GbOHLkCMxmMx5++GEAQG1tLcLDwwE03vUoPj4eQOM9x3NycjB9+nRotVqYzWYU\nFxe3ud2jR49i6tSpAACdToe4uDgcP34cADBkyJCWW8qGhISgtLTUYb8fkTtheBO5Ca1WiyFDhuDj\njz9udblGowEAbNu2DUlJSVi3bh1EUWwJ5rZcfhhckqSW1y4fE5c4GzORXfCENSIXplKpWs46Hzx4\nMI4dOwaz2QwA+OGHH7Bz584r3lNYWIioqCiIoojk5GSkp6ejtrYWQGNQN2+v2dChQ7Fnzx4AgMVi\nwfHjxzFo0CBH/lpEbo/hTeTCTCYTAgMDMXXqVBgMBrz00kt47LHHcP/992Pjxo2t3mN4ypQp+O23\n3zBjxgz8+OOPeOihh7B8+XKUlpZizJgxuOuuu5Cent6y/syZM1FZWYn7778fDz74IObMmdNyOJ6I\nHIN3FSMiIlIY7nkTEREpDMObiIhIYRjeRERECsPwJiIiUhiGNxERkcIwvImIiBSG4U1ERKQwDG8i\nIiKF+f/svkvl+TFlsgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "metadata": { - "collapsed": true, - "id": "UxBEH9__YZ3G", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.4 Control flow\n", - "\n", - "As you've seen, TensorFlow now an imperative programming style, and that's all because of Eager. \n", - "\n", - "As another example of the power of Eager, let's take a look at how we can build a dynamic model that uses Python flow control. Here's an example of the [Collatz conjecture](https://en.wikipedia.org/wiki/Collatz_conjecture) using TensorFlow’s arithmetic operations. Such dynamic behavior is not possible in past versions of TensorFlow (up to v1.4)!" - ] - }, - { - "metadata": { - "id": "LCfX4kfRYZ3W", - "colab_type": "code", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 170 - }, - "outputId": "45cece74-ed18-44e5-e046-6449fcca38ca" - }, - "cell_type": "code", - "source": [ - "a = tf.constant(12)\n", - "counter = 0\n", - "while not tf.equal(a, 1):\n", - " if tf.equal(a % 2, 0):\n", - " a = a / 2\n", - " else:\n", - " a = 3 * a + 1\n", - " print(a)" - ], - "execution_count": 24, - "outputs": [ - { - "output_type": "stream", - "text": [ - "tf.Tensor(6, shape=(), dtype=int32)\n", - "tf.Tensor(3, shape=(), dtype=int32)\n", - "tf.Tensor(10, shape=(), dtype=int32)\n", - "tf.Tensor(5, shape=(), dtype=int32)\n", - "tf.Tensor(16, shape=(), dtype=int32)\n", - "tf.Tensor(8, shape=(), dtype=int32)\n", - "tf.Tensor(4, shape=(), dtype=int32)\n", - "tf.Tensor(2, shape=(), dtype=int32)\n", - "tf.Tensor(1, shape=(), dtype=int32)\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "id": "P-dYmvJPbtWa", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "" - ], - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/lab1/Part2_music_generation.ipynb b/lab1/Part2_music_generation.ipynb deleted file mode 100644 index b7ac8695..00000000 --- a/lab1/Part2_music_generation.ipynb +++ /dev/null @@ -1,1072 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Part2_music_generation.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "metadata": { - "id": "O-97SDET3JG-", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "\n", - "# Lab 1: Intro to TensorFlow and Music Generation with RNNs\n", - "\n", - "# Part 2: Music Generation with RNNs\n", - "\n", - "In this portion of the lab, we will explore building a Recurrent Neural Network (RNN) for music generation. We will train a model to learn the patterns in raw sheet music in [ABC notation](https://en.wikipedia.org/wiki/ABC_notation) and then use this model to generate new music. " - ] - }, - { - "metadata": { - "id": "oJ4aiwAq3j6X", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.1 Dependencies \n", - "First, let's download the course repository, install dependencies, and import the relevant packages we'll need for this lab." - ] - }, - { - "metadata": { - "id": "riVZCVK65QTH", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "! git clone https://github.com/aamini/introtodeeplearning_labs.git\n", - "% cd introtodeeplearning_labs\n", - "! git pull\n", - "% cd .." - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "FwnMeYBa4wmA", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf \n", - "tf.enable_eager_execution()\n", - "\n", - "import numpy as np\n", - "import os\n", - "import time\n", - "import functools\n", - "\n", - "import introtodeeplearning_labs as util\n", - "\n", - "is_correct_tf_version = '1.14.0' in tf.__version__\n", - "assert is_correct_tf_version, \"Wrong tensorflow version ({}) installed\".format(tf.__version__)\n", - "\n", - "is_eager_enabled = tf.executing_eagerly()\n", - "assert is_eager_enabled, \"Tensorflow eager mode is not enabled\"\n", - "\n", - "'''If this does not return true on Colaboratory, \n", - " go to runtime -> change runtime type -> GPU\n", - " or see a TA'''\n", - "assert tf.test.is_gpu_available()\n", - "\n", - "!apt-get install abcmidi timidity > /dev/null 2>&1" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "_ajvp0No4qDm", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.2 Dataset\n", - "\n", - "![Let's Dance!](http://33.media.tumblr.com/3d223954ad0a77f4e98a7b87136aa395/tumblr_nlct5lFVbF1qhu7oio1_500.gif)\n", - "\n", - "We've gathered a dataset of thousands of Irish folk songs, represented in the ABC notation. Let's download the dataset: " - ] - }, - { - "metadata": { - "id": "P7dFnP5q3Jve", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "path_to_file = tf.keras.utils.get_file('irish.abc', 'https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab1/data/irish.abc')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "UHjdCjDuSvX_" - }, - "cell_type": "markdown", - "source": [ - "### Inspect the dataset\n", - "\n", - "We can take a look and listen to get a better sense of the dataset:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "aavnuByVymwK", - "colab": {} - }, - "cell_type": "code", - "source": [ - "text = open(path_to_file).read()\n", - "# length of text is the number of characters in it\n", - "print ('Length of text: {} characters'.format(len(text)))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "Ww73Nh8xhzd0", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can grab a song from our dataset as an example and play it back: " - ] - }, - { - "metadata": { - "id": "VihurcAoadAQ", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "util.play_generated_song(text)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "Duhg9NrUymwO", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Take a look at the first 250 characters in text\n", - "print(text[:250])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "7vH24yyquwKQ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "One important thing to think about is that this notation of music does not simply contain information on the notes being played, but additionally there is meta information such as the song title, key, and tempo. How does the number of different characters are present in the text file impact the complexity of the learning problem? This will become important soon, when we generate a numerical representation for the text data." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "IlCgQBRVymwR", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# The unique characters in the file\n", - "vocab = sorted(set(text))\n", - "print ('{} unique characters'.format(len(vocab)))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "lwSjN0CMiJtX", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "rNnrKn_lL-IJ" - }, - "cell_type": "markdown", - "source": [ - "## 2.3 Process the dataset for the learning task\n", - "\n", - "Let's take a step back and consider our prediction task. We're trying to train a RNN model to learn patterns in ABC music, and then use this model to generate (i.e., predict) a new piece of music based on this learned information. \n", - "\n", - "Breaking this down, what we're really asking the model is: given a character, or a sequence of characters, what is the most probable next character? We'll train the model to perform this task. \n", - "\n", - "To achieve this, we will input a sequence of characters to the model, and train the model to predict the output, that is, the following character at each time step. RNNs maintain an internal state that depends on previously seen elements, so information about all characters seen up until a given moment will be taken into account in generating the prediction." - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "LFjSVAlWzf-N" - }, - "cell_type": "markdown", - "source": [ - "### Vectorize the text\n", - "\n", - "Before we begin training our RNN model, we'll need to create a numerical representation of our text-based dataset. To do this, we'll generate two lookup tables: one that maps characters to numbers, and a second that maps numbers back to characters. Recall that we just identified the unique characters present in the text." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "IalZLbvOzf-F", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Creating a mapping from unique characters to indices\n", - "char2idx = {u:i for i, u in enumerate(vocab)}\n", - "text_as_int = np.array([char2idx[c] for c in text])\n", - "\n", - "# Create a mapping from indices to characters\n", - "idx2char = np.array(vocab)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "tZfqhkYCymwX" - }, - "cell_type": "markdown", - "source": [ - "This gives us an integer representation for each character. Observe that the unique characters (i.e., our vocabulary) in the text are mapped as indices from 0 to `len(unique)`. Let's take a peek at this numerical representation of our dataset:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "FYyNlCNXymwY", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print('{')\n", - "for char,_ in zip(char2idx, range(20)):\n", - " print(' {:4s}: {:3d},'.format(repr(char), char2idx[char]))\n", - "print(' ...\\n}')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "IqxpSuZ1w-ub", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also look at how the first part of the text is mapped to an integer representation:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "l1VKcQHcymwb", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print ('{} ---- characters mapped to int ---- > {}'.format(repr(text[:13]), text_as_int[:13]))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "hgsVvVxnymwf" - }, - "cell_type": "markdown", - "source": [ - "### Create training examples and targets\n", - "\n", - "Our next step is to actually divide the text into example sequences that we'll use during training. Each input sequence that we feed into our RNN will contain `seq_length` characters from the text. We'll also need to define a target sequence for each input sequence, which will be used in training the RNN to predict the next character. For each input, the corresponding target will contain the same length of text, except shifted one character to the right.\n", - "\n", - "To do this, we'll break the text into chunks of `seq_length+1`. Suppose `seq_length` is 4 and our text is \"Hello\". Then, our input sequence is \"Hell\", and the target sequence \"ello\".\n", - "\n", - "First, use the `tf.data.Dataset.from_tensor_slices` function to convert the text vector into a stream of character indices. This is a function within `tf.data` which is generally useful for importing data.\n", - "\n", - "The batch method will then let us convert this stream of character indices to sequences of the desired size." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "0UHJDA39zf-O", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# The maximum length sentence we want for a single input in characters\n", - "seq_length = 100\n", - "examples_per_epoch = len(text)//seq_length\n", - "\n", - "# Create training examples / targets\n", - "# Note how we are using the `tf.data` module!\n", - "char_dataset = tf.data.Dataset.from_tensor_slices(text_as_int)\n", - "\n", - "'''TODO: use the batch function to generate sequences of the desired size.'''\n", - "'''Hint: youll want to set drop_remainder=True'''\n", - "sequences = # TODO\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "UbLcIPBj_mWZ" - }, - "cell_type": "markdown", - "source": [ - "Next, we need to define the input and target texts for each sequence. \n", - "\n", - "Define a function to do this, and then use the [`map`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset) method to apply a simple function to each batch. " - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "9NGu-FkO_kYU", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: define a function that takes a sequence (chunk) and outputs both the input text and target text sequences'''\n", - "'''Hint: consider the \"Hello\" example'''\n", - "def split_input_target(chunk):\n", - " input_text = # TODO\n", - " target_text = # TODO\n", - " return input_text, target_text\n", - "\n", - "'''TODO: use the map method to apply your function to the list of sequences to generate the dataset!'''\n", - "dataset = # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "_33OHL3b84i0" - }, - "cell_type": "markdown", - "source": [ - "For each of these vectors, each index is processed at a single time step. So, for the input at time step 0, the model receives the index for the first character in the sequence, and tries to predict the index of the next character. At the next timestep, it does the same thing, but the `RNN` considers the information from the previous step, i.e., its updated state, in addition to the current input.\n", - "\n", - "We can make this concrete by taking a look at how this works over the first several characters in our text:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "0eBu9WZG84i0", - "colab": {} - }, - "cell_type": "code", - "source": [ - "for input_example, target_example in dataset.take(1):\n", - " \n", - " for i, (input_idx, target_idx) in enumerate(zip(input_example[:5], target_example[:5])):\n", - " print(\"Step {:4d}\".format(i))\n", - " print(\" input: {} ({:s})\".format(input_idx, repr(idx2char[input_idx])))\n", - " print(\" expected output: {} ({:s})\".format(target_idx, repr(idx2char[target_idx])))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "MJdfPmdqzf-R" - }, - "cell_type": "markdown", - "source": [ - "### Create training batches\n", - "\n", - "Great! Now we have our text split into sequences of manageable size. But before we actually feed this data into our model, we'll [`shuffle`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#shuffle) the data (for the purpose of stochastic gradient descent) and then pack it into batches which will be used during training." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "p2pGotuNzf-S", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Batch size \n", - "BATCH_SIZE = 64\n", - "steps_per_epoch = examples_per_epoch//BATCH_SIZE\n", - "\n", - "# Buffer size is similar to a queue size\n", - "# This defines a manageable data size to put into memory, where elements are shuffled\n", - "BUFFER_SIZE = 10000\n", - "\n", - "dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)\n", - "\n", - "# Examine the dimensions of the dataset\n", - "dataset" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "r6oUuElIMgVx" - }, - "cell_type": "markdown", - "source": [ - "## 2.4 The Recurrent Neural Network (RNN) model" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "m8gPwEjRzf-Z" - }, - "cell_type": "markdown", - "source": [ - "Now we're ready to define and train a RNN model on our ABC music dataset, and then use that trained model to generate a new song. We'll train our RNN using batches of song snippets from our dataset, which we generated in the previous section.\n", - "\n", - "The model is based off the LSTM architecture, where we use a state vector to maintain information about the temporal relationships between consecutive characters. The final output of the LSTM is then fed into a fully connected [`Dense`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense) layer where we'll output a softmax over each character in the vocabulary, and then sample from this distribution to predict the next character. \n", - "\n", - "As we introduced in the first portion of this lab, we'll be using the Keras API, specifically, [`tf.keras.Sequential`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential), to define the model. Three layers are used to define the model:\n", - "\n", - "* [`tf.keras.layers.Embedding`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Embedding): This is the input layer, consisting of a trainable lookup table that maps the numbers of each character to a vector with `embedding_dim` dimensions.\n", - "* [`tf.keras.layers.LSTM`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/LSTM): Our LSTM network, with size `units=rnn_units`. \n", - "* [`tf.keras.layers.Dense`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense): The output layer, with `vocab_size` outputs.\n", - "\n", - "\n", - "\"Drawing\"/" - ] - }, - { - "metadata": { - "id": "rlaOqndqBmJo", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Define the RNN model\n", - "\n", - "Let's define some important dimensions:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "zHT8cLh7EAsg", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Length of the vocabulary in chars\n", - "vocab_size = len(vocab)\n", - "\n", - "# The embedding dimension \n", - "embedding_dim = 256\n", - "\n", - "# The number of RNN units\n", - "'''TODO: after running through the lab, try changing the number of units in the network to see how it affects performance'''\n", - "rnn_units = 1024" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "NNVB-jmMEOzP" - }, - "cell_type": "markdown", - "source": [ - "Now, we can define the function that will be used to actually build the model. \n", - "\n", - "If you'll be running your models on a GPU, you will want to use the [`CuDNNLSTM`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/CuDNNLSTM) function:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "DHsTugpJlLD6", - "colab": {} - }, - "cell_type": "code", - "source": [ - "if tf.test.is_gpu_available():\n", - " LSTM = tf.keras.layers.CuDNNLSTM\n", - "else:\n", - " LSTM = functools.partial(\n", - " tf.keras.layers.LSTM, recurrent_activation='sigmoid')\n", - "\n", - "LSTM = functools.partial(LSTM, \n", - " return_sequences=True, \n", - " recurrent_initializer='glorot_uniform',\n", - " stateful=True\n", - ")" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "IbWU4dMJmMvq", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "The time has come! Fill in the `TODOs` to define the RNN model within the `build_model` function, and then call the function you just defined to instantiate the model!" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "MtCrdfzEI2N0", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def build_model(vocab_size, embedding_dim, rnn_units, batch_size):\n", - " model = tf.keras.Sequential([\n", - " tf.keras.layers.Embedding(vocab_size, embedding_dim, \n", - " batch_input_shape=[batch_size, None]),\n", - " LSTM(''' TODO'''), # TODO: Define the dimensionality of the RNN\n", - " tf.keras.layers.Dense('''TODO''') # TODO: Define the dimensionality of the Dense layer\n", - " ])\n", - "\n", - " return model" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "wwsrpOik5zhv", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: call the build_model function to instantiate the RNN model'''\n", - "model = build_model('''TODO''')\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "-ubPo0_9Prjb" - }, - "cell_type": "markdown", - "source": [ - "### Test out the RNN model\n", - "\n", - "It's always a good idea to run a few simple checks on our model to see that it behaves as expected. \n", - "\n", - "First, we can use the `Model.summary` function to print out a summary of our model's internal workings. Here we can check the layers in the model, the shape of the output of each of the layers, the batch size, etc." - ] - }, - { - "metadata": { - "id": "RwG1DD6rDrRM", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model.summary()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "8xeDn5nZD0LX", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also quickly check the dimensionality of our output, using a sequence length of 100. Note that the model can be run on inputs of any length." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "C-_70kKAPrPU", - "colab": {} - }, - "cell_type": "code", - "source": [ - "for input_example_batch, target_example_batch in dataset.take(1): \n", - " example_batch_predictions = model(input_example_batch)\n", - " print(example_batch_predictions.shape, \"# (batch_size, sequence_length, vocab_size)\")" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mT1HvFVUGpoE", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Predictions from the untrained model\n", - "\n", - "Let's take a look at what our untrained model is predicting.\n", - "\n", - "To get actual predictions from the model, we sample from the output distribution, which is defined by a softmax over our character vocabulary. This will give us actual character indices.\n", - "\n", - "Note here that we sample from this probability distribution, as opposed to simply taking the argmax, which can cause the model to get stuck in a loop.\n", - "\n", - "Let's try this sampling out for the first example in the batch." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "4V4MfFg0RQJg", - "colab": {} - }, - "cell_type": "code", - "source": [ - "sampled_indices = tf.random.multinomial(example_batch_predictions[0], num_samples=1)\n", - "sampled_indices = tf.squeeze(sampled_indices,axis=-1).numpy()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "QM1Vbxs_URw5" - }, - "cell_type": "markdown", - "source": [ - "Note how we used a [multinomial distribution](http://onlinestatbook.com/lms/probability/multinomial.html) to sample over the example prediction. This gives a prediction of the next character (specifically its index) at each timestep:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "YqFMUQc_UFgM", - "colab": {} - }, - "cell_type": "code", - "source": [ - "sampled_indices" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "LfLtsP3mUhCG" - }, - "cell_type": "markdown", - "source": [ - "We can now decode these to see the text predicted by the untrained model:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "xWcFwPwLSo05", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print(\"Input: \\n\", repr(\"\".join(idx2char[input_example_batch[0]])))\n", - "print()\n", - "print(\"Next Char Predictions: \\n\", repr(\"\".join(idx2char[sampled_indices ])))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HEHHcRasIDm9", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As you can see, the text predicted by the untrained model is pretty nonsensical! How can we do better? Training!" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "LJL0Q0YPY6Ee" - }, - "cell_type": "markdown", - "source": [ - "### Training the model: loss and training operations\n", - "\n", - "Now it's time to train the model!\n", - "\n", - "At this point, we can think of our next character prediction problem as a standard classification problem. We have the previous state of the RNN as well as the input at a given time step, and want to predict the class of the next character, that is, actually predict the next character. \n", - "\n", - "So, to train our model on this classification task, we can use a form of the `crossentropy` loss (negative log likelihood loss). Specifically, we will use the [`sparse_categorical_crossentropy`](https://www.tensorflow.org/api_docs/python/tf/keras/backend/sparse_categorical_crossentropy) loss, as it utilizes integer targets for categorical classification tasks. We will want to compute the loss using the true targets and the predicted targets.\n", - "\n", - "Let's first compute the loss using our example predictions from the untrained model: " - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "4HrXTACTdzY-", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def compute_loss(labels, logits):\n", - " return tf.keras.backend.sparse_categorical_crossentropy(labels, logits, from_logits=True)\n", - "\n", - "'''TODO: compute the loss using the example batch and predictions from above'''\n", - "example_batch_loss = compute_loss('''TODO''')\n", - "print(\"Prediction shape: \", example_batch_predictions.shape, \" # (batch_size, sequence_length, vocab_size)\") \n", - "print(\"scalar_loss: \", example_batch_loss.numpy().mean())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "5cu11p1MKYZd", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now we are ready to define our training operation, i.e., our optimizer and duration of training, and actually train the model. Experiment with the choice of optimizer and the duration for which you train your models, and see how this affects the network's output. Some optimizers you may like to try are `AdamOptimizer`, `AdagradOptimizer`, and `MomentumOptimizer`.\n", - "\n", - "We will use the [`tf.GradientTape`](https://www.tensorflow.org/api_docs/python/tf/GradientTape) method to perform the backpropagation operations. \n", - "\n", - "We will also generate a print-out of the model's progress through training, which will help us easily visualize whether or not we are minimizing the loss!" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "d4tSNwymzf-q", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Training step\n", - "EPOCHS = 5 \n", - "'''TODO: experiment with different optimizers'''\n", - "'''How does changing this affect the network's performance?'''\n", - "optimizer = tf.train.AdamOptimizer() # TODO\n", - "checkpoint_dir = './training_checkpoints'\n", - "checkpoint_prefix = os.path.join(checkpoint_dir, \"ckpt_{epoch}\")\n", - "\n", - "history = []\n", - "plotter = util.PeriodicPlotter(sec=1, xlabel='Iterations', ylabel='Loss')\n", - "for epoch in range(EPOCHS):\n", - " start = time.time()\n", - "\n", - " # Initialize the hidden state at the start of every epoch; initially is None\n", - " hidden = model.reset_states()\n", - " \n", - " # Enumerate the dataset for use in training\n", - " custom_msg = util.custom_progress_text(\"Loss: %(loss)2.2f\")\n", - " bar = util.create_progress_bar(custom_msg)\n", - " for inp, target in bar(dataset):\n", - " # Use tf.GradientTape()\n", - " with tf.GradientTape() as tape:\n", - " '''TODO: feed the current input into the model and generate predictions'''\n", - " predictions = model('''TODO''') # TODO\n", - " '''TODO: compute the loss!'''\n", - " loss = # TODO\n", - " \n", - " # Now, compute the gradients and try to minimize\n", - " '''TODO: complete the function call for gradient computation'''\n", - " grads = tape.gradient('''TODO''') # TODO\n", - " optimizer.apply_gradients(zip(grads, model.trainable_variables))\n", - " \n", - " # Update the progress bar!\n", - " history.append(loss.numpy().mean())\n", - " custom_msg.update_mapping(loss=history[-1])\n", - " plotter.plot(history)\n", - " \n", - " # Update the model with the changed weights!\n", - " model.save_weights(checkpoint_prefix.format(epoch=epoch))\n", - "\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "kKkD5M6eoSiN" - }, - "cell_type": "markdown", - "source": [ - "## 2.5 Generate music using the RNN model\n", - "\n", - "Now, we can use our trained RNN model to generate some music! When generating music, we'll have to feed the model some sort of seed to get it started (because it can't predict anything without something to start with!).\n", - "\n", - "Once we have a generated seed, we can then iteratively predict each successive character (remember, we are using the ABC representation for our music) using our trained RNN. More specifically, recall that our RNN outputs a softmax over possible successive caharacters. For inference, we iteratively sample from these distributions, and then use our samples to encode a generated song in the ABC format.\n", - "\n", - "Then, all we have to do is write it to a file and listen!" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "JIPcXllKjkdr" - }, - "cell_type": "markdown", - "source": [ - "### Restore the latest checkpoint\n", - "\n", - "To keep this inference step simple, we will use a batch size of 1. Because of how the RNN state is passed from timestep to timestep, the model will only be able to accept a fixed batch size once it is built. \n", - "\n", - "To run the model with a different `batch_size`, we'll need to rebuild the model and restore the weights from the latest checkpoint, i.e., the weights after the last checkpoint during training:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "LycQ-ot_jjyu", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model = build_model(vocab_size, embedding_dim, rnn_units, batch_size=1)\n", - "\n", - "model.load_weights(tf.train.latest_checkpoint(checkpoint_dir))\n", - "\n", - "model.build(tf.TensorShape([1, None]))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "71xa6jnYVrAN", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model.summary()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "I9b4V2C8N62l", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Notice how now in our `model.summary` the first dimension of the output shape is 1. This is because we have fed in a fixed `batch_size` of 1." - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "DjGz1tDkzf-u" - }, - "cell_type": "markdown", - "source": [ - "### The prediction procedure\n", - "\n", - "Now, we're ready to write the code to generate text in the ABC music format:\n", - "\n", - "* Initialize a \"seed\" start string and the RNN state, and set the number of characters we want to generate.\n", - "\n", - "* Use the start string and the RNN state to obtain the probability distribution of the next predicted character.\n", - "\n", - "* Sample from multinomial distribution to calculate the index of the predicted character. This predicted character is then used as the next input to the model.\n", - "\n", - "* At each time step, the updated RNN state returned is fed back into the model, so that it now has more context. After predicting the next character, the updated RNN states are again fed back into the model, which is how it learns sequence dependencies in the data, as it gets more information from the previous predictions.\n", - "\n", - "![LSTM inference](https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab1/img/lstm_inference.png)\n", - "\n", - "Complete and experiment with this code block (as well as some of the aspects of network definition and training!), and see how the model performs. How do songs generated after training with a small number of epochs compare to those generated after a longer duration of training?" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "WvuwZBX5Ogfd", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def generate_text(model, start_string, generation_length=1000):\n", - " # Evaluation step (generating ABC text using the learned RNN model)\n", - "\n", - " '''TODO: convert the start string to numbers (vectorize)'''\n", - " input_eval = # TODO\n", - " input_eval = tf.expand_dims(input_eval, 0)\n", - "\n", - " # Empty string to store our results\n", - " text_generated = []\n", - "\n", - " # Here batch size == 1\n", - " model.reset_states()\n", - " bar = util.create_progress_bar()\n", - " for i in bar(range(generation_length)):\n", - " '''TODO: evaluate the inputs and generate the next character predictions'''\n", - " predictions = # TODO\n", - " \n", - " # Remove the batch dimension\n", - " predictions = tf.squeeze(predictions, 0)\n", - " \n", - " '''TODO: use a multinomial distribution to sample'''\n", - " predicted_id = tf.multinomial('''TODO''')[-1,0].numpy() # TODO \n", - " \n", - " # Pass the prediction along with the previous hidden state\n", - " # as the next inputs to the model\n", - " input_eval = tf.expand_dims([predicted_id], 0)\n", - " \n", - " '''TODO: add the predicted character to the string of generated text!'''\n", - " '''Hint: consider what format the prediction is in, vs. the output'''\n", - " text_generated.append('''TODO''') # TODO \n", - "\n", - " return (start_string + ''.join(text_generated))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "ktovv0RFhrkn", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Use the model to generate ABC format text!'''\n", - "# As you may notice, ABC files start with \"X\" - this may be a good start string\n", - "text = # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "AM2Uma_-yVIq" - }, - "cell_type": "markdown", - "source": [ - "### Play back the generated music!\n", - "\n", - "We can now call a function to convert the ABC format text to an audio file, and then play that back to check out our generated music! Try training longer if the resulting song is not long enough!" - ] - }, - { - "metadata": { - "id": "LrOtG64bfLto", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "util.play_generated_song(text)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "Ozx1TsxpirXm", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print(text)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HgVvcrYmSKGG", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.6 Experiment!\n", - "\n", - "Congrats on making your first sequence model in TensorFlow! It's a pretty big accomplishment, and hopefully you have some sweet tunes to show for it.\n", - "\n", - "If you want to go further, consider how you may improve your model and what seems to be most important in terms of performance. Here are some ideas to get you started:\n", - "\n", - "* How does the number of training epochs affect the performance?\n", - "* What if you alter or augment the dataset? \n", - "* Does the choice of start string significantly affect the result? \n", - "\n", - "Have fun and happy listening!\n", - "\n", - "\n", - "![Let's Dance!](http://33.media.tumblr.com/3d223954ad0a77f4e98a7b87136aa395/tumblr_nlct5lFVbF1qhu7oio1_500.gif)\n", - "\n", - "\n", - "\n" - ] - } - ] -} diff --git a/lab1/Part2_music_generation_solution.ipynb b/lab1/Part2_music_generation_solution.ipynb deleted file mode 100644 index 4b3ed3fe..00000000 --- a/lab1/Part2_music_generation_solution.ipynb +++ /dev/null @@ -1,1075 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Part2_music_generation_solution.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "metadata": { - "id": "O-97SDET3JG-", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "# Lab 1: Intro to TensorFlow and Music Generation with RNNs\n", - "\n", - "# Part 2: Music Generation with RNNs\n", - "\n", - "In this portion of the lab, we will explore building a Recurrent Neural Network (RNN) for music generation. We will train a model to learn the patterns in raw sheet music in [ABC notation](https://en.wikipedia.org/wiki/ABC_notation) and then use this model to generate new music. " - ] - }, - { - "metadata": { - "id": "oJ4aiwAq3j6X", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.1 Dependencies \n", - "First, let's download the course repository, install dependencies, and import the relevant packages we'll need for this lab." - ] - }, - { - "metadata": { - "id": "riVZCVK65QTH", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "! git clone https://github.com/aamini/introtodeeplearning_labs.git\n", - "% cd introtodeeplearning_labs\n", - "! git pull\n", - "% cd .." - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "FwnMeYBa4wmA", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf \n", - "tf.enable_eager_execution()\n", - "\n", - "import numpy as np\n", - "import os\n", - "import time\n", - "import functools\n", - "from IPython import display as ipythondisplay\n", - "\n", - "import introtodeeplearning_labs as util\n", - "\n", - "is_correct_tf_version = '1.14.0' in tf.__version__\n", - "assert is_correct_tf_version, \"Wrong tensorflow version ({}) installed\".format(tf.__version__)\n", - "\n", - "is_eager_enabled = tf.executing_eagerly()\n", - "assert is_eager_enabled, \"Tensorflow eager mode is not enabled\"\n", - "\n", - "'''If this does not return true on Colaboratory, \n", - " go to runtime -> change runtime type -> GPU\n", - " or see a TA'''\n", - "assert tf.test.is_gpu_available()\n", - "\n", - "!apt-get install abcmidi timidity > /dev/null 2>&1" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "_ajvp0No4qDm", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.2 Dataset\n", - "\n", - "![Let's Dance!](http://33.media.tumblr.com/3d223954ad0a77f4e98a7b87136aa395/tumblr_nlct5lFVbF1qhu7oio1_500.gif)\n", - "\n", - "We've gathered a dataset of thousands of Irish folk songs, represented in the ABC notation. Let's download the dataset: " - ] - }, - { - "metadata": { - "id": "P7dFnP5q3Jve", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "path_to_file = tf.keras.utils.get_file('irish.abc', 'https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab1/data/irish.abc')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "UHjdCjDuSvX_" - }, - "cell_type": "markdown", - "source": [ - "### Inspect the dataset\n", - "\n", - "We can take a look and listen to get a better sense of the dataset:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "aavnuByVymwK", - "colab": {} - }, - "cell_type": "code", - "source": [ - "text = open(path_to_file).read()\n", - "# length of text is the number of characters in it\n", - "print ('Length of text: {} characters'.format(len(text)))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "Ww73Nh8xhzd0", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can grab a song from our dataset as an example and play it back: " - ] - }, - { - "metadata": { - "id": "VihurcAoadAQ", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "util.play_generated_song(text)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "Duhg9NrUymwO", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Take a look at the first 250 characters in text\n", - "print(text[:250])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "7vH24yyquwKQ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "One important thing to think about is that this notation of music does not simply contain information on the notes being played, but additionally there is meta information such as the song title, key, and tempo. How does the number of different characters are present in the text file impact the complexity of the learning problem? This will become important soon, when we generate a numerical representation for the text data." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "IlCgQBRVymwR", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# The unique characters in the file\n", - "vocab = sorted(set(text))\n", - "print ('{} unique characters'.format(len(vocab)))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "lwSjN0CMiJtX", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "rNnrKn_lL-IJ" - }, - "cell_type": "markdown", - "source": [ - "## 2.3 Process the dataset for the learning task\n", - "\n", - "Let's take a step back and consider our prediction task. We're trying to train a RNN model to learn patterns in ABC music, and then use this model to generate (i.e., predict) a new piece of music based on this learned information. \n", - "\n", - "Breaking this down, what we're really asking the model is: given a character, or a sequence of characters, what is the most probable next character? We'll train the model to perform this task. \n", - "\n", - "To achieve this, we will input a sequence of characters to the model, and train the model to predict the output, that is, the following character at each time step. RNNs maintain an internal state that depends on previously seen elements, so information about all characters seen up until a given moment will be taken into account in generating the prediction." - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "LFjSVAlWzf-N" - }, - "cell_type": "markdown", - "source": [ - "### Vectorize the text\n", - "\n", - "Before we begin training our RNN model, we'll need to create a numerical representation of our text-based dataset. To do this, we'll generate two lookup tables: one that maps characters to numbers, and a second that maps numbers back to characters. Recall that we just identified the unique characters present in the text." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "IalZLbvOzf-F", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Creating a mapping from unique characters to indices\n", - "char2idx = {u:i for i, u in enumerate(vocab)}\n", - "text_as_int = np.array([char2idx[c] for c in text])\n", - "\n", - "'''TODO: Create a mapping from indices to characters'''\n", - "idx2char = np.array(vocab)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "tZfqhkYCymwX" - }, - "cell_type": "markdown", - "source": [ - "This gives us an integer representation for each character. Observe that the unique characters (i.e., our vocabulary) in the text are mapped as indices from 0 to `len(unique)`. Let's take a peek at this numerical representation of our dataset:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "FYyNlCNXymwY", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print('{')\n", - "for char,_ in zip(char2idx, range(20)):\n", - " print(' {:4s}: {:3d},'.format(repr(char), char2idx[char]))\n", - "print(' ...\\n}')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "IqxpSuZ1w-ub", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also look at how the first part of the text is mapped to an integer representation:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "l1VKcQHcymwb", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print ('{} ---- characters mapped to int ---- > {}'.format(repr(text[:13]), text_as_int[:13]))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "hgsVvVxnymwf" - }, - "cell_type": "markdown", - "source": [ - "### Create training examples and targets\n", - "\n", - "Our next step is to actually divide the text into example sequences that we'll use during training. Each input sequence that we feed into our RNN will contain `seq_length` characters from the text. We'll also need to define a target sequence for each input sequence, which will be used in training the RNN to predict the next character. For each input, the corresponding target will contain the same length of text, except shifted one character to the right.\n", - "\n", - "To do this, we'll break the text into chunks of `seq_length+1`. Suppose `seq_length` is 4 and our text is \"Hello\". Then, our input sequence is \"Hell\", and the target sequence \"ello\".\n", - "\n", - "First, use the `tf.data.Dataset.from_tensor_slices` function to convert the text vector into a stream of character indices. This is a function within `tf.data` which is generally useful for importing data.\n", - "\n", - "The batch method will then let us convert this stream of character indices to sequences of the desired size." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "0UHJDA39zf-O", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# The maximum length sentence we want for a single input in characters\n", - "seq_length = 100\n", - "examples_per_epoch = len(text)//seq_length\n", - "\n", - "# Create training examples / targets\n", - "# Note how we are using the `tf.data` module!\n", - "char_dataset = tf.data.Dataset.from_tensor_slices(text_as_int)\n", - "\n", - "'''TODO: use the batch function to generate sequences of the desired size'''\n", - "'''Hint: youll want to set drop_remainder=True'''\n", - "sequences = char_dataset.batch(seq_length+1, drop_remainder=True)\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "UbLcIPBj_mWZ" - }, - "cell_type": "markdown", - "source": [ - "Next, we need to define the input and target texts for each sequence. \n", - "\n", - "Define a function to do this, and then use the [`map`](http://book.pythontips.com/en/latest/map_filter.html) method to apply a simple function to each batch. " - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "9NGu-FkO_kYU", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: define a function that takes a sequence (chunk) and outputs both the input text and target text sequences'''\n", - "'''Hint: consider the \"Hello\" example'''\n", - "def split_input_target(chunk):\n", - " input_text = chunk[:-1]\n", - " target_text = chunk[1:]\n", - " return input_text, target_text\n", - "\n", - "'''TODO: use the map method to apply your function to the list of sequences to generate the dataset!'''\n", - "dataset = sequences.map(split_input_target)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "_33OHL3b84i0" - }, - "cell_type": "markdown", - "source": [ - "For each of these vectors, each index is processed at a single time step. So, for the input at time step 0, the model receives the index for the first character in the sequence, and tries to predict the index of the next character. At the next timestep, it does the same thing, but the `RNN` considers the information from the previous step, i.e., its updated state, in addition to the current input.\n", - "\n", - "We can make this concrete by taking a look at how this works over the first several characters in our text:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "0eBu9WZG84i0", - "colab": {} - }, - "cell_type": "code", - "source": [ - "for input_example, target_example in dataset.take(1):\n", - " \n", - " for i, (input_idx, target_idx) in enumerate(zip(input_example[:5], target_example[:5])):\n", - " print(\"Step {:4d}\".format(i))\n", - " print(\" input: {} ({:s})\".format(input_idx, repr(idx2char[input_idx])))\n", - " print(\" expected output: {} ({:s})\".format(target_idx, repr(idx2char[target_idx])))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "MJdfPmdqzf-R" - }, - "cell_type": "markdown", - "source": [ - "### Create training batches\n", - "\n", - "Great! Now we have our text split into sequences of manageable size. But before we actually feed this data into our model, we'll [`shuffle`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#shuffle) the data (for the purpose of stochastic gradient descent) and then pack it into batches which will be used during training." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "p2pGotuNzf-S", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Batch size \n", - "BATCH_SIZE = 64\n", - "steps_per_epoch = examples_per_epoch//BATCH_SIZE\n", - "\n", - "# Buffer size is similar to a queue size\n", - "# This defines a manageable data size to put into memory, where elements are shuffled\n", - "BUFFER_SIZE = 10000\n", - "\n", - "dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)\n", - "\n", - "# Examine the dimensions of the dataset\n", - "dataset" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "r6oUuElIMgVx" - }, - "cell_type": "markdown", - "source": [ - "## 2.4 The Recurrent Neural Network (RNN) model" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "m8gPwEjRzf-Z" - }, - "cell_type": "markdown", - "source": [ - "Now we're ready to define and train a RNN model on our ABC music dataset, and then use that trained model to generate a new song. We'll train our RNN using batches of song snippets from our dataset, which we generated in the previous section.\n", - "\n", - "The model is based off the LSTM architecture, where we use a state vector to maintain information about the temporal relationships between consecutive characters. The final output of the LSTM is then fed into a fully connected [`Dense`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense) layer where we'll output a softmax over each character in the vocabulary, and then sample from this distribution to predict the next character. \n", - "\n", - "As we introduced in the first portion of this lab, we'll be using the Keras API, specifically, [`tf.keras.Sequential`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential), to define the model. Three layers are used to define the model:\n", - "\n", - "* [`tf.keras.layers.Embedding`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Embedding): This is the input layer, consisting of a trainable lookup table that maps the numbers of each character to a vector with `embedding_dim` dimensions.\n", - "* [`tf.keras.layers.LSTM`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/LSTM): Our LSTM network, with size `units=rnn_units`. \n", - "* [`tf.keras.layers.Dense`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense): The output layer, with `vocab_size` outputs.\n", - "\n", - "\n", - "\"Drawing\"/" - ] - }, - { - "metadata": { - "id": "rlaOqndqBmJo", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Define the RNN model\n", - "\n", - "Let's define some important dimensions:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "zHT8cLh7EAsg", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Length of the vocabulary in chars\n", - "vocab_size = len(vocab)\n", - "\n", - "# The embedding dimension \n", - "embedding_dim = 256\n", - "\n", - "# The number of RNN units\n", - "'''TODO: after running through the lab, try changing the number of units in the network to see how it affects performance'''\n", - "rnn_units = 1024" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "NNVB-jmMEOzP" - }, - "cell_type": "markdown", - "source": [ - "Now, we can define the function that will be used to actually build the model. \n", - "\n", - "If you'll be running your models on a GPU, you will want to use the [`CuDNNLSTM`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/CuDNNLSTM) function:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "DHsTugpJlLD6", - "colab": {} - }, - "cell_type": "code", - "source": [ - "if tf.test.is_gpu_available():\n", - " LSTM = tf.keras.layers.CuDNNLSTM\n", - "else:\n", - " LSTM = functools.partial(\n", - " tf.keras.layers.LSTM, recurrent_activation='sigmoid')\n", - "\n", - "LSTM = functools.partial(LSTM, \n", - " return_sequences=True, \n", - " recurrent_initializer='glorot_uniform',\n", - " stateful=True\n", - ")" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "IbWU4dMJmMvq", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "The time has come! Fill in the `TODOs` to define the RNN model within the `build_model` function, and then call the function you just defined to instantiate the model!" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "MtCrdfzEI2N0", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def build_model(vocab_size, embedding_dim, rnn_units, batch_size):\n", - " model = tf.keras.Sequential([\n", - " tf.keras.layers.Embedding(vocab_size, embedding_dim, \n", - " batch_input_shape=[batch_size, None]),\n", - " LSTM(rnn_units), # TODO: Define the dimensionality of the RNN\n", - " tf.keras.layers.Dense(vocab_size) # TODO: Define the dimensionality of the Dense layer\n", - " ])\n", - "\n", - " return model" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "wwsrpOik5zhv", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: call the build_model function to instantiate the RNN model'''\n", - "model = build_model(\n", - " vocab_size = len(vocab), \n", - " embedding_dim=embedding_dim, \n", - " rnn_units=rnn_units, \n", - " batch_size=BATCH_SIZE)\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "-ubPo0_9Prjb" - }, - "cell_type": "markdown", - "source": [ - "### Test out the RNN model\n", - "\n", - "It's always a good idea to run a few simple checks on our model to see that it behaves as expected. \n", - "\n", - "First, we can use the `Model.summary` function to print out a summary of our model's internal workings. Here we can check the layers in the model, the shape of the output of each of the layers, the batch size, etc." - ] - }, - { - "metadata": { - "id": "RwG1DD6rDrRM", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model.summary()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "8xeDn5nZD0LX", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also quickly check the dimensionality of our output, using a sequence length of 100. Note that the model can be run on inputs of any length." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "C-_70kKAPrPU", - "colab": {} - }, - "cell_type": "code", - "source": [ - "for input_example_batch, target_example_batch in dataset.take(1): \n", - " example_batch_predictions = model(input_example_batch)\n", - " print(example_batch_predictions.shape, \"# (batch_size, sequence_length, vocab_size)\")" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mT1HvFVUGpoE", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Predictions from the untrained model\n", - "\n", - "Let's take a look at what our untrained model is predicting.\n", - "\n", - "To get actual predictions from the model, we sample from the output distribution, which is defined by a softmax over our character vocabulary. This will give us actual character indices.\n", - "\n", - "Note here that we sample from this probability distribution, as opposed to simply taking the argmax, which can cause the model to get stuck in a loop.\n", - "\n", - "Let's try this sampling out for the first example in the batch." - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "4V4MfFg0RQJg", - "colab": {} - }, - "cell_type": "code", - "source": [ - "sampled_indices = tf.random.multinomial(example_batch_predictions[0], num_samples=1)\n", - "sampled_indices = tf.squeeze(sampled_indices,axis=-1).numpy()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "QM1Vbxs_URw5" - }, - "cell_type": "markdown", - "source": [ - "Note how we used a [multinomial distribution](http://onlinestatbook.com/lms/probability/multinomial.html) to sample over the example prediction. This gives a prediction of the next character (specifically its index) at each timestep:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "YqFMUQc_UFgM", - "colab": {} - }, - "cell_type": "code", - "source": [ - "sampled_indices" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "LfLtsP3mUhCG" - }, - "cell_type": "markdown", - "source": [ - "We can now decode these to see the text predicted by the untrained model:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "xWcFwPwLSo05", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print(\"Input: \\n\", repr(\"\".join(idx2char[input_example_batch[0]])))\n", - "print()\n", - "print(\"Next Char Predictions: \\n\", repr(\"\".join(idx2char[sampled_indices ])))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HEHHcRasIDm9", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As you can see, the text predicted by the untrained model is pretty nonsensical! How can we do better? Training!" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "LJL0Q0YPY6Ee" - }, - "cell_type": "markdown", - "source": [ - "### Training the model: loss and training operations\n", - "\n", - "Now it's time to train the model!\n", - "\n", - "At this point, we can think of our next character prediction problem as a standard classification problem. We have the previous state of the RNN as well as the input at a given time step, and want to predict the class of the next character, that is, actually predict the next character. \n", - "\n", - "So, to train our model on this classification task, we can use a form of the `crossentropy` loss (negative log likelihood loss). Specifically, we will use the [`sparse_categorical_crossentropy`](https://www.tensorflow.org/api_docs/python/tf/keras/backend/sparse_categorical_crossentropy) loss, as it utilizes integer targets for categorical classification tasks. We will want to compute the loss using the true targets and the predicted targets.\n", - "\n", - "Let's first compute the loss using our example predictions from the untrained model: " - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "4HrXTACTdzY-", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def compute_loss(labels, logits):\n", - " return tf.keras.backend.sparse_categorical_crossentropy(labels, logits, from_logits=True)\n", - "\n", - "'''TODO: compute the loss using the example batch and predictions from above'''\n", - "example_batch_loss = compute_loss(target_example_batch, example_batch_predictions)\n", - "print(\"Prediction shape: \", example_batch_predictions.shape, \" # (batch_size, sequence_length, vocab_size)\") \n", - "print(\"scalar_loss: \", example_batch_loss.numpy().mean())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "5cu11p1MKYZd", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now we are ready to define our training operation, i.e., our optimizer and duration of training, and actually train the model. Experiment with the choice of optimizer and the duration for which you train your models, and see how this affects the network's output. Some optimizers you may like to try are `AdamOptimizer`, `AdagradOptimizer`, and `MomentumOptimizer`.\n", - "\n", - "We will use the [`tf.GradientTape`](https://www.tensorflow.org/api_docs/python/tf/GradientTape) method to perform the backpropagation operations. \n", - "\n", - "We will also generate a print-out of the model's progress through training, which will help us easily visualize whether or not we are minimizing the loss!" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "d4tSNwymzf-q", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Training step\n", - "EPOCHS = 5 \n", - "'''TODO: experiment with different optimizers'''\n", - "'''How does changing this affect the network's performance?'''\n", - "optimizer = tf.train.AdamOptimizer() # TODO\n", - "checkpoint_dir = './training_checkpoints'\n", - "checkpoint_prefix = os.path.join(checkpoint_dir, \"ckpt_{epoch}\")\n", - "\n", - "history = []\n", - "plotter = util.PeriodicPlotter(sec=1, xlabel='Iterations', ylabel='Loss')\n", - "for epoch in range(EPOCHS):\n", - "\n", - " # Initialize the hidden state at the start of every epoch; initially is None\n", - " hidden = model.reset_states()\n", - " \n", - " # Enumerate the dataset for use in training\n", - " custom_msg = util.custom_progress_text(\"Loss: %(loss)2.2f\")\n", - " bar = util.create_progress_bar(custom_msg)\n", - " for inp, target in bar(dataset):\n", - " # Use tf.GradientTape()\n", - " with tf.GradientTape() as tape:\n", - " '''TODO: feed the current input into the model and generate predictions'''\n", - " predictions = model(inp) # TODO\n", - " '''TODO: compute the loss!'''\n", - " loss = compute_loss(target, predictions) # TODO\n", - " \n", - " # Now, compute the gradients and try to minimize\n", - " '''TODO: complete the function call for gradient computation'''\n", - " grads = tape.gradient(loss, model.trainable_variables) # TODO\n", - " optimizer.apply_gradients(zip(grads, model.trainable_variables))\n", - " \n", - " # Update the progress bar!\n", - " history.append(loss.numpy().mean())\n", - " custom_msg.update_mapping(loss=history[-1])\n", - " plotter.plot(history)\n", - " \n", - " # Update the model with the changed weights!\n", - " model.save_weights(checkpoint_prefix.format(epoch=epoch))\n", - "\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "kKkD5M6eoSiN" - }, - "cell_type": "markdown", - "source": [ - "## 2.5 Generate music using the RNN model\n", - "\n", - "Now, we can use our trained RNN model to generate some music! When generating music, we'll have to feed the model some sort of seed to get it started (because it can't predict anything without something to start with!).\n", - "\n", - "Once we have a generated seed, we can then iteratively predict each successive character (remember, we are using the ABC representation for our music) using our trained RNN. More specifically, recall that our RNN outputs a softmax over possible successive caharacters. For inference, we iteratively sample from these distributions, and then use our samples to encode a generated song in the ABC format.\n", - "\n", - "Then, all we have to do is write it to a file and listen!" - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "JIPcXllKjkdr" - }, - "cell_type": "markdown", - "source": [ - "### Restore the latest checkpoint\n", - "\n", - "To keep this inference step simple, we will use a batch size of 1. Because of how the RNN state is passed from timestep to timestep, the model will only be able to accept a fixed batch size once it is built. \n", - "\n", - "To run the model with a different `batch_size`, we'll need to rebuild the model and restore the weights from the latest checkpoint, i.e., the weights after the last checkpoint during training:" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "LycQ-ot_jjyu", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model = build_model(vocab_size, embedding_dim, rnn_units, batch_size=1)\n", - "\n", - "model.load_weights(tf.train.latest_checkpoint(checkpoint_dir))\n", - "\n", - "model.build(tf.TensorShape([1, None]))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "71xa6jnYVrAN", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model.summary()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "I9b4V2C8N62l", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Notice how now in our `model.summary` the first dimension of the output shape is 1. This is because we have fed in a fixed `batch_size` of 1." - ] - }, - { - "metadata": { - "colab_type": "text", - "id": "DjGz1tDkzf-u" - }, - "cell_type": "markdown", - "source": [ - "### The prediction procedure\n", - "\n", - "Now, we're ready to write the code to generate text in the ABC music format:\n", - "\n", - "* Initialize a \"seed\" start string and the RNN state, and set the number of characters we want to generate.\n", - "\n", - "* Use the start string and the RNN state to obtain the probability distribution of the next predicted character.\n", - "\n", - "* Sample from multinomial distribution to calculate the index of the predicted character. This predicted character is then used as the next input to the model.\n", - "\n", - "* At each time step, the updated RNN state returned is fed back into the model, so that it now has more context. After predicting the next character, the updated RNN states are again fed back into the model, which is how it learns sequence dependencies in the data, as it gets more information from the previous predictions.\n", - "\n", - "![LSTM inference](https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab1/img/lstm_inference.png)\n", - "\n", - "Complete and experiment with this code block (as well as some of the aspects of network definition and training!), and see how the model performs. How do songs generated after training with a small number of epochs compare to those generated after a longer duration of training?" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "WvuwZBX5Ogfd", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def generate_text(model, start_string, generation_length=1000):\n", - " # Evaluation step (generating ABC text using the learned RNN model)\n", - "\n", - " '''TODO: convert the start string to numbers (vectorize)'''\n", - " input_eval = [char2idx[s] for s in start_string]\n", - " input_eval = tf.expand_dims(input_eval, 0)\n", - "\n", - " # Empty string to store our results\n", - " text_generated = []\n", - "\n", - " # Here batch size == 1\n", - " model.reset_states()\n", - " bar = util.create_progress_bar()\n", - " for i in bar(range(generation_length)):\n", - " '''TODO: evaluate the inputs and generate the next character predictions'''\n", - " predictions = model(input_eval) # TODO\n", - " \n", - " # Remove the batch dimension\n", - " predictions = tf.squeeze(predictions, 0)\n", - " \n", - " '''TODO: use a multinomial distribution to sample'''\n", - " predicted_id = tf.multinomial(predictions, num_samples=1)[-1,0].numpy() # TODO \n", - " \n", - " # Pass the prediction along with the previous hidden state\n", - " # as the next inputs to the model\n", - " input_eval = tf.expand_dims([predicted_id], 0)\n", - " \n", - " '''TODO: add the predicted character to the generated text!'''\n", - " # Hint: consider what format the prediction is in, vs. the output\n", - " text_generated.append(idx2char[predicted_id]) # TODO \n", - "\n", - " return (start_string + ''.join(text_generated))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "ktovv0RFhrkn", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Use the model to generate ABC format text!'''\n", - "# As you may notice, ABC files start with \"X\" - this may be a good start string\n", - "text = generate_text(model, start_string=\"X\")" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "text", - "id": "AM2Uma_-yVIq" - }, - "cell_type": "markdown", - "source": [ - "### Play back the generated music!\n", - "\n", - "We can now call a function to convert the ABC format text to an audio file, and then play that back to check out our generated music! Try training longer if the resulting song is not long enough!" - ] - }, - { - "metadata": { - "id": "LrOtG64bfLto", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "util.play_generated_song(text)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "Ozx1TsxpirXm", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print(text)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HgVvcrYmSKGG", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.6 Experiment!\n", - "\n", - "Congrats on making your first sequence model in TensorFlow! It's a pretty big accomplishment, and hopefully you have some sweet tunes to show for it.\n", - "\n", - "If you want to go further, consider how you may improve your model and what seems to be most important in terms of performance. Here are some ideas to get you started:\n", - "\n", - "* How does the number of training epochs affect the performance?\n", - "* What if you alter or augment the dataset? \n", - "* Does the choice of start string significantly affect the result? \n", - "\n", - "Have fun and happy listening!\n", - "\n", - "\n", - "![Let's Dance!](http://33.media.tumblr.com/3d223954ad0a77f4e98a7b87136aa395/tumblr_nlct5lFVbF1qhu7oio1_500.gif)\n", - "\n", - "\n", - "\n" - ] - } - ] -} diff --git a/lab2/Part1_mnist.ipynb b/lab2/Part1_mnist.ipynb deleted file mode 100644 index e7777a6a..00000000 --- a/lab2/Part1_mnist.ipynb +++ /dev/null @@ -1,788 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Part1_mnist_solutions.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "metadata": { - "id": "Xmf_JRJa_N8C", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "\n", - "# Laboratory 2: Computer Vision\n", - "\n", - "# Part 1: MNIST Digit Classification\n", - "\n", - "In the first portion of this lab, we will build and train a convolutional neural network (CNN) for classification of handwritten digits from the famous [MNIST](http://yann.lecun.com/exdb/mnist/) dataset. The MNIST dataset consists of 60,000 training images and 10,000 test images. Our classes are the digits 0-9.\n", - "\n", - "First we'll import TensorFlow, enable Eager execution, and also import some dependencies." - ] - }, - { - "metadata": { - "id": "RsGqx_ai_N8F", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import random\n", - "from progressbar import progressbar\n", - "\n", - "# Download the class repository\n", - "! git clone https://github.com/aamini/introtodeeplearning_labs.git > /dev/null 2>&1\n", - "% cd introtodeeplearning_labs \n", - "! git pull\n", - "% cd .. \n", - "\n", - "# Import the necessary class-specific utility files for this lab\n", - "import introtodeeplearning_labs as util" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HKjrdUtX_N8J", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.1 MNIST dataset \n", - "\n", - "Let's download and load the dataset and display a few random samples from it:" - ] - }, - { - "metadata": { - "id": "p2dQsHI3_N8K", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "mnist = tf.keras.datasets.mnist\n", - "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n", - "train_images = np.expand_dims(train_images, axis=-1)/255.\n", - "train_labels = np.int64(train_labels)\n", - "test_images = np.expand_dims(test_images, axis=-1)/255.\n", - "test_labels = np.int64(test_labels)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "5ZtUqOqePsRD", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Our training set is made up of 28x28 grayscale images of handwritten digits. \n", - "\n", - "Let's visualize what some of these images and their corresponding training labels look like." - ] - }, - { - "metadata": { - "scrolled": true, - "id": "bDBsR2lP_N8O", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "plt.figure(figsize=(10,10))\n", - "random_inds = np.random.choice(60000,36)\n", - "for i in range(36):\n", - " plt.subplot(6,6,i+1)\n", - " plt.xticks([])\n", - " plt.yticks([])\n", - " plt.grid(False)\n", - " image_ind = random_inds[i]\n", - " plt.imshow(np.squeeze(train_images[image_ind]), cmap=plt.cm.binary)\n", - " plt.xlabel(train_labels[image_ind])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "V6hd3Nt1_N8q", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.2 Neural Network for Handwritten Digit Classification\n", - "\n", - "We'll first build a simple neural network consisting of two fully connected layers and apply this to the digit classification task. Our network will ultimately output a probability distribution over the 10 digit classes (0-9). This first architecture we will be building is depicted below:\n", - "\n", - "![alt_text](img/mnist_2layers_arch.png \"CNN Architecture for MNIST Classification\")\n" - ] - }, - { - "metadata": { - "id": "rphS2rMIymyZ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Fully connected neural network architecture\n", - "To define the architecture of this first fully connected neural network, we'll once again use the Keras API and define the model using the [`Sequential`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential) class. Note how we first use a [`Flatten`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Flatten) layer, which flattens the input so that it can be fed into the model. \n", - "\n", - "In this next block, you'll define the output layer -- the second fully connected of this simple network." - ] - }, - { - "metadata": { - "id": "MMZsbjAkDKpU", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def build_fc_model():\n", - " fc_model = tf.keras.Sequential([\n", - " # First define a Flatten layer\n", - " tf.keras.layers.Flatten(),\n", - " # '''TODO: Define the activation function for the first fully connected layer.'''\n", - " tf.keras.layers.Dense(128, '''TODO'''), # TODO \n", - " # '''TODO: Define the second Dense layer to output the classification probabilities'''\n", - " tf.keras.layers.Dense('''TODO''', '''TODO''') # TODO \n", - " ])\n", - " return fc_model\n", - "\n", - "model = build_fc_model()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "VtGZpHVKz5Jt", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As we progress through this next portion, you may find that you'll want to make changes to the architecture defined above. **Note that in order to update the model later on, you'll need to re-run the above cell to re-initialize the model. **" - ] - }, - { - "metadata": { - "id": "mVN1_AeG_N9N", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's take a step back and think about the network we've just created. The first layer in this network, `tf.keras.layers.Flatten`, transforms the format of the images from a 2d-array (28 x 28 pixels), to a 1d-array of 28 * 28 = 784 pixels. You can think of this layer as unstacking rows of pixels in the image and lining them up. There are no learned parameters in this layer; it only reformats the data.\n", - "\n", - "After the pixels are flattened, the network consists of a sequence of two `tf.keras.layers.Dense` layers. These are fully-connected neural layers. The first `Dense` layer has 128 nodes (or neurons). The second (and last) layer (which you've defined!) should return an array of probability scores that sum to 1. Each node contains a score that indicates the probability that the current image belongs to one of the handwritten digit classes.\n", - "\n", - "That defines our fully connected model! " - ] - }, - { - "metadata": { - "id": "gut8A_7rCaW6", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - "\n", - "### Compile the model\n", - "\n", - "Before training the model, we need to define a few more settings. These are added during the model's [`compile`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#compile) step:\n", - "\n", - "* *Loss function* — This defines how we measure how accurate the model is during training. As was covered in lecture, during training we want to minimize this function, which will \"steer\" the model in the right direction.\n", - "* *Optimizer* — This defines how the model is updated based on the data it sees and its loss function.\n", - "* *Metrics* — Here we can define metrics used to monitor the training and testing steps. In this example, we'll look at the *accuracy*, the fraction of the images that are correctly classified.\n", - "\n", - "We'll start out by using a stochastic gradient descent (SGD) optimizer initialized with a learning rate of 0.1. Since we are performing a categorical classification task, we'll want to use the [cross entropy loss](https://www.tensorflow.org/api_docs/python/tf/keras/metrics/sparse_categorical_crossentropy).\n", - "\n", - "You'll want to experiment with both the choice of optimizer and learning rate and evaluate how these affect the accuracy of the trained model. " - ] - }, - { - "metadata": { - "id": "Lhan11blCaW7", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Experiment with different optimizers and learning rates. How do these affect\n", - " the accuracy of the trained model? Which optimizers and/or learning rates yield\n", - " the best performance?'''\n", - "model.compile(optimizer=tf.train.GradientDescentOptimizer(learning_rate=1e-1), \n", - " loss='sparse_categorical_crossentropy',\n", - " metrics=['accuracy'])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "qKF6uW-BCaW-", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Train the model\n", - "\n", - "We're now ready to train our model, which will involve feeding the training data (`train_images` and `train_labels`) into the model, and then asking it to learn the associations between images and labels. We'll also need to define the batch size and the number of epochs, or iterations over the MNIST dataset, to use during training. With the Keras API and defining the model settings in the `compile` step, training is all accomplished by calling the [`fit`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#fit) method on an instance of the Model class. \n" - ] - }, - { - "metadata": { - "id": "EFMbIqIvQ2X0", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Define the batch size and the number of epochs to use during training\n", - "BATCH_SIZE = 64\n", - "EPOCHS = 5" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "xvwvpA64CaW_", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model.fit(train_images, train_labels, batch_size=BATCH_SIZE, epochs=EPOCHS)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "W3ZVOhugCaXA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As the model trains, the loss and accuracy metrics are displayed. With five epochs and a learning rate of 0.01, this fully connected model should achieve an accuracy of approximatley 0.97 (or 97%) on the training data." - ] - }, - { - "metadata": { - "id": "oEw4bZgGCaXB", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Evaluate accuracy on the test dataset\n", - "\n", - "Now that we've trained the model, we can ask it to make predictions about a test set that it hasn't seen before. In this example, the `test_images` array comprises our test dataset. To evaluate accuracy, we can check to see if the model's predictions match the labels from the `test_labels` array. \n", - "\n", - "Use the [`evaluate`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#evaluate) method to evaluate the model on the test dataset!" - ] - }, - { - "metadata": { - "id": "VflXLEeECaXC", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Use the evaluate method to test the model!'''\n", - "test_loss, test_acc = # TODO\n", - "\n", - "print('Test accuracy:', test_acc)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "yWfgsmVXCaXG", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "You may observe that the accuracy on the test dataset is a little lower than the accuracy on the training dataset. This gap between training accuracy and test accuracy is an example of *overfitting*, when a machine learning model performs worse on new data than on its training data. \n", - "\n", - "What is the highest accuracy you can achieve with this first fully connected model? Since the handwritten digit classification task is pretty straightforward, you may be wondering how we can do better...\n", - "\n", - "![Deeper...](https://i.kym-cdn.com/photos/images/newsfeed/000/534/153/f87.jpg)" - ] - }, - { - "metadata": { - "id": "baIw9bDf8v6Z", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.3 Convolutional Neural Network (CNN) for handwritten digit classification" - ] - }, - { - "metadata": { - "id": "_J72Yt1o_fY7", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As we saw in lecture, convolutional neural networks (CNNs) are particularly well-suited for a variety of tasks in computer vision, and have achieved near-perfect accuracies on the MNIST dataset. We will now build a CNN composed of two convolutional layers and pooling layers, followed by two fully connected layers, and ultimately output a probability distribution over the 10 digit classes (0-9). The CNN we will be building is depicted below:\n", - "\n", - "![alt_text](img/convnet_fig.png \"CNN Architecture for MNIST Classification\")" - ] - }, - { - "metadata": { - "id": "EEHqzbJJAEoR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Define the CNN model\n", - "\n", - "We'll use the same training and test datasets as before, and proceed similarly as our fully connected network to define and train our new CNN model. \n", - "\n", - "You can use [`keras.layers.Conv2D` ](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D) to define convolutional layers and [`keras.layers.MaxPool2D`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/MaxPool2D) to define the pooling layers. Use the parameters shown in the network architecture above to define these layers and build the CNN model!" - ] - }, - { - "metadata": { - "id": "vec9qcJs-9W5", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def build_cnn_model():\n", - " cnn_model = tf.keras.Sequential([\n", - "\n", - " tf.keras.layers.Conv2D(filters=24, kernel_size=(3,3), input_shape=(28, 28, 1), activation=tf.nn.relu), # TODO \n", - "\n", - "\n", - " tf.keras.layers.MaxPool2D(pool_size=(2,2)), \n", - "\n", - " #'''TODO: Define the second convolutional layer'''\n", - " tf.keras.layers.Conv2D('''TODO'''), # TODO\n", - "\n", - " #'''TODO: Define the second max pooling layer'''\n", - " tf.keras.layers.MaxPool2D('''TODO'''), # TODO\n", - "\n", - " tf.keras.layers.Flatten(),\n", - " tf.keras.layers.Dense(128, activation=tf.nn.relu),\n", - " #'''TODO: Define the last Dense layer'''\n", - " tf.keras.layers.Dense('''TODO''') # TODO\n", - " ])\n", - " return cnn_model\n", - " \n", - "cnn_model = build_cnn_model()\n", - "print(cnn_model.summary())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "kUAXIBynCih2", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Train and test the CNN model\n", - "\n", - "Now, as before, we can define the loss function, optimizer, and metrics through the `compile` method. Compile the CNN model with an optimizer and learning rate of choice:" - ] - }, - { - "metadata": { - "id": "vheyanDkCg6a", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Define the compile operation with your optimizer and learning rate of choice.\n", - "We recommend beginning with the same optimizer and learning rate as the feed forward model'''\n", - "cnn_model.compile(optimizer='''TODO''', # TODO\n", - " loss='sparse_categorical_crossentropy',\n", - " metrics=['accuracy'])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "U19bpRddC7H_", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now we can train our model using the `fit` method via the Keras API:" - ] - }, - { - "metadata": { - "id": "YdrGZVmWDK4p", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Train the CNN model'''\n", - "cnn_model.fit('''TODO''') # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "pEszYWzgDeIc", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Great! Now that we've trained the model, let's evaluate it on the test dataset using the [`evaluate`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#evaluate) method:" - ] - }, - { - "metadata": { - "id": "JDm4znZcDtNl", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Use the evaluate method to test the model!'''\n", - "test_loss, test_acc = cnn_model.evaluate('''TODO''') # TODO\n", - "\n", - "print('Test accuracy:', test_acc)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "2rvEgK82Glv9", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "What is the highest accuracy you're able to achieve using the CNN model, and how does the accuracy of the CNN model compare to the accuracy of the simple fully connected network? What optimizers and learning rates seem to be optimal for training the CNN model? " - ] - }, - { - "metadata": { - "id": "xsoS7CPDCaXH", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Make predictions with the CNN model\n", - "\n", - "With the model trained, we can use it to make predictions about some images. We'll use the [`predict`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#predict) function call to generate the output predictions given a set of input samples.\n" - ] - }, - { - "metadata": { - "id": "Gl91RPhdCaXI", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "predictions = cnn_model.predict(test_images)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "x9Kk1voUCaXJ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "With this function call, the model has predicted the label for each image in the testing set. Let's take a look at the prediction for the first image in the test dataset:" - ] - }, - { - "metadata": { - "id": "3DmJEUinCaXK", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "predictions[0]" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "-hw1hgeSCaXN", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As you can see, a prediction is an array of 10 numbers. Recall that the output of our model is a probability distribution over the 10 digit classes. Thus, these numbers describe the model's \"confidence\" that the image corresponds to each of the 10 different digits. \n", - "\n", - "Let's look at the digit that has the highest confidence for the first image in the test dataset:" - ] - }, - { - "metadata": { - "id": "qsqenuPnCaXO", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: identify the digit with the highest confidence prediction for the first\n", - " image in the test dataset'''\n", - "digit = # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "E51yS7iCCaXO", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "So, the model is most confident that this image is a \"7\". We can check the test label (remember, this is the true identity of the digit) to see if this prediction is correct:" - ] - }, - { - "metadata": { - "id": "Sd7Pgsu6CaXP", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "test_labels[0]" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "ygh2yYC972ne", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "It is!\n", - "\n", - "We can define a couple of functions to help visualize the classification results on the MNIST dataset. First, we'll write a function, `plot_image`, to plot images along with their predicted label and the probability of the prediction. Second, we'll also define a function, `plot_value_array`, to plot the prediction probabilities for each of the digits. " - ] - }, - { - "metadata": { - "id": "DvYmmrpIy6Y1", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def plot_image(i, predictions_array, true_label, img):\n", - " predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]\n", - " plt.grid(False)\n", - " plt.xticks([])\n", - " plt.yticks([])\n", - " \n", - " plt.imshow(np.squeeze(img), cmap=plt.cm.binary)\n", - "\n", - " predicted_label = np.argmax(predictions_array)\n", - " if predicted_label == true_label:\n", - " color = 'blue'\n", - " else:\n", - " color = 'red'\n", - " \n", - " plt.xlabel(\"{} {:2.0f}% ({})\".format(predicted_label,\n", - " 100*np.max(predictions_array),\n", - " true_label),\n", - " color=color)\n", - "\n", - "def plot_value_array(i, predictions_array, true_label):\n", - " predictions_array, true_label = predictions_array[i], true_label[i]\n", - " plt.grid(False)\n", - " plt.xticks([])\n", - " plt.yticks([])\n", - " thisplot = plt.bar(range(10), predictions_array, color=\"#777777\")\n", - " plt.ylim([0, 1]) \n", - " predicted_label = np.argmax(predictions_array)\n", - " \n", - " thisplot[predicted_label].set_color('red')\n", - " thisplot[true_label].set_color('blue')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "d4Ov9OFDMmOD", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's use these functions to visualize the model's predictions for the images in the test dataset: " - ] - }, - { - "metadata": { - "id": "HV5jw-5HwSmO", - "colab_type": "code", - "cellView": "both", - "colab": {} - }, - "cell_type": "code", - "source": [ - "#@title Change the slider to look at the model's predictions! { run: \"auto\" }\n", - "\n", - "image_index = 8 #@param {type:\"slider\", min:0, max:100, step:1}\n", - "plt.subplot(1,2,1)\n", - "plot_image(image_index, predictions, test_labels, test_images)\n", - "plt.subplot(1,2,2)\n", - "plot_value_array(image_index, predictions, test_labels)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "kgdvGD52CaXR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also plot several images along with their predictions, where correct prediction labels are blue and incorrect prediction labels are red. The number gives the percent confidence (out of 100) for the predicted label. Note the model can be very confident in an incorrect prediction!" - ] - }, - { - "metadata": { - "id": "hQlnbqaw2Qu_", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Plot the first X test images, their predicted label, and the true label\n", - "# Color correct predictions in blue, incorrect predictions in red\n", - "num_rows = 5\n", - "num_cols = 4\n", - "num_images = num_rows*num_cols\n", - "plt.figure(figsize=(2*2*num_cols, 2*num_rows))\n", - "for i in range(num_images):\n", - " plt.subplot(num_rows, 2*num_cols, 2*i+1)\n", - " plot_image(i, predictions, test_labels, test_images)\n", - " plt.subplot(num_rows, 2*num_cols, 2*i+2)\n", - " plot_value_array(i, predictions, test_labels)\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "k-2glsRiMdqa", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.4 Training the model 2.0\n", - "\n", - "Earlier in the lab, we used the [`fit`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#fit) function call to train the model. This function is quite high-level and intuitive, which is really useful for simpler models. As you may be able to tell, this function abstracts away many details in the training call, and we have less control over training model, which could be useful in other contexts. \n", - "\n", - "As an alternative to this, we can use the [`tf.GradientTape`](https://www.tensorflow.org/api_docs/python/tf/GradientTape) class to record differentiation operations during training, and then call the [`tf.GradientTape.gradient`](https://www.tensorflow.org/api_docs/python/tf/GradientTape#gradient) function to actually compute the gradients. \n", - "\n", - "You may recall seeing this in Lab 1 Part 1, but let's take another look at this here.\n", - "\n", - "We'll use this framework to train our `cnn_model` using stochastic gradient descent." - ] - }, - { - "metadata": { - "id": "Wq34id-iN1Ml", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Rebuild the CNN model\n", - "cnn_model = build_cnn_model()\n", - "\n", - "batch_size = 12\n", - "loss_history = util.LossHistory(smoothing_factor=0.99) # to record the evolution of the loss\n", - "plotter = util.PeriodicPlotter(sec=2, xlabel='Iterations', ylabel='Loss', scale='semilogy')\n", - "optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-2) # define our optimizer\n", - "\n", - "bar = util.create_progress_bar()\n", - "for idx in bar(range(0, train_images.shape[0],batch_size)):\n", - " # First grab a batch of training data and convert the input images to tensors\n", - " (images, labels) = (train_images[idx:idx+batch_size], train_labels[idx:idx+batch_size])\n", - " images = tf.convert_to_tensor(images, dtype=tf.float32)\n", - "\n", - " # GradientTape to record differentiation operations\n", - " with tf.GradientTape() as tape:\n", - " logits = cnn_model(images) # feed the images into the model\n", - " loss_value = tf.keras.backend.sparse_categorical_crossentropy(labels, logits) # value of the loss\n", - "\n", - " loss_history.append(loss_value.numpy().mean()) # append the loss to the loss_history record\n", - " plotter.plot(loss_history.get())\n", - " # Backpropagation\n", - " grads = tape.gradient(loss_value, cnn_model.variables)\n", - " optimizer.apply_gradients(zip(grads, cnn_model.variables),\n", - " global_step=tf.train.get_or_create_global_step())\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "3cNtDhVaqEdR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.5 Conclusion\n", - "In this part of the lab, you had the chance to play with different MNIST classifiers with different architectures (fully-connected layers only, CNN), and experiment with how different hyperparameters affect accuracy (learning rate, etc.). The next part of the lab explores another application of CNNs, facial detection, and some drawbacks of AI systems in real world applications, like issues of bias. " - ] - } - ] -} \ No newline at end of file diff --git a/lab2/Part1_mnist_solution.ipynb b/lab2/Part1_mnist_solution.ipynb deleted file mode 100644 index 148197bd..00000000 --- a/lab2/Part1_mnist_solution.ipynb +++ /dev/null @@ -1,799 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Part1_mnist_solutions.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "metadata": { - "id": "Xmf_JRJa_N8C", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "\n", - "# Laboratory 2: Computer Vision\n", - "\n", - "# Part 1: MNIST Digit Classification\n", - "\n", - "In the first portion of this lab, we will build and train a convolutional neural network (CNN) for classification of handwritten digits from the famous [MNIST](http://yann.lecun.com/exdb/mnist/) dataset. The MNIST dataset consists of 60,000 training images and 10,000 test images. Our classes are the digits 0-9.\n", - "\n", - "First we'll import TensorFlow, enable Eager execution, and also import some dependencies." - ] - }, - { - "metadata": { - "id": "RsGqx_ai_N8F", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import random\n", - "from progressbar import progressbar\n", - "\n", - "# Download the class repository\n", - "! git clone https://github.com/aamini/introtodeeplearning_labs.git > /dev/null 2>&1\n", - "% cd introtodeeplearning_labs \n", - "! git pull\n", - "% cd .. \n", - "\n", - "# Import the necessary class-specific utility files for this lab\n", - "import introtodeeplearning_labs as util" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HKjrdUtX_N8J", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.1 MNIST dataset \n", - "\n", - "Let's download and load the dataset and display a few random samples from it:" - ] - }, - { - "metadata": { - "id": "p2dQsHI3_N8K", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "mnist = tf.keras.datasets.mnist\n", - "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n", - "train_images = np.expand_dims(train_images, axis=-1)/255.\n", - "train_labels = np.int64(train_labels)\n", - "test_images = np.expand_dims(test_images, axis=-1)/255.\n", - "test_labels = np.int64(test_labels)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "5ZtUqOqePsRD", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Our training set is made up of 28x28 grayscale images of handwritten digits. \n", - "\n", - "Let's visualize what some of these images and their corresponding training labels look like." - ] - }, - { - "metadata": { - "scrolled": true, - "id": "bDBsR2lP_N8O", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "plt.figure(figsize=(10,10))\n", - "random_inds = np.random.choice(60000,36)\n", - "for i in range(36):\n", - " plt.subplot(6,6,i+1)\n", - " plt.xticks([])\n", - " plt.yticks([])\n", - " plt.grid(False)\n", - " image_ind = random_inds[i]\n", - " plt.imshow(np.squeeze(train_images[image_ind]), cmap=plt.cm.binary)\n", - " plt.xlabel(train_labels[image_ind])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "V6hd3Nt1_N8q", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.2 Neural Network for Handwritten Digit Classification\n", - "\n", - "We'll first build a simple neural network consisting of two fully connected layers and apply this to the digit classification task. Our network will ultimately output a probability distribution over the 10 digit classes (0-9). This first architecture we will be building is depicted below:\n", - "\n", - "![alt_text](img/mnist_2layers_arch.png \"CNN Architecture for MNIST Classification\")\n" - ] - }, - { - "metadata": { - "id": "rphS2rMIymyZ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Fully connected neural network architecture\n", - "To define the architecture of this first fully connected neural network, we'll once again use the Keras API and define the model using the [`Sequential`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential) class. Note how we first use a [`Flatten`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Flatten) layer, which flattens the input so that it can be fed into the model. \n", - "\n", - "In this next block, you'll define the output layer -- the second fully connected of this simple network." - ] - }, - { - "metadata": { - "id": "MMZsbjAkDKpU", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def build_fc_model():\n", - " fc_model = tf.keras.Sequential([\n", - " # First define a Flatten layer\n", - " tf.keras.layers.Flatten(),\n", - " # '''TODO: Define the activation function for the first fully connected layer.'''\n", - " tf.keras.layers.Dense(128, activation=tf.nn.relu), # TODO (activation)\n", - " # '''TODO: Define the second Dense layer to output the classification probabilities'''\n", - " tf.keras.layers.Dense(10, activation=tf.nn.softmax) # TODO (both dimension and activation)\n", - " ])\n", - " return fc_model\n", - "\n", - "model = build_fc_model()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "VtGZpHVKz5Jt", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As we progress through this next portion, you may find that you'll want to make changes to the architecture defined above. **Note that in order to update the model later on, you'll need to re-run the above cell to re-initialize the model. **" - ] - }, - { - "metadata": { - "id": "mVN1_AeG_N9N", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's take a step back and think about the network we've just created. The first layer in this network, `tf.keras.layers.Flatten`, transforms the format of the images from a 2d-array (28 x 28 pixels), to a 1d-array of 28 * 28 = 784 pixels. You can think of this layer as unstacking rows of pixels in the image and lining them up. There are no learned parameters in this layer; it only reformats the data.\n", - "\n", - "After the pixels are flattened, the network consists of a sequence of two `tf.keras.layers.Dense` layers. These are fully-connected neural layers. The first `Dense` layer has 128 nodes (or neurons). The second (and last) layer (which you've defined!) should return an array of probability scores that sum to 1. Each node contains a score that indicates the probability that the current image belongs to one of the handwritten digit classes.\n", - "\n", - "That defines our fully connected model! " - ] - }, - { - "metadata": { - "id": "gut8A_7rCaW6", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - "\n", - "### Compile the model\n", - "\n", - "Before training the model, we need to define a few more settings. These are added during the model's [`compile`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#compile) step:\n", - "\n", - "* *Loss function* — This defines how we measure how accurate the model is during training. As was covered in lecture, during training we want to minimize this function, which will \"steer\" the model in the right direction.\n", - "* *Optimizer* — This defines how the model is updated based on the data it sees and its loss function.\n", - "* *Metrics* — Here we can define metrics used to monitor the training and testing steps. In this example, we'll look at the *accuracy*, the fraction of the images that are correctly classified.\n", - "\n", - "We'll start out by using a stochastic gradient descent (SGD) optimizer initialized with a learning rate of 0.1. Since we are performing a categorical classification task, we'll want to use the [cross entropy loss](https://www.tensorflow.org/api_docs/python/tf/keras/metrics/sparse_categorical_crossentropy).\n", - "\n", - "You'll want to experiment with both the choice of optimizer and learning rate and evaluate how these affect the accuracy of the trained model. " - ] - }, - { - "metadata": { - "id": "Lhan11blCaW7", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Experiment with different optimizers and learning rates. How do these affect\n", - " the accuracy of the trained model? Which optimizers and/or learning rates yield\n", - " the best performance?'''\n", - "model.compile(optimizer=tf.train.GradientDescentOptimizer(learning_rate=1e-1), \n", - " loss='sparse_categorical_crossentropy',\n", - " metrics=['accuracy'])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "qKF6uW-BCaW-", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Train the model\n", - "\n", - "We're now ready to train our model, which will involve feeding the training data (`train_images` and `train_labels`) into the model, and then asking it to learn the associations between images and labels. We'll also need to define the batch size and the number of epochs, or iterations over the MNIST dataset, to use during training. With the Keras API and defining the model settings in the `compile` step, training is all accomplished by calling the [`fit`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#fit) method on an instance of the Model class. \n" - ] - }, - { - "metadata": { - "id": "EFMbIqIvQ2X0", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Define the batch size and the number of epochs to use during training\n", - "BATCH_SIZE = 64\n", - "EPOCHS = 5" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "xvwvpA64CaW_", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "model.fit(train_images, train_labels, batch_size=BATCH_SIZE, epochs=EPOCHS)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "W3ZVOhugCaXA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As the model trains, the loss and accuracy metrics are displayed. With five epochs and a learning rate of 0.01, this fully connected model should achieve an accuracy of approximatley 0.97 (or 97%) on the training data." - ] - }, - { - "metadata": { - "id": "oEw4bZgGCaXB", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Evaluate accuracy on the test dataset\n", - "\n", - "Now that we've trained the model, we can ask it to make predictions about a test set that it hasn't seen before. In this example, the `test_images` array comprises our test dataset. To evaluate accuracy, we can check to see if the model's predictions match the labels from the `test_labels` array. \n", - "\n", - "Use the [`evaluate`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#evaluate) method to evaluate the model on the test dataset!" - ] - }, - { - "metadata": { - "id": "VflXLEeECaXC", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Use the evaluate method to test the model!'''\n", - "test_loss, test_acc = model.evaluate(test_images, test_labels) # TODO\n", - "\n", - "print('Test accuracy:', test_acc)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "yWfgsmVXCaXG", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "You may observe that the accuracy on the test dataset is a little lower than the accuracy on the training dataset. This gap between training accuracy and test accuracy is an example of *overfitting*, when a machine learning model performs worse on new data than on its training data. \n", - "\n", - "What is the highest accuracy you can achieve with this first fully connected model? Since the handwritten digit classification task is pretty straightforward, you may be wondering how we can do better...\n", - "\n", - "![Deeper...](https://i.kym-cdn.com/photos/images/newsfeed/000/534/153/f87.jpg)" - ] - }, - { - "metadata": { - "id": "baIw9bDf8v6Z", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.3 Convolutional Neural Network (CNN) for handwritten digit classification" - ] - }, - { - "metadata": { - "id": "_J72Yt1o_fY7", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As we saw in lecture, convolutional neural networks (CNNs) are particularly well-suited for a variety of tasks in computer vision, and have achieved near-perfect accuracies on the MNIST dataset. We will now build a CNN composed of two convolutional layers and pooling layers, followed by two fully connected layers, and ultimately output a probability distribution over the 10 digit classes (0-9). The CNN we will be building is depicted below:\n", - "\n", - "![alt_text](img/convnet_fig.png \"CNN Architecture for MNIST Classification\")" - ] - }, - { - "metadata": { - "id": "EEHqzbJJAEoR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Define the CNN model\n", - "\n", - "We'll use the same training and test datasets as before, and proceed similarly as our fully connected network to define and train our new CNN model. \n", - "\n", - "You can use [`keras.layers.Conv2D` ](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D) to define convolutional layers and [`keras.layers.MaxPool2D`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/MaxPool2D) to define the pooling layers. Use the parameters shown in the network architecture above to define these layers and build the CNN model!" - ] - }, - { - "metadata": { - "id": "vec9qcJs-9W5", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def build_cnn_model():\n", - " cnn_model = tf.keras.Sequential([\n", - "\n", - " tf.keras.layers.Conv2D(filters=24, kernel_size=(3,3), input_shape=(28, 28, 1), activation=tf.nn.relu), # TODO \n", - "\n", - " tf.keras.layers.MaxPool2D(pool_size=(2,2)), # TODO\n", - "\n", - " #'''TODO: Define the second convolutional layer'''\n", - " tf.keras.layers.Conv2D(filters=36, kernel_size=(3,3), activation=tf.nn.relu), # TODO\n", - "\n", - " #'''TODO: Define the second max pooling layer'''\n", - " tf.keras.layers.MaxPool2D(pool_size=(2,2)), # TODO\n", - "\n", - " tf.keras.layers.Flatten(),\n", - " tf.keras.layers.Dense(128, activation=tf.nn.relu),\n", - " #'''TODO: Define the last Dense layer'''\n", - " tf.keras.layers.Dense(10, activation=tf.nn.softmax) # TODO\n", - " ])\n", - " return cnn_model\n", - " \n", - "cnn_model = build_cnn_model()\n", - "print(cnn_model.summary())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "kUAXIBynCih2", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Train and test the CNN model\n", - "\n", - "Now, as before, we can define the loss function, optimizer, and metrics through the `compile` method. Compile the CNN model with an optimizer and learning rate of choice:" - ] - }, - { - "metadata": { - "id": "vheyanDkCg6a", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Define the compile operation with your optimizer and learning rate of choice'''\n", - "cnn_model.compile(optimizer=tf.train.GradientDescentOptimizer(learning_rate=1e-1), # TODO\n", - " loss='sparse_categorical_crossentropy',\n", - " metrics=['accuracy'])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "U19bpRddC7H_", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now we can train our model using the `fit` method via the Keras API:" - ] - }, - { - "metadata": { - "id": "YdrGZVmWDK4p", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Train the CNN model'''\n", - "cnn_model.fit(train_images, train_labels, batch_size=BATCH_SIZE, epochs=EPOCHS)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "pEszYWzgDeIc", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Great! Now that we've trained the model, let's evaluate it on the test dataset using the [`evaluate`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#evaluate) method:" - ] - }, - { - "metadata": { - "id": "JDm4znZcDtNl", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: Use the evaluate method to test the model!'''\n", - "test_loss, test_acc = cnn_model.evaluate(test_images, test_labels) # TODO\n", - "\n", - "print('Test accuracy:', test_acc)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "2rvEgK82Glv9", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "What is the highest accuracy you're able to achieve using the CNN model, and how does the accuracy of the CNN model compare to the accuracy of the simple fully connected network? What optimizers and learning rates seem to be optimal for training the CNN model? " - ] - }, - { - "metadata": { - "id": "xsoS7CPDCaXH", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Make predictions with the CNN model\n", - "\n", - "With the model trained, we can use it to make predictions about some images. We'll use the [`predict`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#predict) function call to generate the output predictions given a set of input samples.\n" - ] - }, - { - "metadata": { - "id": "Gl91RPhdCaXI", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "predictions = cnn_model.predict(test_images)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "x9Kk1voUCaXJ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "With this function call, the model has predicted the label for each image in the testing set. Let's take a look at the prediction for the first image in the test dataset:" - ] - }, - { - "metadata": { - "id": "3DmJEUinCaXK", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "predictions[0]" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "-hw1hgeSCaXN", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As you can see, a prediction is an array of 10 numbers. Recall that the output of our model is a probability distribution over the 10 digit classes. Thus, these numbers describe the model's \"confidence\" that the image corresponds to each of the 10 different digits. \n", - "\n", - "Let's look at the digit that has the highest confidence for the first image in the test dataset:" - ] - }, - { - "metadata": { - "id": "qsqenuPnCaXO", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: identify the digit with the highest confidence prediction for the first\n", - " image in the test dataset'''\n", - "np.argmax(predictions[0]) # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "E51yS7iCCaXO", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "So, the model is most confident that this image is a \"7\". We can check the test label (remember, this is the true identity of the digit) to see if this prediction is correct:" - ] - }, - { - "metadata": { - "id": "Sd7Pgsu6CaXP", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "test_labels[0]" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "ygh2yYC972ne", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "It is!\n", - "\n", - "We can define a couple of functions to help visualize the classification results on the MNIST dataset. First, we'll write a function, `plot_image`, to plot images along with their predicted label and the probability of the prediction. Second, we'll also define a function, `plot_value_array`, to plot the prediction probabilities for each of the digits. " - ] - }, - { - "metadata": { - "id": "DvYmmrpIy6Y1", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def plot_image(i, predictions_array, true_label, img):\n", - " predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]\n", - " plt.grid(False)\n", - " plt.xticks([])\n", - " plt.yticks([])\n", - " \n", - " plt.imshow(np.squeeze(img), cmap=plt.cm.binary)\n", - "\n", - " predicted_label = np.argmax(predictions_array)\n", - " if predicted_label == true_label:\n", - " color = 'blue'\n", - " else:\n", - " color = 'red'\n", - " \n", - " plt.xlabel(\"{} {:2.0f}% ({})\".format(predicted_label,\n", - " 100*np.max(predictions_array),\n", - " true_label),\n", - " color=color)\n", - "\n", - "def plot_value_array(i, predictions_array, true_label):\n", - " predictions_array, true_label = predictions_array[i], true_label[i]\n", - " plt.grid(False)\n", - " plt.xticks([])\n", - " plt.yticks([])\n", - " thisplot = plt.bar(range(10), predictions_array, color=\"#777777\")\n", - " plt.ylim([0, 1]) \n", - " predicted_label = np.argmax(predictions_array)\n", - " \n", - " thisplot[predicted_label].set_color('red')\n", - " thisplot[true_label].set_color('blue')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "d4Ov9OFDMmOD", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's use these functions to visualize the model's predictions for the images in the test dataset: " - ] - }, - { - "metadata": { - "id": "HV5jw-5HwSmO", - "colab_type": "code", - "cellView": "both", - "colab": {} - }, - "cell_type": "code", - "source": [ - "#@title Change the slider to look at the model's predictions! { run: \"auto\" }\n", - "\n", - "image_index = 8 #@param {type:\"slider\", min:0, max:100, step:1}\n", - "plt.subplot(1,2,1)\n", - "plot_image(image_index, predictions, test_labels, test_images)\n", - "plt.subplot(1,2,2)\n", - "plot_value_array(image_index, predictions, test_labels)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "kgdvGD52CaXR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also plot several images along with their predictions, where correct prediction labels are blue and incorrect prediction labels are red. The number gives the percent confidence (out of 100) for the predicted label. Note the model can be very confident in an incorrect prediction!" - ] - }, - { - "metadata": { - "id": "hQlnbqaw2Qu_", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Plot the first X test images, their predicted label, and the true label\n", - "# Color correct predictions in blue, incorrect predictions in red\n", - "num_rows = 5\n", - "num_cols = 4\n", - "num_images = num_rows*num_cols\n", - "plt.figure(figsize=(2*2*num_cols, 2*num_rows))\n", - "for i in range(num_images):\n", - " plt.subplot(num_rows, 2*num_cols, 2*i+1)\n", - " plot_image(i, predictions, test_labels, test_images)\n", - " plt.subplot(num_rows, 2*num_cols, 2*i+2)\n", - " plot_value_array(i, predictions, test_labels)\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "k-2glsRiMdqa", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.4 Training the model 2.0\n", - "\n", - "Earlier in the lab, we used the [`fit`](https://www.tensorflow.org/api_docs/python/tf/keras/models/Sequential#fit) function call to train the model. This function is quite high-level and intuitive, which is really useful for simpler models. As you may be able to tell, this function abstracts away many details in the training call, and we have less control over training model, which could be useful in other contexts. \n", - "\n", - "As an alternative to this, we can use the [`tf.GradientTape`](https://www.tensorflow.org/api_docs/python/tf/GradientTape) class to record differentiation operations during training, and then call the [`tf.GradientTape.gradient`](https://www.tensorflow.org/api_docs/python/tf/GradientTape#gradient) function to actually compute the gradients. \n", - "\n", - "You may recall seeing this in Lab 1 Part 1, but let's take another look at this here.\n", - "\n", - "We'll use this framework to train our `cnn_model` using stochastic gradient descent." - ] - }, - { - "metadata": { - "id": "Wq34id-iN1Ml", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Rebuild the CNN model\n", - "cnn_model = build_cnn_model()\n", - "\n", - "batch_size = 12\n", - "loss_history = util.LossHistory(smoothing_factor=0.99) # to record the evolution of the loss\n", - "plotter = util.PeriodicPlotter(sec=2, xlabel='Iterations', ylabel='Loss', scale='semilogy')\n", - "optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-2) # define our optimizer\n", - "\n", - "bar = util.create_progress_bar()\n", - "for idx in bar(range(0, train_images.shape[0],batch_size)):\n", - " # First grab a batch of training data and convert the input images to tensors\n", - " (images, labels) = (train_images[idx:idx+batch_size], train_labels[idx:idx+batch_size])\n", - " images = tf.convert_to_tensor(images, dtype=tf.float32)\n", - "\n", - " # GradientTape to record differentiation operations\n", - " with tf.GradientTape() as tape:\n", - " logits = cnn_model(images) # feed the images into the model\n", - " loss_value = tf.keras.backend.sparse_categorical_crossentropy(labels, logits) # value of the loss\n", - "\n", - " loss_history.append(loss_value.numpy().mean()) # append the loss to the loss_history record\n", - " plotter.plot(loss_history.get())\n", - " # Backpropagation\n", - " grads = tape.gradient(loss_value, cnn_model.variables)\n", - " optimizer.apply_gradients(zip(grads, cnn_model.variables),\n", - " global_step=tf.train.get_or_create_global_step())\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "3cNtDhVaqEdR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 1.5 Conclusion\n", - "In this part of the lab, you had the chance to play with different MNIST classifiers with different architectures (fully-connected layers only, CNN), and experiment with how different hyperparameters affect accuracy (learning rate, etc.). The next part of the lab explores another application of CNNs, facial detection, and some drawbacks of AI systems in real world applications, like issues of bias. " - ] - }, - { - "metadata": { - "id": "Pu9T7wjF7Pz7", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "" - ], - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/lab2/Part2_debiasing.ipynb b/lab2/Part2_debiasing.ipynb deleted file mode 100644 index d7e3347e..00000000 --- a/lab2/Part2_debiasing.ipynb +++ /dev/null @@ -1,1255 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Copy of Copy of Part2_debiasing_solution.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [ - "NDj7KBaW8Asz" - ] - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "metadata": { - "id": "Ag_e7xtTzT1W", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "\n", - "# Laboratory 2: Computer Vision\n", - "\n", - "# Part 2: Debiasing Facial Detection Systems\n", - "\n", - "In the second portion of the lab, we'll explore two prominent aspects of applied deep learning: facial detection and algorithmic bias. \n", - "\n", - "Deploying fair, unbiased AI systems is critical to their long-term acceptance. Consider the task of facial detection: given an image, is it an image of a face? [Recent work from the MIT Media Lab](http://proceedings.mlr.press/v81/buolamwini18a/buolamwini18a.pdf) showed that this seemingly simple, but extremely important, task is subject to extreme amounts of algorithmic bias among select demographics. [Another report](https://ieeexplore.ieee.org/document/6327355) analyzed the face detection system used by the US law enforcement and found that it had significantly lower accuracy among dark skinned women between the age of 18-30 years old. \n", - "\n", - "Run the next code block for a short video from Google that explores how and why it's important to consider bias when thinking about machine learning:" - ] - }, - { - "metadata": { - "id": "XQh5HZfbupFF", - "colab_type": "code", - "outputId": "4a6df36f-b4b5-442c-b735-0cce3ad31e71", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 322 - } - }, - "cell_type": "code", - "source": [ - "from IPython.display import YouTubeVideo\n", - "YouTubeVideo('59bMh59JQDo')" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/html": [ - "\n", - " \n", - " " - ], - "image/jpeg": "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\n1I6b0kle7O7xXaqzfNlFwRpVVRUQQVtaVfNnIRTERydJF0gMkvXILe0va7dzMtufQ6SSrCvKmiKr\nhHbjqMethxcf0LkRM12uzE9rXVHwbxmWp6jqdAWnVNJ92S7YzTZY1A7hx5YkDbJPhmzXe7Ez3XWu\n6tOa1Hufnx3OT6PUUNNLSbpJx5d1w07yys4q1Q6CgqKuOmOrOAMhhj8R9TD6rO+LXyd2Z3sL8k+F\ndUOvoKerlppKQ5wzKE+og6nHxEzOTPbJrsz2JuTKxTA8ur/u9VUp7rvHg7N0elt25u91viuK492a\neq6xS0W0VXVwU2+Yww78oQ7speEI83bIvgy31znG3B+n65HBHqMJTDTGUkeJnD4hEZAIgdsgJhG/\n+VrOyttZmmjpqiSkjGaojgmKmikLbjlnGMihAiu2IubM17t397d6tm8nGpTTluS24qufeP2KjjDh\nybUZqKaLUZ6DsU5TSDFchnEiAsSHNmybBxZyZ2tIXJ+57rVDlGCYqaOOSoGKYoAkLbjOcYy2QkL1\nQc8Wf4OqX7PK7U6nTgm1qmjpKsjmEooxxHbEvMmUeZbZO1+WT91+V7N0Jlj1ErvVc4pPhcfkz0dO\nD3aiTTlTd3eFSw+Dmfs4q9XnoNzXqaGkq9+QRCEh64MRKMyEJCaMruY2yfkDP6Vedug7R2Xfi7Rh\nu7OYb+34c9q+WH9rLU4e4iotUjObTqmKrCMyhkKHLpkH1SyZnxdnZ29Ds92d1phwjSfexa1jN2sg\nw8fmvwtjPC3j22Ye+3ptfmsPkktufN+Dr+jjpuHyk3h7Xh2+18Y8v+RscZajUUWnVVTRUhVtRFFl\nDTjkRGWQj4Q6pMWdysPN8LNzdLhPUqit06lqaukKgqJospqeTLKIsiHwl1DkzMVi5sxMz82dW5Mt\nEtTp+09k3o+0E2e162OOX6ZWa9r3tztZWlOMa3Ou35M46U5T3RbarisffyZWqgKTZ3o93Hc2sx3N\nv8+3e+Pxsq/ijVJaKmKeGmKpITjHAb9Il65Ys74tZm7vWZZB0Gn7f944l2jDG+RYfh7eWHtwZm9n\nwvzVkzLKtWcJRbUXlRazjs8rn0dV6cJRkvksWnjPdY7ezBQzFLDFIUZRlIEchRF+IBSCJYF/Uzvb\n+yjp2oQVOfZ545dksZNtxLEurxf7P8Hs6zxSgREIyCTxvjIwkJEBflIfV/utbRdFpaLd7NFt7z7k\nnU5fmxYcnfEGyezNya7qW53FRpr/AHPvx2rHPJWoVLdaf+1dvz344KGbhivLiENW+9pRoI4dktNE\njGMi2Tj6hzwIXM9y7te4s3czWuOM6utg06qm0umGrrYwHs0BeEiKQRIsbtuYg5Ha7Xwt6VbWTda7\nfBxr6dRUlFtbrd3m34uyr4TqauagpZtTgjpq2SISqYY/CEn9PN8bti7td7O7td7LXbh/HVPvLfk6\nosNn1fBh4r+D1rW7+d1scUTVcdIZUEYy1GUeLFj4ch3CESdmIrfH/wBFuaacpQxFOIxzlFGUoD1C\nM2I7gjzfpZ7+l/7rnnGGpNQkm9tSTzV5XPn0duip6WluUubi+LeFdr35NlnUlynC9FrEep6pNqNX\nBNQTGP3XDCPVBGJH4vNs4lg4M9ye7s78m7+nXSmculqOatprnn7/ANTIhY1NlY0AlF03SsoYE6Sd\nknUgd0XUE2VQTd1FJ3SYkFgykyxssjIQNDpkouhInUHJZFjkVgRukhSZkIBmWQEhZSQkV00WTZVA\n2UhSFc/x9pVfW0wRaZX9glGaOSQ8jHOMRLo3AZyHrcSt3PjZ+9aacVKSTde2Za2o4Qcoxcmuyq3+\nuC31as7NTT1O3JNsRSzbUf4h7cZSYR/1Pa391XcEcQjq1AFaMElMMhSDhIQlltljlHILNuA78u5u\nbP7FdRMQiORZFiORY45F6xY+rd7vZSU3FRarPkpWo9RT3VGsxpZfm/Xghn1EOQ5D4hy6hy8OQ943\nQzKg0nhKnpNUq9WjmnKatHGQJDEoR6gIsRtcucY2yd7M7s3LufH2hVWp0gwUlfJp0ozRzFLGRjnG\nImJAW0bFjchLv7wb9Wtsg2kpY7trgr1tVacpOHyV0k1ldsuqsv0O6hTRkMYCUhSEICJGXiMhHEjL\nH1nfn/dZVk0dKdoFFSUSQkBTd1BDqoNDU9fpKSenpqmpjhmqyxpgLLIyyx9VrR3d2FnJ2Z3ezc1k\n1HRqSpmhnqaaKWakLKmMwyKIsmK4l+os/PudmfvWDUtBpKuenqammjlmpCypjLLoLIS8IuzSWdmJ\nsmeztdualxRBVzUU8OnTx01VIOMMsg5CBZDl6HxuDEN7PbK9nstXCEtq/W+OTnhq62k5S7L+Hbe5\nqsp8K3lGfXhqCpKgaIo46ooZOzEf4Yz4ltuXJ2xvbvZ/0fuVfwQGoDQRDqxBJViUmZBh1R7j7ee0\n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\nffUMEPa5qTYmGfKEciLEcfa2Jte7Pzs/odX9VUBDHuTShCA45HKbAI+qORm7NzRwhGCaec2q4/7L\nR1dbU1XFp0klF3d+kuVRUaNxZSVtfV6dDvb1B+NkGMZYybcm3Jd8sTdme7N8Ls11ewwiP4YiOTkR\nYiI5EXiIsfET+1YYaaIZCmjjhE5sdyWMAGSXHw7kgteS3ou7qu0jieirauooqafcqKTLfDExEcS2\n5MZCbGTE7C9n5O7K8kpZ006SV9zCEnptLXcdzbUe1+ErfKXJocE8Xhq01bCFJU03YJRid58esiKQ\ncenwSttvdn7sm5q7rtKp6iaKaaKOSWAsojK/R1Ze2xWdmdr3s7XW4uYmodVfXIqmOti+6mhwkpOe\nbntnzx23Yn3HAr5NZhtb28UofBKS3Z8Lz49HrJxnNy0300o2k23dLKTq7ln0dOpKj450I9U06ooI\nauagOfbxqIcsg25AkxIRNnICxxdmJuROt3h3TioqKlpJJ5KkqaGOEp5vxJSjHEjkyd3ye3pd3+L9\n63Tdnn75b9tYrm+/iuSwZcoXHNP/AMQf8PbFT2jZ397ENj8HfxLnljg1r2td7KXC3DVXRanqVbPq\n09bBXnlBSSCW3SjuEQiORu3Sz4NgLXYWvd7W6fEcsunLw5etj4sf8vpsoyzO5zimvjnN07Sf3xZX\nU2h0sdXLXxxkNRKOJlkWPq5EMfcJPgN/0+L3wcUSagPZ/u6OI8pf8Tnj0h04+J/D4r43fk1lDitt\nSxg+7SiEs/P7uHg5Y+NvB4r48+6ytq2qCCE5pS2whEpJC6ukR8XSPP8A2XG4xe6EU4LlyVJO8tp/\nuemnJOM5NTfCTt1WEmv2Mzsk0gl62WL4lj1Yv7P1WppGpwVcLT00m5EWWJYkPUJYkJCVnHmtDhnh\n2LTiqCikmk7SYyFuEPLHPw4+Iut7u/N7N7Ft1ZNx2JOL5d8KsV5sz2JKSm2pLhV7zfii6dJDIutz\nAE3ZF0kAIQhADpOlkmgIEyiLKZMoKxBsCSCSZ02dVBJRdSUSViRM65/hLhKl0mSqkpCmyrZRmk3j\nEhDHMhCPFm6WeQ+ZXfnzd7K/SMchIciHISHIfEOXrD/U3epjqSScU8Pky1NGMmpyjco3T8WqwTSd\nc99n/Dkuk0h001bJXkU0kwnIJDgJCA4CJG7+q5Pztc35e3oSUziotqLteSNGc5wTnHa+6tOvysEb\n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\nyyZx03NS5aWH4vlHuV3WK68PP/F9xL7v4f8AltQ+vS8r7iX+Q0D5av8Ar1boyL9RHuJDOvDvlfcS\n/wAhoHy1f9ejyvuJf5DQPlq/69OjIdRHuRnU2Xhpv4wOJfd3D3y2ofXo8sHiX3dw98tqH7gnRkOo\nj3OosvDflg8S+7uHvltQ+vS8sHiX3dw98tqH7gnRkOojzohCF1GAIQhACEIQAhCEAIQhACEIQAhC\nEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQA\nhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEI\nQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhAC\nEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQh\nACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQH//2Q==\n", - "text/plain": [ - "" - ] - }, - "metadata": { - "tags": [] - }, - "execution_count": 1 - } - ] - }, - { - "metadata": { - "id": "3Ezfc6Yv6IhI", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "In this lab, we'll investigate [one recently published approach](http://introtodeeplearning.com/AIES_2019_Algorithmic_Bias.pdf) to addressing algorithmic bias. We'll build a facial detection model that learns the *latent variables* underlying face image datasets and uses this to adaptively re-sample the training data, thus mitigating any biases that may be present in order to train a *debiased* model.\n", - "\n", - "Let's get started by installing the relevant dependencies:" - ] - }, - { - "metadata": { - "id": "E46sWVKK6LP9", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "\n", - "import functools\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pdb\n", - "\n", - "# Download the class repository\n", - "! git clone https://github.com/aamini/introtodeeplearning_labs.git > /dev/null 2>&1\n", - "% cd introtodeeplearning_labs \n", - "! git pull\n", - "% cd .. \n", - "\n", - "# Import the necessary class-specific utility files for this lab\n", - "import introtodeeplearning_labs as util" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "V0e77oOM3udR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.1 Datasets\n", - "\n", - "We'll be using three datasets in this lab. In order to train our facial detection models, we'll need a dataset of positive examples (i.e., of faces) and a dataset of negative examples (i.e., of things that are not faces). We'll use these data to train our models to classify images as either faces or not faces. Finally, we'll need a test dataset of face images. Since we're concerned about the potential *bias* of our learned models against certain demographics, it's important that the test dataset we use has equal representation across the demographics or features of interest. In this lab, we'll consider skin tone and gender. \n", - "\n", - "1. **Positive training data**: [CelebA Dataset](http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html). A large-scale (over 200K images) of celebrity faces. \n", - "2. **Negative training data**: [ImageNet](http://www.image-net.org/). Many images across many different categories. We'll take negative examples from a variety of non-human categories. \n", - "3. **Test data**: [Pilot Parliaments Benchmark](http://proceedings.mlr.press/v81/buolamwini18a/buolamwini18a.pdf) (PPB). The PPB dataset consists of images of 1270 male and female parliamentarians from various African and European countries and exhibits parity in both skin tone and gender. The gender of each face is annotated with the sex-based \"Male'' and \"Female'' labels. Skin tone annotations are based on the Fitzpatrick skin type classification system, with each image labeled as \"Lighter'' or \"Darker''.\n", - "\n", - "Let's begin by importing these datasets: " - ] - }, - { - "metadata": { - "id": "RWXaaIWy6jVw", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Get the training data: both images from CelebA and ImageNet\n", - "path_to_training_data = tf.keras.utils.get_file('train_face.h5', 'https://www.dropbox.com/s/l5iqduhe0gwxumq/train_face.h5?dl=1')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "bAY6pDc_Zljt", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "This directly downloads the raw data. We've written two classes that do a bit of data pre-processing and import the results in a usable format: `TrainingDatasetLoader` for the training data and `PPBFaceEvaluator` for the test data.\n", - "\n", - "Let's create a `TrainingDatasetLoader` and use it to take a look at the training data." - ] - }, - { - "metadata": { - "id": "UX-eUcEoazBm", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Instantiate a TrainingDatasetLoader using the downloaded dataset\n", - "loader = util.TrainingDatasetLoader(path_to_training_data)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "yIE321rxa_b3", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can look at the size of the training dataset and grab a batch of size 100:" - ] - }, - { - "metadata": { - "id": "DjPSjZZ_bGqe", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "number_of_training_examples = loader.get_train_size()\n", - "(images, labels) = loader.get_batch(100)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "sxtkJoqF6oH1", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Play around with displaying images to get a sense of what the training data actually looks like!" - ] - }, - { - "metadata": { - "id": "Jg17jzwtbxDA", - "colab_type": "code", - "outputId": "1e0c923e-f1e5-4ac9-b506-064a0d11568e", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 165 - } - }, - "cell_type": "code", - "source": [ - "#@title Change the sliders to look at positive and negative training examples! { run: \"auto\" }\n", - "\n", - "face_images = images[np.where(labels==1)[0]]\n", - "not_face_images = images[np.where(labels==0)[0]]\n", - "\n", - "idx_face = 20 #@param {type:\"slider\", min:0, max:50, step:1}\n", - "idx_not_face = 11 #@param {type:\"slider\", min:0, max:50, step:1}\n", - "\n", - "plt.figure(figsize=(4,2))\n", - "plt.subplot(1, 2, 1)\n", - "plt.imshow(face_images[idx_face])\n", - "plt.title(\"Face\")\n", - "plt.grid(False)\n", - "\n", - "plt.subplot(1, 2, 2)\n", - "plt.imshow(not_face_images[idx_not_face])\n", - "plt.title(\"Not Face\")\n", - "plt.grid(False)" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "display_data", - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "metadata": { - "id": "kjuaEdLzb4pP", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also create a `PPBFaceEvaluator` instance for the PPB dataset and display some example images. We'll use this dataset later on in the evaluation step." - ] - }, - { - "metadata": { - "id": "4B4egQZY6wEt", - "colab_type": "code", - "outputId": "5d322438-3add-4333-e05d-5384c8d46700", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 351 - } - }, - "cell_type": "code", - "source": [ - "#@title { run: \"auto\" }\n", - "\n", - "ppb = util.PPBFaceEvaluator() # create the dataset handler\n", - "\n", - "gender = \"male\" #@param [\"male\", \"female\"]\n", - "skin_color = \"darker\" #@param [\"lighter\", \"darker\"]\n", - "\n", - "img = ppb.get_sample_faces_from_demographic(gender, skin_color)\n", - "plt.imshow(img)\n", - "plt.grid(False)" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "display_data", - "data": { - "image/png": "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\nRK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "metadata": { - "id": "NDj7KBaW8Asz", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Thinking about bias\n", - "\n", - "Remember we'll be training our facial detection classifiers on the large, well-curated CelebA dataset (and ImageNet), and then evaluating their accuracy by testing them on the PPB dataset. Our goal is to build a model that trains on CelebA *and* achieves high classification accuracy on PPB across all demographics, and to thus show that this model does not suffer from any hidden bias. \n", - "\n", - "What exactly do we mean when we say a classifier is biased? In order to formalize this, we'll need to think about [*latent variables*](https://en.wikipedia.org/wiki/Latent_variable), variables that define a dataset but are not strictly observed. As defined in the generative modeling lecture, we'll use the term *latent space* to refer to the probability distributions of the aforementioned latent variables. Putting these ideas together, we consider a classifier *biased* if its classification decision changes after it sees some additional latent features. This notion of bias may be helpful to keep in mind throughout the rest of the lab. " - ] - }, - { - "metadata": { - "id": "AIFDvU4w8OIH", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.2 CNN for facial detection \n", - "\n", - "First, we'll define and train a CNN on the facial classification task, and evaluate its accuracy on the PPB dataset. Later, we'll evaluate the performance of our debiased models against this baseline CNN. The CNN model has a relatively standard architecture consisting of a series of convolutional layers with batch normalization followed by two fully connected layers to flatten the convolution output and generate a class prediction. \n", - "\n", - "### Define and train the CNN model\n", - "\n", - "Like we did in the first part of the lab, we'll define our CNN model, and then train on the CelebA and ImageNet datasets using the `tf.GradientTape` class and the `tf.GradientTape.gradient` method." - ] - }, - { - "metadata": { - "id": "82EVTAAW7B_X", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "n_outputs = 1 # number of outputs (i.e., face or not face)\n", - "n_filters = 12 # base number of convolutional filters\n", - "\n", - "'''Function to define a standard CNN model'''\n", - "def make_standard_classifier():\n", - " Conv2D = functools.partial(tf.keras.layers.Conv2D, padding='same', activation='relu')\n", - " BatchNormalization = tf.keras.layers.BatchNormalization\n", - " Flatten = tf.keras.layers.Flatten\n", - " Dense = functools.partial(tf.keras.layers.Dense, activation='relu')\n", - "\n", - " model = tf.keras.Sequential([\n", - " Conv2D(filters=1*n_filters, kernel_size=[5,5], strides=[2,2], input_shape=(64,64,3)),\n", - " BatchNormalization(),\n", - " \n", - " Conv2D(filters=2*n_filters, kernel_size=[5,5], strides=[2,2]),\n", - " BatchNormalization(),\n", - "\n", - " Conv2D(filters=4*n_filters, kernel_size=[3,3], strides=[2,2]),\n", - " BatchNormalization(),\n", - "\n", - " Conv2D(filters=6*n_filters, kernel_size=[3,3], strides=[1,1]),\n", - " BatchNormalization(),\n", - "\n", - " Flatten(),\n", - " Dense(1, activation=None),\n", - " tf.keras.layers.Dropout(0.5)\n", - " ])\n", - " return model\n", - " \n", - "standard_classifier = make_standard_classifier()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "c-eWf3l_lCri", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now let's train the standard CNN!\n", - "\n", - "**IMPORTANT NOTE: For educational purposes (to keep training times low), in this lab we are not training our models (both this CNN and a second model later on) for very long, and are only using a small, randomly sampled fraction of the CelebA dataset to train. As a result, the gap in accuracies between the standard CNN classifier and the debiased model (which you'll define soon) will not be as pronounced as if you were to train the models for longer and/or with more data.**" - ] - }, - { - "metadata": { - "id": "jmOBzRgplB-n", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "batch_size = 36\n", - "num_epochs = 10 # keep small to run faster\n", - "learning_rate = 1e-3\n", - "\n", - "optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) # define our optimizer\n", - "loss_history = util.LossHistory(smoothing_factor=0.99) # to record the evolution of the loss\n", - "plotter = util.PeriodicPlotter(sec=2, scale='semilogy')\n", - "\n", - "# The training loop!\n", - "for epoch in range(num_epochs):\n", - " \n", - " custom_msg = util.custom_progress_text(\"Epoch: %(epoch).0f Loss: %(loss)2.2f\")\n", - " bar = util.create_progress_bar(custom_msg)\n", - " \n", - " for idx in bar(range(loader.get_train_steps_per_epoch(batch_size))):\n", - " # First grab a batch of training data and convert the input images to tensors\n", - " x, y = loader.get_batch(batch_size)\n", - " x = tf.convert_to_tensor(x, dtype=tf.float32)\n", - " y = tf.convert_to_tensor(y, dtype=tf.float32)\n", - " \n", - " # GradientTape to record differentiation operations\n", - " with tf.GradientTape() as tape:\n", - " logits = standard_classifier(x) # feed the images into the model\n", - " loss_value = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=logits) # compute the loss\n", - "\n", - " custom_msg.update_mapping(epoch=epoch, loss=loss_value.numpy().mean())\n", - " # Backpropagation\n", - " grads = tape.gradient(loss_value, standard_classifier.variables)\n", - " optimizer.apply_gradients(zip(grads, standard_classifier.variables), global_step=tf.train.get_or_create_global_step())\n", - "\n", - " loss_history.append(loss_value.numpy().mean()) \n", - " plotter.plot(loss_history.get())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "AKMdWVHeCxj8", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Evaluate performance of the standard CNN\n", - "\n", - "Next, let's evaluate the classification performance of our CelebA-trained standard CNN on the training dataset and the PPB dataset. For the PPB data, we'll look at the classification accuracy across four different demographics defined in PPB: dark-skinned male, dark-skinned female, light-skinned male, and light-skinned female.\n" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "35-PDgjdWk6_", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Evaluate on a subset of CelebA+Imagenet\n", - "(batch_x, batch_y) = loader.get_batch(5000)\n", - "y_pred_standard = tf.round(tf.nn.sigmoid(standard_classifier.predict(batch_x)))\n", - "acc_standard = tf.reduce_mean(tf.cast(tf.equal(batch_y, y_pred_standard), tf.float32))\n", - "print \"Standard CNN accuracy on (potentially biased) training set: {:.4f}\".format(acc_standard.numpy())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "colab_type": "code", - "id": "vfDD8ztGWk6x", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Evaluate on PPB dataset (takes ~3 minutes)\n", - "standard_cnn_accuracy = []\n", - "for skin_color in ['lighter', 'darker']:\n", - " for gender in ['male', 'female']:\n", - " standard_cnn_accuracy.append( ppb.evaluate([standard_classifier], gender, skin_color, from_logit=True)[0] )\n", - " print \n", - " print \"{} {}: {}\".format(gender, skin_color, standard_cnn_accuracy[-1])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "SaPPGYdPmcCi", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "plt.bar(range(4), standard_cnn_accuracy)\n", - "plt.xticks(range(4), ('LM', 'LF', 'DM', 'DF'))\n", - "plt.ylim(np.min(standard_cnn_accuracy)-0.01,np.max(standard_cnn_accuracy)+0.01)\n", - "plt.ylabel('Accuracy')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "j0Cvvt90DoAm", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Take a look at the accuracies for this first model across these four groups. What do you observe? Would you consider this model biased or unbiased, and why? " - ] - }, - { - "metadata": { - "id": "nLemS7dqECsI", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.3 Variational autoencoder (VAE) for learning latent structure\n", - "\n", - "As you saw, the accuracy of the CNN varies across the four demographics we looked at. To think about why this may be, consider the dataset the model was trained on, CelebA. If certain features, such as dark skin or hats, are *rare* in CelebA, the model may end up biased against these as a result of training with a biased dataset. That is to say, its classification accuracy will be worse on faces that have under-represented features, such as dark-skinned faces or faces with hats, relevative to faces have features that are well-represented in the training data! This is a problem. \n", - "\n", - "Our goal is to train a *debiased* version of this classifier -- one that accounts for potential disparities in feature representation within the training data. Specifically, to build a debiased facial classifier, we'll train a model that learns a representation of the underlying latent space to the face training data. The model then uses this information to mitigate unwanted biases by sampling faces with rare features, like dark skin or hats, *more frequently* during training. The key design requirement for our model is that it can learn an *encoding* of the latent features in the face data in an entirely *unsupervised* way. To achieve this, we'll turn to variational autoencoders (VAEs).\n", - "\n", - "![The concept of a VAE](http://kvfrans.com/content/images/2016/08/vae.jpg)\n", - "\n", - "As shown in the schematic above, VAEs rely on an encoder-decoder structure to learn a latent representation of the input data. In the context of computer vision, the encoder network takes in input images, encodes them into a series of variables defined by a mean and standard deviation, and then draws from the distributions defined by these parameters to generate a set of sampled latent variables. The decoder network then \"decodes\" these variables to generate a reconstruction of the original image, which is used during training to help the model identify which latent variables are important to learn. \n", - "\n", - "Let's formalize two key aspects of the VAE model and define relevant functions for each.\n" - ] - }, - { - "metadata": { - "id": "KmbXKtcPkTXA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Understanding VAEs: loss function\n", - "\n", - "In practice, how can we train a VAE? In doing the reparameterization above, we constrain the means and standard deviations to approximately follow a unit Gaussian. Recall that these are learned parameters, and therefore must factor into the loss computation, and that the decoder portion of the VAE is using these parameters to output a reconstruction that should closely match the input image, which also must factor into the loss. What this means is that we'll have two terms in our VAE loss function:\n", - "\n", - "1. **Latent loss ($L_{KL}$)**: measures how closely the learned latent variables match a unit Gaussian and is defined by the Kullback-Leibler (KL) divergence. Note that the reparameterization trick is what makes this loss function differentiable!\n", - "2. **Reconstruction loss ($L_{x}{(x,\\hat{x})}$)**: measures how accurately the reconstructed outputs match the input and is given by the $L^2$ norm of the input image and its reconstructed output. \n", - "\n", - "The equations for both of these losses are provided below:\n", - "\n", - "$$ L_{KL}(\\mu, \\sigma) = \\frac{1}{2}\\sum\\limits_{j=0}^{k-1}\\small{(\\sigma_j + \\mu_j^2 - 1 - \\log{\\sigma_j})} $$\n", - "\n", - "$$ L_{x}{(x,\\hat{x})} = ||x-\\hat{x}||_2 $$ \n", - "\n", - "Thus for the VAE loss we have: \n", - "\n", - "$$ L_{VAE} = c\\cdot L_{KL} + L_{x}{(x,\\hat{x})} $$\n", - "\n", - "where $c$ is a weighting coefficient used for regularization. \n", - "\n", - "Now we're ready to define our VAE loss function:" - ] - }, - { - "metadata": { - "id": "S00ASo1ImSuh", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Function to calculate VAE loss given an input x, reconstructed output x_pred, \n", - "# encoded means mu, encoded log of standard deviation logsigma, and weight parameter for the latent loss\n", - "def vae_loss_function(x, x_pred, mu, logsigma, kl_weight=0.0005):\n", - " '''TODO: Define the latent loss.\n", - " Hint: note that this function takes in logsigma!'''\n", - " latent_loss = 0.5 * tf.reduce_sum('''TODO''', axis=1) # TODO\n", - " '''TODO: Define the reconstruction loss. Hint: you'll need to use tf.reduce_mean to compute the mean-squared error, \n", - " with axis=(1,2,3)'''\n", - " reconstruction_loss = # TODO\n", - " '''TODO: Define the total VAE loss, i.e., weighted combination of two losses above.'''\n", - " total_vae_loss = # TODO\n", - " return total_vae_loss" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "E8mpb3pJorpu", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Great! Now that we have a more concrete sense of how VAEs work, let's explore how we can leverage this network structure to train a *debiased* facial classifier." - ] - }, - { - "metadata": { - "id": "DqtQH4S5fO8F", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Understanding VAEs: reparameterization \n", - "\n", - "As you may recall from lecture, VAEs use a \"reparameterization trick\" for sampling learned latent variables. Instead of the VAE encoder generating a single vector of real numbers for each latent variable, it generates a vector of means and a vector of standard deviations that are constrained to roughly follow Gaussian distributions. We then sample from the standard deviations and add back the mean to output this as our sampled latent vector. Formalizing this for a latent variable $z$ where we sample $\\epsilon \\sim \\mathcal{N}(0,(I))$ we have: \n", - "\n", - "$$ z = \\mathbb{\\mu} + e^{\\left(\\frac{1}{2} \\cdot \\log{\\Sigma}\\right)}\\circ \\epsilon $$\n", - "\n", - "where $\\mu$ is the mean and $\\Sigma$ is the covariance matrix. This is useful because it will let us neatly define the loss function for the VAE, generate randomly sampled latent variables, achieve improved network generalization, **and** make our complete VAE network differentiable so that it can be trained via backpropagation. Quite powerful!\n", - "\n", - "Let's define a function to implement the VAE sampling operation:" - ] - }, - { - "metadata": { - "id": "cT6PGdNajl3K", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "\"\"\"Reparameterization trick by sampling from an isotropic unit Gaussian.\n", - "# Arguments\n", - " args (tensor): mean and log of standard deviation of latent distribution (Q(z|X))\n", - "# Returns\n", - " z (tensor): sampled latent vector\n", - "\"\"\"\n", - "def sampling(args):\n", - " z_mean, z_logsigma = args\n", - " batch = z_mean.shape[0]\n", - " dim = z_mean.shape[1]\n", - " \n", - " # by default, random_normal has mean=0 and std=1.0\n", - " epsilon = tf.random_normal(shape=(batch, dim))\n", - " '''TODO: Define the reparameterization computation using the equation in the text above.'''\n", - " z = # TODO\n", - " return z" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "qtHEYI9KNn0A", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.4 Debiasing variational autoencoder (DB-VAE) for facial detection\n", - "\n", - "Now, we'll use the general idea behind the VAE architecture to build a model, termed a *debiasing variational autoencoder* or DB-VAE, to mitigate (potentially) unknown biases present within the training idea. We'll train our DB-VAE model on the facial detection task, run the debiasing operation during training, evaluate on the PPB dataset, and compare its accuracy to our original, biased CNN model. \n", - "\n", - "### The DB-VAE model\n", - "\n", - "The key idea behind this debiasing approach is to use the latent variables learned via a VAE to adaptively re-sample the CelebA data during training. Specifically, we will alter the probability that a given image is used during training based on how often its latent features appear in the dataset. So, faces with rarer features (like dark skin, sunglasses, or hats) should become more likely to be sampled during training, while the sampling probability for faces with features that are over-represented in the training dataset should decrease (relative to uniform random sampling across the training data). \n", - "\n", - "A general schematic of the DB-VAE approach is shown here:\n", - "\n", - "![DB-VAE](https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab2/img/DB-VAE.png)" - ] - }, - { - "metadata": { - "id": "ziA75SN-UxxO", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Recall that we want to apply our DB-VAE to a *supervised classification* problem -- the facial detection task. Importantly, note how the encoder portion in the DB-VAE architecture also outputs a single supervised variable, $z_o$, corresponding to the class prediction -- face or not face. Usually, VAEs are not trained to output any supervised variables (such as a class prediction)! This is another key distinction between the DB-VAE and a traditional VAE. \n", - "\n", - "Keep in mind that we only want to learn the latent representation of *faces*, as that's what we're ultimately debiasing against, even though we are training a model on a binary classification problem. We'll need to ensure that, **for faces**, our DB-VAE model both learns a representation of the unsupervised latent variables, captured by the distribution $q_\\phi(z|x)$, **and** outputs a supervised class prediction $z_o$, but that, **for negative examples**, it only outputs a class prediction $z_o$." - ] - }, - { - "metadata": { - "id": "XggIKYPRtOZR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Defining the DB-VAE loss function\n", - "\n", - "This means we'll need to be a bit clever about the loss function for the DB-VAE. The form of the loss will depend on whether it's a face image or a non-face image that's being considered. \n", - "\n", - "For **face images**, our loss function will have two components:\n", - "\n", - "\n", - "1. **VAE loss ($L_{VAE}$)**: consists of the latent loss and the reconstruction loss.\n", - "2. **Classification loss ($L_y(y,\\hat{y})$)**: standard cross-entropy loss for a binary classification problem. \n", - "\n", - "In contrast, for images of non-faces, our loss function is solely the classification loss. \n", - "\n", - "We can write a single expression for the loss by defining an indicator variable $\\mathcal{I}_f$which reflects which training data are images of faces ($\\mathcal{I}_f(x) = 1$ ) and which are images of non-faces ($\\mathcal{I}_f(x) = 0$). Using this, we obtain:\n", - "\n", - "$$L_{total} = L_y(y,\\hat{y}) + \\mathcal{I}_f(x)\\Big[L_{VAE}\\Big]$$\n", - "\n", - "Let's write a function to define the DB-VAE loss function:\n", - "\n" - ] - }, - { - "metadata": { - "id": "VjieDs8Ovcqs", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Loss function for DB-VAE\n", - "def debiasing_loss_function(x, x_pred, y, y_logit, mu, logsigma):\n", - "\n", - " '''TODO: call the relevant function that you created above to obtain the total VAE loss'''\n", - " vae_loss = # TODO\n", - " '''TODO: define the classification loss for the binary classification task.'''\n", - " classification_loss = tf.nn.sigmoid_cross_entropy_with_logits('''TODO''', '''TODO''') # TODO\n", - " \n", - " # Use the training data labels to create variable face_mask\n", - " # This is I_f in the equation in the text above.\n", - " face_mask = tf.cast(tf.equal(y, 1), tf.float32)\n", - " \n", - " '''TODO: define the DB-VAE total loss, based on the equation in the text above.\n", - " Think about the dimensionality of your output and why tf.reduce_mean is being used'''\n", - " total_loss = tf.reduce_mean(\n", - " '''TODO'''\n", - " )\n", - " \n", - " return total_loss, classification_loss" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "YIu_2LzNWwWY", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### DB-VAE architecture\n", - "\n", - "Now we're ready to define the DB-VAE architecture. First, let's define some key parameters for our model: the number of latent variables, the number of supervised outputs, and the starting number of filters for the first convolutional layer in the encoder." - ] - }, - { - "metadata": { - "id": "ds7o8AuFxUpg", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "latent_dim = 100" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "amYEnHdJxWYB", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "To build the DB-VAE, we'll define each of the encoder and decoder networks separately, create and initialize the two models, and then construct the end-to-end VAE. We'll go through each of these steps in turn. " - ] - }, - { - "metadata": { - "id": "4k0tQeW1xpJf", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''Define the encoder network for the DB-VAE'''\n", - "def make_face_encoder_network():\n", - " Conv2D = functools.partial(tf.keras.layers.Conv2D, padding='same', activation='relu')\n", - " BatchNormalization = tf.keras.layers.BatchNormalization\n", - " Flatten = tf.keras.layers.Flatten\n", - " Dense = functools.partial(tf.keras.layers.Dense, activation='relu')\n", - "\n", - " inputs = tf.keras.layers.Input(shape=(64,64,3))\n", - " \n", - " hidden = Conv2D(filters=1*n_filters, kernel_size=[5,5], strides=[2,2])(inputs)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2D(filters=2*n_filters, kernel_size=[5,5], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2D(filters=4*n_filters, kernel_size=[3,3], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2D(filters=6*n_filters, kernel_size=[3,3], strides=[1,1])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - "\n", - " hidden = Flatten(name='flatten')(hidden)\n", - "# hidden = Dense(128)(hidden)\n", - " \n", - " '''Encoder outputs:\n", - " y_logit: supervised class prediction\n", - " z_mean: means in the latent space\n", - " z_logsigma: standard deviations in the latent space'''\n", - " y_logit = Dense(1, activation=None, name='y_logit')(hidden)\n", - " z_mean = Dense(latent_dim, name='z_mean')(hidden)\n", - " z_logsigma = Dense(latent_dim, name='z_logsigma')(hidden)\n", - "\n", - " # use reparameterization trick to sample from the latent space\n", - " z = tf.keras.layers.Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_logsigma])\n", - "\n", - " # define the outputs that the encoder model should return\n", - " outputs = [y_logit, z_mean, z_logsigma, z]\n", - " # finalize the encoder model\n", - " encoder = tf.keras.Model(inputs=inputs, outputs=outputs, name='encoder')\n", - "\n", - " # get the shape of the final convolutional output (right before the flatten)\n", - " flatten_layer_idx = encoder.layers.index(encoder.get_layer('flatten'))\n", - " pre_flatten_shape = encoder.layers[flatten_layer_idx-1].get_output_at(0).shape[1:]\n", - " \n", - " return encoder, inputs, outputs, pre_flatten_shape" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "FlB-Gcot0gYw", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Similarly, we can define the decoder network, which takes as input the sampled latent variables, runs them through a series of deconvolutional layers, and outputs a reconstruction of the original input image:" - ] - }, - { - "metadata": { - "id": "JfWPHGrmyE7R", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''Define the decoder network for the DB-VAE'''\n", - "def make_face_decoder_network(pre_flatten_shape):\n", - " Conv2DTranspose = functools.partial(tf.keras.layers.Conv2DTranspose, padding='same', activation='relu')\n", - " BatchNormalization = tf.keras.layers.BatchNormalization\n", - " Flatten = tf.keras.layers.Flatten\n", - " Dense = functools.partial(tf.keras.layers.Dense, activation='relu')\n", - "\n", - " latent_inputs = tf.keras.layers.Input(shape=(latent_dim,))\n", - " \n", - "# hidden = Dense(128)(latent_inputs)\n", - " hidden = Dense(tf.reduce_prod(pre_flatten_shape))(latent_inputs)\n", - " hidden = tf.keras.layers.Reshape(pre_flatten_shape)(hidden)\n", - " \n", - " # series of deconvolutional layers with batch normalization\n", - " hidden = Conv2DTranspose(filters=4*n_filters, kernel_size=[3,3], strides=[1,1])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2DTranspose(filters=2*n_filters, kernel_size=[3,3], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2DTranspose(filters=1*n_filters, kernel_size=[5,5], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " \n", - " x_hat = Conv2DTranspose(filters=3, kernel_size=[5,5], strides=[2,2])(hidden)\n", - "\n", - " # instantiate decoder model\n", - " decoder = tf.keras.Model(inputs=latent_inputs, outputs=x_hat, name='decoder')\n", - " return decoder\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "yWCMu12w1BuD", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, call these functions to create the encoder and decoder!" - ] - }, - { - "metadata": { - "id": "dSFDcFBL13c3", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: call the functions you defined above to create the encoder and decoder networks'''\n", - "encoder, inputs, ouputs, pre_flatten_shape = # TODO\n", - "decoder = # TODO\n", - "\n", - "# initialize the models\n", - "encoder_output = encoder(inputs)\n", - "y_logit, z_mean, z_logsigma, z = encoder_output\n", - "reconstructed_inputs = decoder(z)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "QbRI5_rz2Myy", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Finally we can construct our network end-to-end." - ] - }, - { - "metadata": { - "id": "WITL88Fm2Z0a", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Construct the end to end vae\n", - "vae = tf.keras.Model(inputs, reconstructed_inputs)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "DjdyDDpc01ZZ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's visualize the architecture of the encoder to get a more concrete understanding of this network," - ] - }, - { - "metadata": { - "id": "7yKMwQU606ZR", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "util.display_model(encoder)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "M-clbYAj2waY", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As you can see, the encoder architecture is virtually identical to the CNN from earlier in this lab. Note the outputs of this model: `y_logit, z_mean, z_logsigma, z`. Think carefully about why each of these are outputted and their significance to the problem at hand.\n", - "\n" - ] - }, - { - "metadata": { - "id": "nbDNlslgQc5A", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Adaptive resampling for automated debiasing with DB-VAE\n", - "\n", - "So, how can we actually use DB-VAE to train a debiased facial detection classifier? Recall the DB-VAE architecture. As the input images are fed through the network, the encoder learns an estimate $\\mathcal{Q}(z|X)$ of the latent space. We want to increase the relative frequency of rare data by increased sampling of under-represented regions of the latent space. We can approximate $\\mathcal{Q}(z|X)$ using the frequency distributions of each of the learned latent variables, and then define the probability distribution of selecting a given datapoint $x$ based on this approximation. These probability distributions will be used during training to re-sample the data.\n", - "\n", - "You'll write a function to execute this update of the sampling probabilities, and then call this function within the DB-VAE training loop to actually debias the model. " - ] - }, - { - "metadata": { - "id": "Fej5FDu37cf7", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "First, we've defined a short helper function `get_latent_mu` that returns the latent variable means returned by the encoder after a batch of images is inputted to the network:" - ] - }, - { - "metadata": { - "id": "ewWbf7TE7wVc", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Function to return the means for an input image batch\n", - "def get_latent_mu(images, encoder, batch_size=1024):\n", - " N = images.shape[0]\n", - " mu = np.zeros((N, latent_dim))\n", - " for start_ind in xrange(0, N, batch_size):\n", - " end_ind = min(start_ind+batch_size, N+1)\n", - " batch = images[start_ind:end_ind]\n", - " batch = tf.convert_to_tensor(batch, dtype=tf.float32)/255.\n", - " _, batch_mu, _, _ = encoder(batch)\n", - " mu[start_ind:end_ind] = batch_mu\n", - " return mu" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "wn4yK3SC72bo", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, let's define the actual resampling algorithm `get_training_sample_probabilities`. Importantly note the argument `smoothing_fac`. This parameter tunes the degree of debiasing: for `smoothing_fac=0`, the re-sampled training set will tend towards falling uniformly over the latent space. " - ] - }, - { - "metadata": { - "id": "HiX9pmmC7_wn", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''Function that recomputes the sampling probabilities for images within a batch\n", - " based on how they distribute across the '''\n", - "def get_training_sample_probabilities(images, encoder, bins=10, smoothing_fac=0.0): \n", - " print \"Recomputing the sampling probabilities\"\n", - " \n", - " mu = get_latent_mu(images, encoder)\n", - " # sampling probabilities for the images\n", - " training_sample_p = np.zeros(mu.shape[0])\n", - " \n", - " # consider the distribution for each latent variable \n", - " for i in range(latent_dim):\n", - " \n", - " latent_distribution = mu[:,i]\n", - " '''TODO: generate a histogram of the latent distribution'''\n", - " hist_density, bin_edges = np.histogram('''TODO''', density=True, bins=bins)\n", - "\n", - " # find which latent bin every data sample falls in \n", - " # https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.digitize.html\n", - " bin_edges[0] = -float('inf')\n", - " bin_edges[-1] = float('inf')\n", - " bin_idx = np.digitize(latent_distribution, bin_edges)\n", - "\n", - " # smooth the density function (Eq. #4 in the DB-VAE paper)\n", - " hist_smoothed_density = hist_density + smoothing_fac\n", - " hist_smoothed_density = hist_smoothed_density / np.sum(hist_smoothed_density)\n", - "\n", - " p = 1.0/(hist_smoothed_density[bin_idx-1])\n", - " \n", - " # normalize all probabilities\n", - " p = p / np.sum(p)\n", - " \n", - " # update sampling probabilities \n", - " training_sample_p = np.maximum(p, training_sample_p)\n", - " \n", - " # final normalization\n", - " training_sample_p /= np.sum(training_sample_p)\n", - "\n", - " return training_sample_p" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "pF14fQkVUs-a", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now that we've defined the resampling update, we can train our DB-VAE model on the CelebA/ImageNet training data, and run the above operation to re-weight the importance of particular data points as we train the model. Remember again that we only want to debias for features relevant to *faces*, not the set of negative examples.\n", - "\n", - "Complete the code block below to execute the training loop!" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "9YR8U43FVZ_8", - "colab": {} - }, - "cell_type": "code", - "source": [ - "loss_history = []\n", - "optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)\n", - "\n", - "enable_debiasing = True\n", - "all_faces = loader.get_all_train_faces() # parameter from data loader\n", - "\n", - "for epoch in range(num_epochs):\n", - " \n", - " # progress message and bar\n", - " custom_msg = util.custom_progress_text(\"Epoch: %(epoch).0f Iter: %(idx).0f Class Loss: %(class_loss)2.2f Loss: %(loss)2.2f\")\n", - " bar = util.create_progress_bar(custom_msg)\n", - "\n", - " p_faces = None\n", - " if enable_debiasing: \n", - " # Recompute data sampling proabilities if debiasing is enabled\n", - " '''TODO: call the get_training_sample_probabilities function\n", - " to recompute the sampling probabilities when debiasing is enabled'''\n", - " p_faces = # TODO\n", - " \n", - " for idx in bar(range(loader.get_train_steps_per_epoch(batch_size))):\n", - " # load a batch of data\n", - " (x, y) = loader.get_batch(batch_size, p_pos=p_faces)\n", - " x = tf.convert_to_tensor(x, dtype=tf.float32)\n", - " y = tf.convert_to_tensor(y, dtype=tf.float32)\n", - " \n", - " # define GradientTape for automatic differentiation\n", - " with tf.GradientTape() as tape:\n", - " y_logit, mu, logsigma, z = encoder(x)\n", - " x_hat = decoder(z)\n", - " '''TODO: call the debiasing_loss_function to compute the loss'''\n", - " loss, class_loss = # TODO\n", - " \n", - " '''TODO: use the GradientTape.gradient method to compute the gradients\n", - " Hint: compute the gradient of the 'loss' with respect to the variables in the VAE\n", - " Hint: recall how this is done in the standard CNN training code block'''\n", - " grads = tape.gradient('''TODO''','''TODO''') # TODO\n", - " # apply gradients to variables\n", - " optimizer.apply_gradients(zip(grads, vae.variables),\n", - " global_step=tf.train.get_or_create_global_step())\n", - "\n", - " # track the losses\n", - " class_loss_value = class_loss.numpy().mean()\n", - " loss_value = loss.numpy().mean()\n", - " loss_history.append((class_loss_value, loss_value))\n", - " custom_msg.update_mapping(epoch=epoch, idx=idx, loss=loss_value, class_loss=class_loss_value)\n", - " \n", - " # plot the progress every 100 steps\n", - " if idx%100 == 0: \n", - " util.plot_sample(x,y,vae)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "uZBlWDPOVcHg", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Wonderful! Now we should have a trained and (hopefully!) debiased facial classification model, ready for evaluation!" - ] - }, - { - "metadata": { - "id": "Eo34xC7MbaiQ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.4 Evaluation on Pilot Parliaments Benchmark (PPB) Dataset\n", - "\n", - "Finally let's test our DB-VAE model on the[ PPB dataset](http://proceedings.mlr.press/v81/buolamwini18a/buolamwini18a.pdf). \n", - "\n", - "We'll evaluate both the overall accuracy of the DB-VAE as well as its accuracy on each the \"Dark Male\", \"Dark Female\", \"Light Male\", and \"Light Female\" demographics, and compare the performance of this debiased model against the biased CNN from earlier in the lab. \n", - "\n", - "Here are some example images from the PPB dataset.\n", - "![PPB Example Images](https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab2/img/PPB%20faces.png)" - ] - }, - { - "metadata": { - "id": "ruzxwzo2ko6N", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "To assess performance, we'll measure the classification accuracy of each model, which we define as the fraction of PPB faces detected. By comparing the accuracy of a model without debiasing and our DB-VAE model, we can get a sense of how effectively we were able to debias against features like skin tone and gender.\n", - "\n", - "Let's evaluate our debiased model on the PPB test dataset." - ] - }, - { - "metadata": { - "id": "bgK77aB9oDtX", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Evaluate on PPB dataset (takes ~4 minutes)\n", - "accuracy_debiased = []\n", - "for skin_color in ['lighter', 'darker']:\n", - " for gender in ['male', 'female']:\n", - " accuracy_debiased.append( ppb.evaluate([encoder], gender, skin_color, output_idx=0, from_logit=True)[0] )\n", - " print \n", - " print \"{} {}: {}\".format(gender, skin_color, accuracy_debiased[-1])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "F-3NzMB0oQtv", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can calculate the accuracies of our model on the whole PPB dataset as well as across the four demographics proposed and visualize our results comparing to the standard, biased CNN.\n" - ] - }, - { - "metadata": { - "id": "zzm-THVJkBjY", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "bar_width = 0.3\n", - "plt.bar(np.arange(4), standard_cnn_accuracy, width=bar_width)\n", - "plt.bar(np.arange(4)+bar_width, accuracy_debiased, width=bar_width)\n", - "plt.legend(('Standard Classifier','Debiased Classifier (DB-VAE)'))\n", - "plt.xticks(np.arange(4), ('LM', 'LF', 'DM', 'DF'))\n", - "plt.ylim(np.min([standard_cnn_accuracy,accuracy_debiased])-0.01,np.max([standard_cnn_accuracy,accuracy_debiased])+0.01)\n", - "plt.ylabel('Accuracy')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "rESoXRPQo_mq", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.5 Conclusion \n", - "\n", - "We encourage you to think about and maybe even address some questions raised by the approach and results outlined here:\n", - "\n", - "* How does the accuracy of the DB-VAE across the four demographics compare to that of the standard CNN? Do you find this result surprising in any way?\n", - "* In which applications (either related to facial detection or not!) would debiasing in this way be desired? Are there applications where you may not want to debias your model? \n", - "* Do you think it should be necessary for companies to demonstrate that their models, particularly in the context of tasks like facial detection, are not biased? If so, do you have thoughts on how this could be standardized and implemented?\n", - "* Do you have ideas for other ways to address issues of bias, particularly in terms of the training data?\n", - "\n", - "Hopefully this lab has shed some light on a few concepts, from vision based tasks, to VAEs, to algorithmic bias. We like to think it has, but we're biased ;). \n", - "\n", - "![Faces](https://media1.tenor.com/images/44e1f590924eca94fe86067a4cf44c72/tenor.gif?itemid=3394328)" - ] - } - ] -} \ No newline at end of file diff --git a/lab2/Part2_debiasing_solution.ipynb b/lab2/Part2_debiasing_solution.ipynb deleted file mode 100644 index a2f36dbc..00000000 --- a/lab2/Part2_debiasing_solution.ipynb +++ /dev/null @@ -1,1381 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Copy of Part2_debiasing_solution.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [ - "NDj7KBaW8Asz" - ], - "include_colab_link": true - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "metadata": { - "id": "Ag_e7xtTzT1W", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "\n", - "# Laboratory 2: Computer Vision\n", - "\n", - "# Part 2: Debiasing Facial Detection Systems\n", - "\n", - "In the second portion of the lab, we'll explore two prominent aspects of applied deep learning: facial detection and algorithmic bias. \n", - "\n", - "Deploying fair, unbiased AI systems is critical to their long-term acceptance. Consider the task of facial detection: given an image, is it an image of a face? [Recent work from the MIT Media Lab](http://proceedings.mlr.press/v81/buolamwini18a/buolamwini18a.pdf) showed that this seemingly simple, but extremely important, task is subject to extreme amounts of algorithmic bias among select demographics. [Another report](https://ieeexplore.ieee.org/document/6327355) analyzed the face detection system used by the US law enforcement and found that it had significantly lower accuracy among dark skinned women between the age of 18-30 years old. \n", - "\n", - "Run the next code block for a short video from Google that explores how and why it's important to consider bias when thinking about machine learning:" - ] - }, - { - "metadata": { - "id": "XQh5HZfbupFF", - "colab_type": "code", - "outputId": "4a6df36f-b4b5-442c-b735-0cce3ad31e71", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 322 - } - }, - "cell_type": "code", - "source": [ - "from IPython.display import YouTubeVideo\n", - "YouTubeVideo('59bMh59JQDo')" - ], - "execution_count": 1, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/html": [ - "\n", - " \n", - " " - ], - "image/jpeg": "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\n1I6b0kle7O7xXaqzfNlFwRpVVRUQQVtaVfNnIRTERydJF0gMkvXILe0va7dzMtufQ6SSrCvKmiKr\nhHbjqMethxcf0LkRM12uzE9rXVHwbxmWp6jqdAWnVNJ92S7YzTZY1A7hx5YkDbJPhmzXe7Ez3XWu\n6tOa1Hufnx3OT6PUUNNLSbpJx5d1w07yys4q1Q6CgqKuOmOrOAMhhj8R9TD6rO+LXyd2Z3sL8k+F\ndUOvoKerlppKQ5wzKE+og6nHxEzOTPbJrsz2JuTKxTA8ur/u9VUp7rvHg7N0elt25u91viuK492a\neq6xS0W0VXVwU2+Yww78oQ7speEI83bIvgy31znG3B+n65HBHqMJTDTGUkeJnD4hEZAIgdsgJhG/\n+VrOyttZmmjpqiSkjGaojgmKmikLbjlnGMihAiu2IubM17t397d6tm8nGpTTluS24qufeP2KjjDh\nybUZqKaLUZ6DsU5TSDFchnEiAsSHNmybBxZyZ2tIXJ+57rVDlGCYqaOOSoGKYoAkLbjOcYy2QkL1\nQc8Wf4OqX7PK7U6nTgm1qmjpKsjmEooxxHbEvMmUeZbZO1+WT91+V7N0Jlj1ErvVc4pPhcfkz0dO\nD3aiTTlTd3eFSw+Dmfs4q9XnoNzXqaGkq9+QRCEh64MRKMyEJCaMruY2yfkDP6Vedug7R2Xfi7Rh\nu7OYb+34c9q+WH9rLU4e4iotUjObTqmKrCMyhkKHLpkH1SyZnxdnZ29Ds92d1phwjSfexa1jN2sg\nw8fmvwtjPC3j22Ye+3ptfmsPkktufN+Dr+jjpuHyk3h7Xh2+18Y8v+RscZajUUWnVVTRUhVtRFFl\nDTjkRGWQj4Q6pMWdysPN8LNzdLhPUqit06lqaukKgqJospqeTLKIsiHwl1DkzMVi5sxMz82dW5Mt\nEtTp+09k3o+0E2e162OOX6ZWa9r3tztZWlOMa3Ou35M46U5T3RbarisffyZWqgKTZ3o93Hc2sx3N\nv8+3e+Pxsq/ijVJaKmKeGmKpITjHAb9Il65Ys74tZm7vWZZB0Gn7f944l2jDG+RYfh7eWHtwZm9n\nwvzVkzLKtWcJRbUXlRazjs8rn0dV6cJRkvksWnjPdY7ezBQzFLDFIUZRlIEchRF+IBSCJYF/Uzvb\n+yjp2oQVOfZ545dksZNtxLEurxf7P8Hs6zxSgREIyCTxvjIwkJEBflIfV/utbRdFpaLd7NFt7z7k\nnU5fmxYcnfEGyezNya7qW53FRpr/AHPvx2rHPJWoVLdaf+1dvz344KGbhivLiENW+9pRoI4dktNE\njGMi2Tj6hzwIXM9y7te4s3czWuOM6utg06qm0umGrrYwHs0BeEiKQRIsbtuYg5Ha7Xwt6VbWTda7\nfBxr6dRUlFtbrd3m34uyr4TqauagpZtTgjpq2SISqYY/CEn9PN8bti7td7O7td7LXbh/HVPvLfk6\nosNn1fBh4r+D1rW7+d1scUTVcdIZUEYy1GUeLFj4ch3CESdmIrfH/wBFuaacpQxFOIxzlFGUoD1C\nM2I7gjzfpZ7+l/7rnnGGpNQkm9tSTzV5XPn0duip6WluUubi+LeFdr35NlnUlynC9FrEep6pNqNX\nBNQTGP3XDCPVBGJH4vNs4lg4M9ye7s78m7+nXSmculqOatprnn7/ANTIhY1NlY0AlF03SsoYE6Sd\nknUgd0XUE2VQTd1FJ3SYkFgykyxssjIQNDpkouhInUHJZFjkVgRukhSZkIBmWQEhZSQkV00WTZVA\n2UhSFc/x9pVfW0wRaZX9glGaOSQ8jHOMRLo3AZyHrcSt3PjZ+9aacVKSTde2Za2o4Qcoxcmuyq3+\nuC31as7NTT1O3JNsRSzbUf4h7cZSYR/1Pa391XcEcQjq1AFaMElMMhSDhIQlltljlHILNuA78u5u\nbP7FdRMQiORZFiORY45F6xY+rd7vZSU3FRarPkpWo9RT3VGsxpZfm/Xghn1EOQ5D4hy6hy8OQ943\nQzKg0nhKnpNUq9WjmnKatHGQJDEoR6gIsRtcucY2yd7M7s3LufH2hVWp0gwUlfJp0ozRzFLGRjnG\nImJAW0bFjchLv7wb9Wtsg2kpY7trgr1tVacpOHyV0k1ldsuqsv0O6hTRkMYCUhSEICJGXiMhHEjL\nH1nfn/dZVk0dKdoFFSUSQkBTd1BDqoNDU9fpKSenpqmpjhmqyxpgLLIyyx9VrR3d2FnJ2Z3ezc1k\n1HRqSpmhnqaaKWakLKmMwyKIsmK4l+os/PudmfvWDUtBpKuenqammjlmpCypjLLoLIS8IuzSWdmJ\nsmeztdualxRBVzUU8OnTx01VIOMMsg5CBZDl6HxuDEN7PbK9nstXCEtq/W+OTnhq62k5S7L+Hbe5\nqsp8K3lGfXhqCpKgaIo46ooZOzEf4Yz4ltuXJ2xvbvZ/0fuVfwQGoDQRDqxBJViUmZBh1R7j7ee0\n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\nffUMEPa5qTYmGfKEciLEcfa2Jte7Pzs/odX9VUBDHuTShCA45HKbAI+qORm7NzRwhGCaec2q4/7L\nR1dbU1XFp0klF3d+kuVRUaNxZSVtfV6dDvb1B+NkGMZYybcm3Jd8sTdme7N8Ls11ewwiP4YiOTkR\nYiI5EXiIsfET+1YYaaIZCmjjhE5sdyWMAGSXHw7kgteS3ou7qu0jieirauooqafcqKTLfDExEcS2\n5MZCbGTE7C9n5O7K8kpZ006SV9zCEnptLXcdzbUe1+ErfKXJocE8Xhq01bCFJU03YJRid58esiKQ\ncenwSttvdn7sm5q7rtKp6iaKaaKOSWAsojK/R1Ze2xWdmdr3s7XW4uYmodVfXIqmOti+6mhwkpOe\nbntnzx23Yn3HAr5NZhtb28UofBKS3Z8Lz49HrJxnNy0300o2k23dLKTq7ln0dOpKj450I9U06ooI\nauagOfbxqIcsg25AkxIRNnICxxdmJuROt3h3TioqKlpJJ5KkqaGOEp5vxJSjHEjkyd3ye3pd3+L9\n63Tdnn75b9tYrm+/iuSwZcoXHNP/AMQf8PbFT2jZ397ENj8HfxLnljg1r2td7KXC3DVXRanqVbPq\n09bBXnlBSSCW3SjuEQiORu3Sz4NgLXYWvd7W6fEcsunLw5etj4sf8vpsoyzO5zimvjnN07Sf3xZX\nU2h0sdXLXxxkNRKOJlkWPq5EMfcJPgN/0+L3wcUSagPZ/u6OI8pf8Tnj0h04+J/D4r43fk1lDitt\nSxg+7SiEs/P7uHg5Y+NvB4r48+6ytq2qCCE5pS2whEpJC6ukR8XSPP8A2XG4xe6EU4LlyVJO8tp/\nuemnJOM5NTfCTt1WEmv2Mzsk0gl62WL4lj1Yv7P1WppGpwVcLT00m5EWWJYkPUJYkJCVnHmtDhnh\n2LTiqCikmk7SYyFuEPLHPw4+Iut7u/N7N7Ft1ZNx2JOL5d8KsV5sz2JKSm2pLhV7zfii6dJDIutz\nAE3ZF0kAIQhADpOlkmgIEyiLKZMoKxBsCSCSZ02dVBJRdSUSViRM65/hLhKl0mSqkpCmyrZRmk3j\nEhDHMhCPFm6WeQ+ZXfnzd7K/SMchIciHISHIfEOXrD/U3epjqSScU8Pky1NGMmpyjco3T8WqwTSd\nc99n/Dkuk0h001bJXkU0kwnIJDgJCA4CJG7+q5Pztc35e3oSUziotqLteSNGc5wTnHa+6tOvysEb\n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\nyyZx03NS5aWH4vlHuV3WK68PP/F9xL7v4f8AltQ+vS8r7iX+Q0D5av8Ar1boyL9RHuJDOvDvlfcS\n/wAhoHy1f9ejyvuJf5DQPlq/69OjIdRHuRnU2Xhpv4wOJfd3D3y2ofXo8sHiX3dw98tqH7gnRkOo\nj3OosvDflg8S+7uHvltQ+vS8sHiX3dw98tqH7gnRkOojzohCF1GAIQhACEIQAhCEAIQhACEIQAhC\nEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQA\nhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEI\nQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhAC\nEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQh\nACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQH//2Q==\n", - "text/plain": [ - "" - ] - }, - "metadata": { - "tags": [] - }, - "execution_count": 1 - } - ] - }, - { - "metadata": { - "id": "3Ezfc6Yv6IhI", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "In this lab, we'll investigate [one recently published approach](http://introtodeeplearning.com/AIES_2019_Algorithmic_Bias.pdf) to addressing algorithmic bias. We'll build a facial detection model that learns the *latent variables* underlying face image datasets and uses this to adaptively re-sample the training data, thus mitigating any biases that may be present in order to train a *debiased* model.\n", - "\n", - "Let's get started by installing the relevant dependencies:" - ] - }, - { - "metadata": { - "id": "E46sWVKK6LP9", - "colab_type": "code", - "outputId": "7fb31396-0d46-4446-dada-87d4f9f9f26f", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 69 - } - }, - "cell_type": "code", - "source": [ - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "\n", - "import functools\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pdb\n", - "\n", - "# Download the class repository\n", - "! git clone https://github.com/aamini/introtodeeplearning_labs.git > /dev/null 2>&1\n", - "% cd introtodeeplearning_labs \n", - "! git pull\n", - "% cd .. \n", - "\n", - "# Import the necessary class-specific utility files for this lab\n", - "import introtodeeplearning_labs as util" - ], - "execution_count": 2, - "outputs": [ - { - "output_type": "stream", - "text": [ - "/content/introtodeeplearning_labs\n", - "Already up to date.\n", - "/content\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "id": "V0e77oOM3udR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.1 Datasets\n", - "\n", - "We'll be using three datasets in this lab. In order to train our facial detection models, we'll need a dataset of positive examples (i.e., of faces) and a dataset of negative examples (i.e., of things that are not faces). We'll use these data to train our models to classify images as either faces or not faces. Finally, we'll need a test dataset of face images. Since we're concerned about the potential *bias* of our learned models against certain demographics, it's important that the test dataset we use has equal representation across the demographics or features of interest. In this lab, we'll consider skin tone and gender. \n", - "\n", - "1. **Positive training data**: [CelebA Dataset](http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html). A large-scale (over 200K images) of celebrity faces. \n", - "2. **Negative training data**: [ImageNet](http://www.image-net.org/). Many images across many different categories. We'll take negative examples from a variety of non-human categories. \n", - "3. **Test data**: [Pilot Parliaments Benchmark](http://proceedings.mlr.press/v81/buolamwini18a/buolamwini18a.pdf) (PPB). The PPB dataset consists of images of 1270 male and female parliamentarians from various African and European countries and exhibits parity in both skin tone and gender. The gender of each face is annotated with the sex-based \"Male'' and \"Female'' labels. Skin tone annotations are based on the Fitzpatrick skin type classification system, with each image labeled as \"Lighter'' or \"Darker''.\n", - "\n", - "Let's begin by importing these datasets: " - ] - }, - { - "metadata": { - "id": "RWXaaIWy6jVw", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Get the training data: both images from CelebA and ImageNet\n", - "path_to_training_data = tf.keras.utils.get_file('train_face.h5', 'https://www.dropbox.com/s/l5iqduhe0gwxumq/train_face.h5?dl=1')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "bAY6pDc_Zljt", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "This directly downloads the raw data. We've written two classes that do a bit of data pre-processing and import the results in a usable format: `TrainingDatasetLoader` for the training data and `PPBFaceEvaluator` for the test data.\n", - "\n", - "Let's create a `TrainingDatasetLoader` and use it to take a look at the training data." - ] - }, - { - "metadata": { - "id": "UX-eUcEoazBm", - "colab_type": "code", - "outputId": "f91666a3-e67e-4213-e313-e339b6cf4a1f", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 52 - } - }, - "cell_type": "code", - "source": [ - "# Instantiate a TrainingDatasetLoader using the downloaded dataset\n", - "loader = util.TrainingDatasetLoader(path_to_training_data)" - ], - "execution_count": 4, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Opening /root/.keras/datasets/train_face.h5\n", - "Loading data into memory...\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "id": "yIE321rxa_b3", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can look at the size of the training dataset and grab a batch of size 100:" - ] - }, - { - "metadata": { - "id": "DjPSjZZ_bGqe", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "number_of_training_examples = loader.get_train_size()\n", - "(images, labels) = loader.get_batch(100)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "sxtkJoqF6oH1", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Play around with displaying images to get a sense of what the training data actually looks like!" - ] - }, - { - "metadata": { - "id": "Jg17jzwtbxDA", - "colab_type": "code", - "outputId": "1e0c923e-f1e5-4ac9-b506-064a0d11568e", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 165 - } - }, - "cell_type": "code", - "source": [ - "#@title Change the sliders to look at positive and negative training examples! { run: \"auto\" }\n", - "\n", - "face_images = images[np.where(labels==1)[0]]\n", - "not_face_images = images[np.where(labels==0)[0]]\n", - "\n", - "idx_face = 20 #@param {type:\"slider\", min:0, max:50, step:1}\n", - "idx_not_face = 11 #@param {type:\"slider\", min:0, max:50, step:1}\n", - "\n", - "plt.figure(figsize=(4,2))\n", - "plt.subplot(1, 2, 1)\n", - "plt.imshow(face_images[idx_face])\n", - "plt.title(\"Face\")\n", - "plt.grid(False)\n", - "\n", - "plt.subplot(1, 2, 2)\n", - "plt.imshow(not_face_images[idx_not_face])\n", - "plt.title(\"Not Face\")\n", - "plt.grid(False)" - ], - "execution_count": 6, - "outputs": [ - { - "output_type": "display_data", - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "metadata": { - "id": "kjuaEdLzb4pP", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also create a `PPBFaceEvaluator` instance for the PPB dataset and display some example images. We'll use this dataset later on in the evaluation step." - ] - }, - { - "metadata": { - "id": "4B4egQZY6wEt", - "colab_type": "code", - "outputId": "5d322438-3add-4333-e05d-5384c8d46700", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 351 - } - }, - "cell_type": "code", - "source": [ - "#@title { run: \"auto\" }\n", - "\n", - "ppb = util.PPBFaceEvaluator(skip=4) # create the dataset handler\n", - "\n", - "gender = \"male\" #@param [\"male\", \"female\"]\n", - "skin_color = \"darker\" #@param [\"lighter\", \"darker\"]\n", - "\n", - "img = ppb.get_sample_faces_from_demographic(gender, skin_color)\n", - "plt.imshow(img)\n", - "plt.grid(False)" - ], - "execution_count": 7, - "outputs": [ - { - "output_type": "display_data", - "data": { - "image/png": "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\nRK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "metadata": { - "id": "NDj7KBaW8Asz", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Thinking about bias\n", - "\n", - "Remember we'll be training our facial detection classifiers on the large, well-curated CelebA dataset (and ImageNet), and then evaluating their accuracy by testing them on the PPB dataset. Our goal is to build a model that trains on CelebA *and* achieves high classification accuracy on PPB across all demographics, and to thus show that this model does not suffer from any hidden bias. \n", - "\n", - "What exactly do we mean when we say a classifier is biased? In order to formalize this, we'll need to think about [*latent variables*](https://en.wikipedia.org/wiki/Latent_variable), variables that define a dataset but are not strictly observed. As defined in the generative modeling lecture, we'll use the term *latent space* to refer to the probability distributions of the aforementioned latent variables. Putting these ideas together, we consider a classifier *biased* if its classification decision changes after it sees some additional latent features. This notion of bias may be helpful to keep in mind throughout the rest of the lab. " - ] - }, - { - "metadata": { - "id": "AIFDvU4w8OIH", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.2 CNN for facial detection \n", - "\n", - "First, we'll define and train a CNN on the facial classification task, and evaluate its accuracy on the PPB dataset. Later, we'll evaluate the performance of our debiased models against this baseline CNN. The CNN model has a relatively standard architecture consisting of a series of convolutional layers with batch normalization followed by two fully connected layers to flatten the convolution output and generate a class prediction. \n", - "\n", - "### Define and train the CNN model\n", - "\n", - "Like we did in the first part of the lab, we'll define our CNN model, and then train on the CelebA and ImageNet datasets using the `tf.GradientTape` class and the `tf.GradientTape.gradient` method." - ] - }, - { - "metadata": { - "id": "82EVTAAW7B_X", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "n_outputs = 1 # number of outputs (i.e., face or not face)\n", - "n_filters = 12 # base number of convolutional filters\n", - "\n", - "'''Function to define a standard CNN model'''\n", - "def make_standard_classifier():\n", - " Conv2D = functools.partial(tf.keras.layers.Conv2D, padding='same', activation='relu')\n", - " BatchNormalization = tf.keras.layers.BatchNormalization\n", - " Flatten = tf.keras.layers.Flatten\n", - " Dense = functools.partial(tf.keras.layers.Dense, activation='relu')\n", - "\n", - " model = tf.keras.Sequential([\n", - " Conv2D(filters=1*n_filters, kernel_size=[5,5], strides=[2,2], input_shape=(64,64,3)),\n", - " BatchNormalization(),\n", - " \n", - " Conv2D(filters=2*n_filters, kernel_size=[5,5], strides=[2,2]),\n", - " BatchNormalization(),\n", - "\n", - " Conv2D(filters=4*n_filters, kernel_size=[3,3], strides=[2,2]),\n", - " BatchNormalization(),\n", - "\n", - " Conv2D(filters=6*n_filters, kernel_size=[3,3], strides=[1,1]),\n", - " BatchNormalization(),\n", - "\n", - " Flatten(),\n", - " Dense(1, activation=None),\n", - " tf.keras.layers.Dropout(0.5)\n", - " ])\n", - " return model\n", - " \n", - "standard_classifier = make_standard_classifier()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "c-eWf3l_lCri", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now let's train the standard CNN!" - ] - }, - { - "metadata": { - "id": "jmOBzRgplB-n", - "colab_type": "code", - "outputId": "f024e7aa-7e90-480a-8266-49c426875acc", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 695 - } - }, - "cell_type": "code", - "source": [ - "batch_size = 36\n", - "num_epochs = 10 # keep small to run faster\n", - "learning_rate = 1e-3\n", - "\n", - "optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) # define our optimizer\n", - "loss_history = util.LossHistory(smoothing_factor=0.99) # to record the evolution of the loss\n", - "plotter = util.PeriodicPlotter(sec=2, scale='semilogy')\n", - "\n", - "# The training loop!\n", - "for epoch in range(num_epochs):\n", - " \n", - " custom_msg = util.custom_progress_text(\"Epoch: %(epoch).0f Loss: %(loss)2.2f\")\n", - " bar = util.create_progress_bar(custom_msg)\n", - " \n", - " for idx in bar(range(loader.get_train_size()//batch_size)):\n", - " # First grab a batch of training data and convert the input images to tensors\n", - " x, y = loader.get_batch(batch_size)\n", - " x = tf.convert_to_tensor(x, dtype=tf.float32)\n", - " y = tf.convert_to_tensor(y, dtype=tf.float32)\n", - " \n", - " # GradientTape to record differentiation operations\n", - " with tf.GradientTape() as tape:\n", - " logits = standard_classifier(x) # feed the images into the model\n", - " loss_value = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=logits) # compute the loss\n", - "\n", - " custom_msg.update_mapping(epoch=epoch, loss=loss_value.numpy().mean())\n", - " # Backpropagation\n", - " grads = tape.gradient(loss_value, standard_classifier.variables)\n", - " optimizer.apply_gradients(zip(grads, standard_classifier.variables), global_step=tf.train.get_or_create_global_step())\n", - "\n", - " loss_history.append(loss_value.numpy().mean()) \n", - " plotter.plot(loss_history.get())" - ], - "execution_count": 9, - "outputs": [ - { - "output_type": "display_data", - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - }, - { - "output_type": "stream", - "text": [ - "100%|######################################|Time: 0:00:10 Epoch: 9 Loss: 0.00\n" - ], - "name": "stderr" - }, - { - "output_type": "display_data", - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - } - } - ] - }, - { - "metadata": { - "id": "AKMdWVHeCxj8", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Evaluate performance of the standard CNN\n", - "\n", - "Next, let's evaluate the classification performance of our CelebA-trained standard CNN on the training dataset and the PPB dataset. For the PPB data, we'll look at the classification accuracy across four different demographics defined in PPB: dark-skinned male, dark-skinned female, light-skinned male, and light-skinned female.\n" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "35-PDgjdWk6_", - "outputId": "1e93ef65-e63a-43b6-ebbf-391c711d7635", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 35 - } - }, - "cell_type": "code", - "source": [ - "# Evaluate on a subset of CelebA+Imagenet\n", - "(batch_x, batch_y) = loader.get_batch(5000)\n", - "y_pred_standard = tf.round(tf.nn.sigmoid(standard_classifier.predict(batch_x)))\n", - "acc_standard = tf.reduce_mean(tf.cast(tf.equal(batch_y, y_pred_standard), tf.float32))\n", - "print \"Standard CNN accuracy on (potentially biased) training set: {:.4f}\".format(acc_standard.numpy())" - ], - "execution_count": 10, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Standard CNN accuracy on (potentially biased) training set: 0.9990\n" - ], - "name": "stdout" - } - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "vfDD8ztGWk6x", - "outputId": "e23992a8-6a9d-4222-9cf3-802d8c4b2ff2", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 138 - } - }, - "cell_type": "code", - "source": [ - "# Evaluate on PPB dataset (takes ~3 minutes)\n", - "standard_cnn_accuracy = []\n", - "for skin_color in ['lighter', 'darker']:\n", - " for gender in ['male', 'female']:\n", - " standard_cnn_accuracy.append( ppb.evaluate([standard_classifier], gender, skin_color, from_logit=True)[0] )\n", - " print \n", - " print \"{} {}: {}\".format(gender, skin_color, standard_cnn_accuracy[-1])" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "stream", - "text": [ - "100% (97 of 97) |########################| Elapsed Time: 0:01:18 Time: 0:01:18\n", - "N/A% (0 of 72) | | Elapsed Time: 0:00:00 ETA: --:--:--" - ], - "name": "stderr" - }, - { - "output_type": "stream", - "text": [ - "\n", - "male lighter: 1.0\n" - ], - "name": "stdout" - }, - { - "output_type": "stream", - "text": [ - "100% (72 of 72) |########################| Elapsed Time: 0:00:57 Time: 0:00:57\n", - "N/A% (0 of 78) | | Elapsed Time: 0:00:00 ETA: --:--:--" - ], - "name": "stderr" - }, - { - "output_type": "stream", - "text": [ - "\n", - "female lighter: 1.0\n" - ], - "name": "stdout" - }, - { - "output_type": "stream", - "text": [ - " 88% (69 of 78) |##################### | Elapsed Time: 0:00:50 ETA: 0:00:07" - ], - "name": "stderr" - } - ] - }, - { - "metadata": { - "id": "SaPPGYdPmcCi", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "plt.bar(range(4), standard_cnn_accuracy)\n", - "plt.xticks(range(4), ('LM', 'LF', 'DM', 'DF'))\n", - "plt.ylim(np.min(standard_cnn_accuracy)-0.1,np.max(standard_cnn_accuracy)+0.1)\n", - "plt.ylabel('Accuracy')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "j0Cvvt90DoAm", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Take a look at the accuracies for this first model across these four groups. What do you observe? Would you consider this model biased or unbiased, and why? " - ] - }, - { - "metadata": { - "id": "nLemS7dqECsI", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.3 Variational autoencoder (VAE) for learning latent structure\n", - "\n", - "As you saw, the accuracy of the CNN varies across the four demographics we looked at. To think about why this may be, consider the dataset the model was trained on, CelebA. If certain features, such as dark skin or hats, are *rare* in CelebA, the model may end up biased against these as a result of training with a biased dataset. That is to say, its classification accuracy will be worse on faces that have under-represented features, such as dark-skinned faces or faces with hats, relevative to faces have features that are well-represented in the training data! This is a problem. \n", - "\n", - "Our goal is to train a *debiased* version of this classifier -- one that accounts for potential disparities in feature representation within the training data. Specifically, to build a debiased facial classifier, we'll train a model that learns a representation of the underlying latent space to the face training data. The model then uses this information to mitigate unwanted biases by sampling faces with rare features, like dark skin or hats, *more frequently* during training. The key design requirement for our model is that it can learn an *encoding* of the latent features in the face data in an entirely *unsupervised* way. To achieve this, we'll turn to variational autoencoders (VAEs).\n", - "\n", - "![The concept of a VAE](http://kvfrans.com/content/images/2016/08/vae.jpg)\n", - "\n", - "As shown in the schematic above, VAEs rely on an encoder-decoder structure to learn a latent representation of the input data. In the context of computer vision, the encoder network takes in input images, encodes them into a series of variables defined by a mean and standard deviation, and then draws from the distributions defined by these parameters to generate a set of sampled latent variables. The decoder network then \"decodes\" these variables to generate a reconstruction of the original image, which is used during training to help the model identify which latent variables are important to learn. \n", - "\n", - "Let's formalize two key aspects of the VAE model and define relevant functions for each.\n" - ] - }, - { - "metadata": { - "id": "KmbXKtcPkTXA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Understanding VAEs: loss function\n", - "\n", - "In practice, how can we train a VAE? In doing the reparameterization above, we constrain the means and standard deviations to approximately follow a unit Gaussian. Recall that these are learned parameters, and therefore must factor into the loss computation, and that the decoder portion of the VAE is using these parameters to output a reconstruction that should closely match the input image, which also must factor into the loss. What this means is that we'll have two terms in our VAE loss function:\n", - "\n", - "1. **Latent loss ($L_{KL}$)**: measures how closely the learned latent variables match a unit Gaussian and is defined by the Kullback-Leibler (KL) divergence. Note that the reparameterization trick is what makes this loss function differentiable!\n", - "2. **Reconstruction loss ($L_{x}{(x,\\hat{x})}$)**: measures how accurately the reconstructed outputs match the input and is given by the $L^2$ norm of the input image and its reconstructed output. \n", - "\n", - "The equations for both of these losses are provided below:\n", - "\n", - "$$ L_{KL}(\\mu, \\sigma) = \\frac{1}{2}\\sum\\limits_{j=0}^{k-1}\\small{(\\sigma_j + \\mu_j^2 - 1 - \\log{\\sigma_j})} $$\n", - "\n", - "$$ L_{x}{(x,\\hat{x})} = ||x-\\hat{x}||_2 $$ \n", - "\n", - "Thus for the VAE loss we have: \n", - "\n", - "$$ L_{VAE} = c\\cdot L_{KL} + L_{x}{(x,\\hat{x})} $$\n", - "\n", - "where $c$ is a weighting coefficient used for regularization. \n", - "\n", - "Now we're ready to define our VAE loss function:" - ] - }, - { - "metadata": { - "id": "S00ASo1ImSuh", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Function to calculate VAE loss given an input x, reconstructed output x_pred, \n", - "# encoded means mu, encoded log of standard deviation logsigma, and weight parameter for the latent loss\n", - "def vae_loss_function(x, x_pred, mu, logsigma, kl_weight=0.0005):\n", - " '''TODO: Define the latent loss'''\n", - " latent_loss = 0.5 * tf.reduce_sum(tf.exp(logsigma) + tf.square(mu) - 1.0 - logsigma, axis=1) # TODO\n", - " '''TODO: Define the reconstruction loss. Hint: you'll need to use tf.reduce_mean'''\n", - " reconstruction_loss = tf.reduce_mean((x-x_pred)**2, axis=(1,2,3)) # TODO\n", - " '''TODO: Define the VAE loss'''\n", - " vae_loss = kl_weight * latent_loss + reconstruction_loss\n", - " return vae_loss" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "E8mpb3pJorpu", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Great! Now that we have a more concrete sense of how VAEs work, let's explore how we can leverage this network structure to train a *debiased* facial classifier." - ] - }, - { - "metadata": { - "id": "DqtQH4S5fO8F", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Understanding VAEs: reparameterization \n", - "\n", - "As you may recall from lecture, VAEs use a \"reparameterization trick\" for sampling learned latent variables. Instead of the VAE encoder generating a single vector of real numbers for each latent variable, it generates a vector of means and a vector of standard deviations that are constrained to roughly follow Gaussian distributions. We then sample from the standard deviations and add back the mean to output this as our sampled latent vector. Formalizing this for a latent variable $z$ where we sample $\\epsilon \\sim \\mathcal{N}(0,(I))$ we have: \n", - "\n", - "$$ z = \\mathbb{\\mu} + e^{\\left(\\frac{1}{2} \\cdot \\log{\\Sigma}\\right)}\\circ \\epsilon $$\n", - "\n", - "where $\\mu$ is the mean and $\\Sigma$ is the covariance matrix. This is useful because it will let us neatly define the loss function for the VAE, generate randomly sampled latent variables, achieve improved network generalization, **and** make our complete VAE network differentiable so that it can be trained via backpropagation. Quite powerful!\n", - "\n", - "Let's define a function to implement the VAE sampling operation:" - ] - }, - { - "metadata": { - "id": "cT6PGdNajl3K", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "\"\"\"Reparameterization trick by sampling from an isotropic unit Gaussian.\n", - "# Arguments\n", - " args (tensor): mean and log of standard deviation of latent distribution (Q(z|X))\n", - "# Returns\n", - " z (tensor): sampled latent vector\n", - "\"\"\"\n", - "def sampling(args):\n", - " z_mean, z_logsigma = args\n", - " batch = z_mean.shape[0]\n", - " dim = z_mean.shape[1]\n", - " \n", - " # by default, random_normal has mean=0 and std=1.0\n", - " epsilon = tf.random_normal(shape=(batch, dim))\n", - " '''TODO: Define the reparameterization computation!'''\n", - " return z_mean + tf.math.exp(0.5 * z_logsigma) * epsilon # TODO" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "qtHEYI9KNn0A", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.4 Debiasing variational autoencoder (DB-VAE) for facial detection\n", - "\n", - "Now, we'll use the general idea behind the VAE architecture to build a model, termed a *debiasing variational autoencoder* or DB-VAE, to mitigate (potentially) unknown biases present within the training idea. We'll train our DB-VAE model on the facial detection task, run the debiasing operation during training, evaluate on the PPB dataset, and compare its accuracy to our original, biased CNN model. \n", - "\n", - "### The DB-VAE model\n", - "\n", - "The key idea behind this debiasing approach is to use the latent variables learned via a VAE to adaptively re-sample the CelebA data during training. Specifically, we will alter the probability that a given image is used during training based on how often its latent features appear in the dataset. So, faces with rarer features (like dark skin, sunglasses, or hats) should become more likely to be sampled during training, while the sampling probability for faces with features that are over-represented in the training dataset should decrease (relative to uniform random sampling across the training data). \n", - "\n", - "A general schematic of the DB-VAE approach is shown here:\n", - "\n", - "![DB-VAE](https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab2/img/DB-VAE.png)" - ] - }, - { - "metadata": { - "id": "ziA75SN-UxxO", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Recall that we want to apply our DB-VAE to a *supervised classification* problem -- the facial detection task. Importantly, note how the encoder portion in the DB-VAE architecture also outputs a single supervised variable, $z_o$, corresponding to the class prediction -- face or not face. Usually, VAEs are not trained to output any supervised variables (such as a class prediction)! This is another key distinction between the DB-VAE and a traditional VAE. \n", - "\n", - "Keep in mind that we only want to learn the latent representation of *faces*, as that's what we're ultimately debiasing against, even though we are training a model on a binary classification problem. We'll need to ensure that, **for faces**, our DB-VAE model both learns a representation of the unsupervised latent variables, captured by the distribution $q_\\phi(z|x)$, **and** outputs a supervised class prediction $z_o$, but that, **for negative examples**, it only outputs a class prediction $z_o$." - ] - }, - { - "metadata": { - "id": "XggIKYPRtOZR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Defining the DB-VAE loss function\n", - "\n", - "This means we'll need to be a bit clever about the loss function for the DB-VAE. The form of the loss will depend on whether it's a face image or a non-face image that's being considered. \n", - "\n", - "For **face images**, our loss function will have two components:\n", - "\n", - "\n", - "1. **VAE loss ($L_{VAE}$)**: consists of the latent loss and the reconstruction loss.\n", - "2. **Classification loss ($L_y(y,\\hat{y})$)**: standard cross-entropy loss for a binary classification problem. \n", - "\n", - "In contrast, for images of non-faces, our loss function is solely the classification loss. \n", - "\n", - "We can write a single expression for the loss by defining an indicator variable $\\mathcal{I}_f$which reflects which training data are images of faces ($\\mathcal{I}_f(x) = 1$ ) and which are images of non-faces ($\\mathcal{I}_f(x) = 0$). Using this, we obtain:\n", - "\n", - "$$L_{total} = L_y(y,\\hat{y}) + \\mathcal{I}_f(x)\\Big[L_{VAE}\\Big]$$\n", - "\n", - "Let's write a function to define the DB-VAE loss function:\n", - "\n" - ] - }, - { - "metadata": { - "id": "VjieDs8Ovcqs", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Loss function for DB-VAE\n", - "def debiasing_loss_function(x, x_pred, y, y_logit, mu, logsigma):\n", - "\n", - " '''TODO: call the relevant function to obtain VAE loss'''\n", - " vae_loss = vae_loss_function(x, x_pred, mu, logsigma) # TODO\n", - " '''TODO: define the classification loss'''\n", - " classification_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=y_logit) # TODO\n", - " \n", - " # Use the training data labels to create variable face_mask\n", - " face_mask = tf.cast(tf.equal(y, 1), tf.float32)\n", - " \n", - " '''TODO: define the DB-VAE total loss! Hint: think about the dimensionality of your output.'''\n", - " total_loss = tf.reduce_mean(\n", - " classification_loss + \n", - " face_mask * vae_loss\n", - " )\n", - " \n", - " return total_loss, classification_loss" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "YIu_2LzNWwWY", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### DB-VAE architecture\n", - "\n", - "Now we're ready to define the DB-VAE architecture. First, let's define some key parameters for our model: the number of latent variables, the number of supervised outputs, and the starting number of filters for the first convolutional layer in the encoder." - ] - }, - { - "metadata": { - "id": "ds7o8AuFxUpg", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "latent_dim = 100" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "amYEnHdJxWYB", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "To build the DB-VAE, we'll define each of the encoder and decoder networks separately, create and initialize the two models, and then construct the end-to-end VAE. We'll go through each of these steps in turn. " - ] - }, - { - "metadata": { - "id": "4k0tQeW1xpJf", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''Define the encoder network for the DB-VAE'''\n", - "def make_face_encoder_network():\n", - " Conv2D = functools.partial(tf.keras.layers.Conv2D, padding='same', activation='relu')\n", - " BatchNormalization = tf.keras.layers.BatchNormalization\n", - " Flatten = tf.keras.layers.Flatten\n", - " Dense = functools.partial(tf.keras.layers.Dense, activation='relu')\n", - "\n", - " inputs = tf.keras.layers.Input(shape=(64,64,3))\n", - " \n", - " hidden = Conv2D(filters=1*n_filters, kernel_size=[5,5], strides=[2,2])(inputs)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2D(filters=2*n_filters, kernel_size=[5,5], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2D(filters=4*n_filters, kernel_size=[3,3], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2D(filters=6*n_filters, kernel_size=[3,3], strides=[1,1])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - "\n", - " hidden = Flatten(name='flatten')(hidden)\n", - "# hidden = Dense(128)(hidden)\n", - " \n", - " '''Encoder outputs:\n", - " y_logit: supervised class prediction\n", - " z_mean: means in the latent space\n", - " z_logsigma: standard deviations in the latent space'''\n", - " y_logit = Dense(1, activation=None, name='y_logit')(hidden)\n", - " z_mean = Dense(latent_dim, name='z_mean')(hidden)\n", - " z_logsigma = Dense(latent_dim, name='z_logsigma')(hidden)\n", - "\n", - " # use reparameterization trick to sample from the latent space\n", - " z = tf.keras.layers.Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_logsigma])\n", - "\n", - " # define the outputs that the encoder model should return\n", - " outputs = [y_logit, z_mean, z_logsigma, z]\n", - " # finalize the encoder model\n", - " encoder = tf.keras.Model(inputs=inputs, outputs=outputs, name='encoder')\n", - "\n", - " # get the shape of the final convolutional output (right before the flatten)\n", - " flatten_layer_idx = encoder.layers.index(encoder.get_layer('flatten'))\n", - " pre_flatten_shape = encoder.layers[flatten_layer_idx-1].get_output_at(0).shape[1:]\n", - " \n", - " return encoder, inputs, outputs, pre_flatten_shape" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "FlB-Gcot0gYw", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Similarly, we can define the decoder network, which takes as input the sampled latent variables, runs them through a series of deconvolutional layers, and outputs a reconstruction of the original input image:" - ] - }, - { - "metadata": { - "id": "JfWPHGrmyE7R", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''Define the decoder network for the DB-VAE'''\n", - "def make_face_decoder_network(pre_flatten_shape):\n", - " Conv2DTranspose = functools.partial(tf.keras.layers.Conv2DTranspose, padding='same', activation='relu')\n", - " BatchNormalization = tf.keras.layers.BatchNormalization\n", - " Flatten = tf.keras.layers.Flatten\n", - " Dense = functools.partial(tf.keras.layers.Dense, activation='relu')\n", - "\n", - " latent_inputs = tf.keras.layers.Input(shape=(latent_dim,))\n", - " \n", - "# hidden = Dense(128)(latent_inputs)\n", - " hidden = Dense(tf.reduce_prod(pre_flatten_shape))(latent_inputs)\n", - " hidden = tf.keras.layers.Reshape(pre_flatten_shape)(hidden)\n", - " \n", - " # series of deconvolutional layers with batch normalization\n", - " hidden = Conv2DTranspose(filters=4*n_filters, kernel_size=[3,3], strides=[1,1])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2DTranspose(filters=2*n_filters, kernel_size=[3,3], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " hidden = Conv2DTranspose(filters=1*n_filters, kernel_size=[5,5], strides=[2,2])(hidden)\n", - " hidden = BatchNormalization()(hidden)\n", - " \n", - " x_hat = Conv2DTranspose(filters=3, kernel_size=[5,5], strides=[2,2])(hidden)\n", - "\n", - " # instantiate decoder model\n", - " decoder = tf.keras.Model(inputs=latent_inputs, outputs=x_hat, name='decoder')\n", - " return decoder\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "yWCMu12w1BuD", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, call these functions to create the encoder and decoder!" - ] - }, - { - "metadata": { - "id": "dSFDcFBL13c3", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''TODO: create the encoder and decoder networks'''\n", - "encoder, inputs, ouputs, pre_flatten_shape = make_face_encoder_network() # TODO\n", - "decoder = make_face_decoder_network(pre_flatten_shape) # TODO\n", - "\n", - "# initialize the models\n", - "encoder_output = encoder(inputs)\n", - "y_logit, z_mean, z_logsigma, z = encoder_output\n", - "reconstructed_inputs = decoder(z)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "QbRI5_rz2Myy", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Finally we can construct our network end-to-end." - ] - }, - { - "metadata": { - "id": "WITL88Fm2Z0a", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Construct the end to end vae\n", - "vae = tf.keras.Model(inputs, reconstructed_inputs)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "DjdyDDpc01ZZ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's visualize the architecture of the encoder to get a more concrete understanding of this network," - ] - }, - { - "metadata": { - "id": "7yKMwQU606ZR", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "util.display_model(encoder)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "M-clbYAj2waY", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "As you can see, the encoder architecture is virtually identical to the CNN from earlier in this lab. Note the outputs of this model: `y_logit, z_mean, z_logsigma, z`. Think carefully about why each of these are outputted and their significance to the problem at hand.\n", - "\n" - ] - }, - { - "metadata": { - "id": "nbDNlslgQc5A", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### Adaptive resampling for automated debiasing with DB-VAE\n", - "\n", - "So, how can we actually use DB-VAE to train a debiased facial detection classifier? Recall the DB-VAE architecture. As the input images are fed through the network, the encoder learns an estimate $\\mathcal{Q}(z|X)$ of the latent space. We want to increase the relative frequency of rare data by increased sampling of under-represented regions of the latent space. We can approximate $\\mathcal{Q}(z|X)$ using the frequency distributions of each of the learned latent variables, and then define the probability distribution of selecting a given datapoint $x$ based on this approximation. These probability distributions will be used during training to re-sample the data.\n", - "\n", - "You'll write a function to execute this update of the sampling probabilities, and then call this function within the DB-VAE training loop to actually debias the model. " - ] - }, - { - "metadata": { - "id": "Fej5FDu37cf7", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "First, we've defined a short helper function `get_latent_mu` that returns the latent variable means returned by the encoder after a batch of images is inputted to the network:" - ] - }, - { - "metadata": { - "id": "ewWbf7TE7wVc", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Function to return the means for an input image batch\n", - "def get_latent_mu(images, encoder, batch_size=1024):\n", - " N = images.shape[0]\n", - " mu = np.zeros((N, latent_dim))\n", - " for start_ind in xrange(0, N, batch_size):\n", - " end_ind = min(start_ind+batch_size, N+1)\n", - " batch = images[start_ind:end_ind]\n", - " batch = tf.convert_to_tensor(batch, dtype=tf.float32)/255.\n", - " _, batch_mu, _, _ = encoder(batch)\n", - " mu[start_ind:end_ind] = batch_mu\n", - " return mu" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "wn4yK3SC72bo", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now, let's define the actual resampling algorithm `get_training_sample_probabilities`. Importantly note the argument `smoothing_fac`. This parameter tunes the degree of debiasing: for `smoothing_fac=0`, the re-sampled training set will tend towards falling uniformly over the latent space. " - ] - }, - { - "metadata": { - "id": "HiX9pmmC7_wn", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "'''Function that recomputes the sampling probabilities for images within a batch\n", - " based on how they distribute across the '''\n", - "def get_training_sample_probabilities(images, encoder, bins=10, smoothing_fac=0.0): \n", - " print \"Recomputing the sampling probabilities\"\n", - " \n", - " mu = get_latent_mu(images, encoder)\n", - " # sampling probabilities for the images\n", - " training_sample_p = np.zeros(mu.shape[0])\n", - " \n", - " # consider the distribution for each latent variable \n", - " for i in range(latent_dim):\n", - " \n", - " latent_distribution = mu[:,i]\n", - " # generate a histogram of the latent distribution\n", - " hist_density, bin_edges = np.histogram(latent_distribution, density=True, bins=bins)\n", - "\n", - " # find which latent bin every data sample falls in \n", - " # https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.digitize.html\n", - " bin_edges[0] = -float('inf')\n", - " bin_edges[-1] = float('inf')\n", - " '''TODO: call the digitize function to find which bins in the latent distribution \n", - " every data sample falls in to'''\n", - " bin_idx = np.digitize(latent_distribution, bin_edges) # TODO\n", - "\n", - " # smooth the density function [Eq. #]\n", - " hist_smoothed_density = hist_density + smoothing_fac\n", - " hist_smoothed_density = hist_smoothed_density / np.sum(hist_smoothed_density)\n", - "\n", - " '''TODO: invert the density function to compute the sampling probability!\n", - " HINT: think carefully about the indexing of the bins! What is the length of bin_edges?'''\n", - " p = 1.0/(hist_smoothed_density[bin_idx-1]) # TODO\n", - " \n", - " # normalize all probabilities\n", - " p = p / np.sum(p)\n", - " \n", - " # update sampling probabilities \n", - " training_sample_p = np.maximum(p, training_sample_p)\n", - " \n", - " # final normalization\n", - " training_sample_p /= np.sum(training_sample_p)\n", - "\n", - " return training_sample_p" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "pF14fQkVUs-a", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now that we've defined the resampling update, we can train our DB-VAE model on the CelebA/ImageNet training data, and run the above operation to re-weight the importance of particular data points as we train the model. Remember again that we only want to debias for features relevant to *faces*, not the set of negative examples.\n", - "\n", - "Complete the code block below to execute the training loop!" - ] - }, - { - "metadata": { - "colab_type": "code", - "id": "9YR8U43FVZ_8", - "colab": {} - }, - "cell_type": "code", - "source": [ - "loss_history = []\n", - "optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)\n", - "\n", - "enable_debiasing = True\n", - "all_faces = loader.get_all_train_faces() # parameter from data loader\n", - "\n", - "for epoch in range(num_epochs):\n", - " \n", - " # progress message and bar\n", - " custom_msg = util.custom_progress_text(\"Epoch: %(epoch).0f Iter: %(idx).0f Class Loss: %(class_loss)2.2f Loss: %(loss)2.2f\")\n", - " bar = util.create_progress_bar(custom_msg)\n", - "\n", - " p_faces = None\n", - " if enable_debiasing: \n", - " # Recompute data sampling proabilities if debiasing is enabled\n", - " '''TODO: write the function call to recompute the sampling probabilities\n", - " when debiasing is enabled'''\n", - " p_faces = get_training_sample_probabilities(all_faces, encoder) # TODO\n", - " \n", - " for idx in bar(range(loader.get_train_size()//batch_size)):\n", - " # load a batch of data\n", - " (x, y) = loader.get_batch(batch_size, p_pos=p_faces)\n", - " x = tf.convert_to_tensor(x, dtype=tf.float32)\n", - " y = tf.convert_to_tensor(y, dtype=tf.float32)\n", - " \n", - " # define GradientTape for automatic differentiation\n", - " with tf.GradientTape() as tape:\n", - " y_logit, mu, logsigma, z = encoder(x)\n", - " x_hat = decoder(z)\n", - " '''TODO: call the relevant loss function to compute the loss'''\n", - " loss, class_loss = debiasing_loss_function(x, x_hat, y, y_logit, mu, logsigma) # TODO\n", - " \n", - " '''TODO: use the GradientTape.gradient method to compute the gradients'''\n", - " grads = tape.gradient(loss, vae.variables) # TODO\n", - " # apply gradients to variables\n", - " optimizer.apply_gradients(zip(grads, vae.variables),\n", - " global_step=tf.train.get_or_create_global_step())\n", - "\n", - " # track the losses\n", - " class_loss_value = class_loss.numpy().mean()\n", - " loss_value = loss.numpy().mean()\n", - " loss_history.append((class_loss_value, loss_value))\n", - " custom_msg.update_mapping(epoch=epoch, idx=idx, loss=loss_value, class_loss=class_loss_value)\n", - " \n", - " # plot the progress every 100 steps\n", - " if idx%100 == 0: \n", - " util.plot_sample(x,y,vae)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "uZBlWDPOVcHg", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Wonderful! Now we should have a trained and (hopefully!) debiased facial classification model, ready for evaluation!" - ] - }, - { - "metadata": { - "id": "Eo34xC7MbaiQ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.4 Evaluation on Pilot Parliaments Benchmark (PPB) Dataset\n", - "\n", - "Finally let's test our DB-VAE model on the[ PPB dataset](http://proceedings.mlr.press/v81/buolamwini18a/buolamwini18a.pdf). \n", - "\n", - "We'll evaluate both the overall accuracy of the DB-VAE as well as its accuracy on each the \"Dark Male\", \"Dark Female\", \"Light Male\", and \"Light Female\" demographics, and compare the performance of this debiased model against the biased CNN from earlier in the lab. \n", - "\n", - "Here are some example images from the PPB dataset.\n", - "![PPB Example Images](https://raw.githubusercontent.com/aamini/introtodeeplearning_labs/2019/lab2/img/PPB%20faces.png)" - ] - }, - { - "metadata": { - "id": "ruzxwzo2ko6N", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "To assess performance, we'll measure the classification accuracy of each model, which we define as the fraction of PPB faces detected. By comparing the accuracy of a model without debiasing and our DB-VAE model, we can get a sense of how effectively we were able to debias against features like skin tone and gender.\n", - "\n", - "Let's evaluate our debiased model on the PPB test dataset." - ] - }, - { - "metadata": { - "id": "bgK77aB9oDtX", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "# Evaluate on PPB dataset (takes ~4 minutes)\n", - "accuracy_debiased = []\n", - "for skin_color in ['lighter', 'darker']:\n", - " for gender in ['male', 'female']:\n", - " accuracy_debiased.append( ppb.evaluate([encoder], gender, skin_color, output_idx=0, from_logit=True)[0] )\n", - " print \n", - " print \"{} {}: {}\".format(gender, skin_color, accuracy_debiased[-1])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "F-3NzMB0oQtv", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can calculate the accuracies of our model on the whole PPB dataset as well as across the four demographics proposed and visualize our results comparing to the standard, biased CNN.\n" - ] - }, - { - "metadata": { - "id": "zzm-THVJkBjY", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "bar_width = 0.3\n", - "plt.bar(np.arange(4), standard_cnn_accuracy, width=bar_width)\n", - "plt.bar(np.arange(4)+bar_width, accuracy_debiased, width=bar_width)\n", - "plt.legend(('Standard Classifier','Debiased Classifier (DB-VAE)'))\n", - "plt.xticks(np.arange(4), ('LM', 'LF', 'DM', 'DF'))\n", - "plt.ylim(np.min([standard_cnn_accuracy,accuracy_debiased])-0.1,1)\n", - "plt.ylabel('Accuracy')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "rESoXRPQo_mq", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "## 2.5 Conclusion \n", - "\n", - "We encourage you to think about and maybe even address some questions raised by the approach and results outlined here:\n", - "\n", - "* How does the accuracy of the DB-VAE across the four demographics compare to that of the standard CNN? Do you find this result surprising in any way?\n", - "* In which applications (either related to facial detection or not!) would debiasing in this way be desired? Are there applications where you may not want to debias your model? \n", - "* Do you think it should be necessary for companies to demonstrate that their models, particularly in the context of tasks like facial detection, are not biased? If so, do you have thoughts on how this could be standardized and implemented?\n", - "* Do you have ideas for other ways to address issues of bias, particularly in terms of the training data?\n", - "\n", - "Hopefully this lab has shed some light on a few concepts, from vision based tasks, to VAEs, to algorithmic bias. We like to think it has, but we're biased ;). \n", - "\n", - "![Faces](https://media1.tenor.com/images/44e1f590924eca94fe86067a4cf44c72/tenor.gif?itemid=3394328)" - ] - } - ] -} \ No newline at end of file diff --git a/lab3/Lab3_rl.ipynb b/lab3/Lab3_rl.ipynb deleted file mode 100644 index 2af99880..00000000 --- a/lab3/Lab3_rl.ipynb +++ /dev/null @@ -1,986 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Lab3_rl.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "metadata": { - "id": "WoXYKhfZMHiw", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "# Lab 3: Model-Free Reinforcement Learning\n", - "\n", - "Reinforcement learning (RL) is a subset of machine learning which poses learning problems as interactions between agents and environments. It often assumes agents have no prior knowledge of the given world, so they must learn to navigate environments by optimizing some provided reward function. Within a world, an agent can take certain actions and receive feedback--in the form of positive or negative rewards--with respect to their decision. As such, an agent's feedback loop is somewhat akin to the manner in which a child might learn to distinguish between \"good\" and \"bad\" actions. In practical terms, our RL agent will interact with the environment by taking an action at each timestep, receiving a corresponding reward, and updating its state according to what it's \"learned\". \n", - "\n", - "![alt text](https://www.kdnuggets.com/images/reinforcement-learning-fig1-700.jpg)\n", - "\n", - "## Why do we care about games? \n", - "While the ultimate goal of reinforcement learning is to teach agents to act in the real, physical world, games provide a set of very useful properties that we also care about: \n", - "\n", - "1. In many cases, games have perfectly describable enviornments. For example, all rules of chess can be formally written and programmed into a chess game simulator;\n", - "2. Massively parallelizable. Do not require running in the real world, therefore simultaneous environments can be run on large data clusters; \n", - "3. Fast prototyping of algorithms on simpler scenarios can speed up the development of algorithms that could eventually run in the real-world; and\n", - "4. ... Games are fun! \n", - "\n", - "In this lab, we focus on building a model-free reinforcement learning algorithm to master two different enviornments with varying complexity. \n", - "\n", - "1. **Cartpole: Balance a pole in an upright position by only moving your base left or right. Low-dimensional observation space.**\n", - "2. **Pong: Beat a classical AI system designed at the game of Pong. High-dimensional observational space -- learning directly from raw pixels! **\n" - ] - }, - { - "metadata": { - "id": "zmrHSiXKTXTY", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "#Part 1: Cartpole\n", - "\n", - "Since we're no longer dealing with a supervised learning task, let's take a step back and outline our approach to the problem. First, we'll need to create our environment and initialize our agent. Moreover, we'll need to provide our agent with some sort of mechanism for remembering action and reward history... in other words, a memory bank. Then we'll need to define our learning algorithm, much like we've done in previous labs.\n", - "\n", - "\n", - "First we'll import TensorFlow, enable Eager execution, and also import some dependencies." - ] - }, - { - "metadata": { - "id": "xk5qeNPWCm00", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "!apt-get install -y xvfb python-opengl > /dev/null 2>&1\n", - "!pip install gym pyvirtualdisplay scikit-video > /dev/null 2>&1\n", - "\n", - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "\n", - "\n", - "import gym\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from IPython import display as ipythondisplay\n", - "import time\n", - "\n", - "# Download the class repository\n", - "! git clone https://github.com/aamini/introtodeeplearning_labs.git > /dev/null 2>&1\n", - "% cd introtodeeplearning_labs \n", - "! git pull\n", - "% cd .. \n", - "\n", - "import introtodeeplearning_labs as util" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "UT7YL8KBJIIc", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.1 Define and inspect the environment\n", - "\n", - "In order to model our environment, we'll be using a toolkit developed by OpenAI, [OpenAI Gym](https://gym.openai.com/). It provides several pre-defined environments for training and testing reinforcement learning agents, including those for classic physics control tasks, Atari video games, and robotic simulations. To access the basic version of a control task, \"Cart Pole\", we can use `env = gym.make(\"CartPole-v0\")`. When we imported `gym`, we gained access to higher level functions in the package, including creating virtual worlds. Each environment has a specific identifier (for which you can read through [here](https://gym.openai.com/envs/#classic_control)) which is accessed by passing the environment name as a string variable.\n", - "One issue we might experience when developing RL algorithms is that many aspects of the learning process are inherently random: initializing game states, changes in the environment, and the agent's actions. As such, it can be helpful to set a random \"seed\" for one of these variables to ensure some level of reproducibility. Much like you might use `numpy.random.seed`, we can call the comparable function in gym, `seed`, with our defined environment to ensure the environment's random variables are initialized the same each time. " - ] - }, - { - "metadata": { - "id": "quv9SC0iIYFm", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "env = gym.make(\"CartPole-v0\")\n", - "env.seed(1) # reproducible, since RL has high variance" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mhEITUcKK455", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - "**CartPole Environment: ** \n", - "\n", - "A pole is attached by an un-actuated joint to a cart, which moves along a frictionless track. The system is controlled by applying a force of +1 or -1 to the cart. The pendulum starts upright, and the goal is to prevent it from falling over. A reward of +1 is provided for every timestep that the pole remains upright. The episode ends when the pole is more than 15 degrees from vertical, or the cart moves more than 2.4 units from the center.\n", - "\n", - "\n", - "\n", - "Observations:\n", - "\n", - "1. position of cart\n", - "2. velocity of cart\n", - "3. angle of pole\n", - "4. rotation rate of pole\n", - "\n", - "We can confirm the size of the space by querying the observation space:\n" - ] - }, - { - "metadata": { - "id": "UVJaEcbdIX82", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print \"Enviornment has observation space = {}\".format(env.observation_space)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "ZibGgjrALgPM", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "At every time step, the agent can move either right or left. Confirm the size of the action space by querying the environment:" - ] - }, - { - "metadata": { - "id": "qc9SIPxBIXrm", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "n_actions = env.action_space.n\n", - "print \"Number of possible actions that the agent can choose from = {}\".format(n_actions)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "pPfHME8aRKkb", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.2 Define the Agent\n", - "\n", - "Let's define our agent, which is simply a deep neural network which takes as input an observation of the enviornment and outputs the probability of taking each of the possible actions. \n" - ] - }, - { - "metadata": { - "id": "W-o_XK4oQ4eu", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def create_cartpole_model():\n", - " model = tf.keras.models.Sequential([\n", - " tf.keras.layers.Dense(units=32, activation='relu'),\n", - " # TODO: define the output dimension of the last Dense layer\n", - " # Hint: think about that the space the agent needs to act in\n", - " tf.keras.layers.Dense(units='''TODO''', activation=None) # TODO\n", - " ])\n", - " return model\n", - "\n", - "cartpole_model = create_cartpole_model()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "d5D5NSIYS2IW", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Define the action function that executes a forward pass through the network and samples from the output. Take special note of the output activation of the model." - ] - }, - { - "metadata": { - "id": "E_vVZRr8Q4R_", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def choose_action(model, observation):\n", - " \n", - " observation = observation.reshape([1, -1])\n", - " '''TODO: feed the observations through the model to predict the log probabilities of each possible action.'''\n", - " logits = # TODO\n", - " \n", - " # pass the log probabilities through a softmax to compute true probabilities\n", - " prob_weights = tf.nn.softmax(logits).numpy()\n", - " \n", - " '''TODO: randomly sample from the prob_weights to pick an action.\n", - " Hint: carefully consider the dimensionality of the input probabilities (vector) and the output action (scalar)'''\n", - " action = # TODO\n", - "\n", - " return action" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "_tR9uAWcTnkr", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.3 Create the agent's memory\n", - "\n", - "During training, the agent will need to remember all of its observations, actions so that once the episode ends, it can \"reinforce\" the good actions and punish the undesirable actions. Let's do this by defining a simple memory buffer that contains the agent's observations, actions, and received rewards from a given episode. " - ] - }, - { - "metadata": { - "id": "8MM6JwXVQ4JG", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "class Memory:\n", - " def __init__(self): \n", - " self.clear()\n", - "\n", - " def clear(self): \n", - " self.observations = []\n", - " self.actions = []\n", - " self.rewards = []\n", - "\n", - " def add_to_memory(self, new_observation, new_action, new_reward): \n", - " self.observations.append(new_observation)\n", - " '''TODO: update the list of actions with new action'''\n", - " # TODO\n", - " '''TODO: update the list of rewards with new reward'''\n", - " # TODO\n", - " \n", - "memory = Memory()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "D4YhtPaUVj5m", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We're almost ready to begin the learning algorithm for our agent! The final step is to compute the discounted rewards of our agent. Recall from lecture, we use reward discount to give more preference at getting rewards now rather than later in the future. The idea of discounting rewards is similar to discounting money in the case of interest and can be defined as: \n", - "\n", - ">$R_{t}=\\sum_{k=0}^\\infty\\gamma^kr_{t+k}$\n", - "\n", - "where $\\gamma$ is the discount factor. In other words, at the end of an episode, we'll want to depreciate any rewards received at later time steps. Since we can't play an infinite number of games, we'll be limited to the number of timesteps in an episode. When implementing the function, you can initialize a numpy array of zeros (with length of the number of time steps) and fill it with the real discounted reward values as you loop through the saved rewards from the episode. We'll also want to normalize our output, which you can do using information about the mean and standard deviation of the discounted rewards.\n" - ] - }, - { - "metadata": { - "id": "5_Q2OFYtQ32X", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def normalize(x):\n", - " x -= np.mean(x)\n", - " x /= np.std(x)\n", - " return x\n", - "\n", - "def discount_rewards(rewards, gamma=0.95): \n", - " discounted_rewards = np.zeros_like(rewards)\n", - " R = 0\n", - " for t in reversed(range(0, len(rewards))):\n", - " # update the total discounted reward\n", - " R = R * gamma + rewards[t]\n", - " discounted_rewards[t] = R\n", - " \n", - " return normalize(discounted_rewards)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "QzbY-mjGYcmt", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.4 Define the learning algorithm\n", - "\n", - "Now we can start to define the learing algorithm which will be used to reinforce good behaviors of the agent and discourage bad behaviours. Start by defining the optimizer we want to use." - ] - }, - { - "metadata": { - "id": "m3u6xDNMY0zg", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "learning_rate = 1e-3\n", - "optimizer = tf.train.AdamOptimizer(learning_rate)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "M-LJwWqTZegG", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "And now let's define the loss function. In this lab we are focusing on policy gradient methods which aim to **maximize** the likelihood of actions that result in large rewards. Equivalently, this means that we want to **minimize** the negative likelihood of these same actions. Like in supervised learning, we can use stochastic gradient descent methods to achieve this minimization. \n", - "\n", - "Since the log function is monotonically increasing, this means that minimizing negative **likelihood** is equivalent to minimizing negative **log-likelihood**. Recall that we can easily compute the negative log-likelihood of an discrete action by evaluting its softmax cross entropy (https://www.tensorflow.org/api_docs/python/tf/nn/sparse_softmax_cross_entropy_with_logits) " - ] - }, - { - "metadata": { - "id": "fsgZ3IDCY_Zn", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def compute_loss(logits, actions, rewards): \n", - " '''TODO: complete the call to compute the loss'''\n", - " neg_logprob = tf.nn.sparse_softmax_cross_entropy_with_logits('''TODO''', '''TODO''') # TODO\n", - " '''TODO: scale the negative log probability by the rewards'''\n", - " loss = tf.reduce_mean( '''TODO''' ) # TODO\n", - " return loss" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "Rr5vQ9fqbPpp", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now let's use the loss function to define a backpropogation step of our learning algorithm." - ] - }, - { - "metadata": { - "id": "_50ada7nbZ7L", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def train_step(model, optimizer, observations, actions, discounted_rewards):\n", - " with tf.GradientTape() as tape:\n", - " # Forward propogate through the agent\n", - " observations = tf.convert_to_tensor(observations, dtype=tf.float32)\n", - " logits = model(observations)\n", - "\n", - " '''TODO: call the compute_loss function to compute the loss'''\n", - " loss = # TODO\n", - "\n", - " '''TODO: run backpropagation using the tape.gradient method'''\n", - " grads = tape.gradient('''TODO''', '''TODO''') # TODO\n", - " optimizer.apply_gradients(zip(grads, model.variables), global_step=tf.train.get_or_create_global_step())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "XsjKXh6BcgjR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.5 Let the agent go and watch it learn from scratch!\n", - "\n", - "Having had no prior knowledge of the environment, the agent will begin to learn how to balance the pole on the cart based only on the feedback received from the environment! Having defined how our agent can move, how it takes in new observations, and how it updates its state, we'll see how it gradually learns a policy of actions to optimize balancing the pole as long as possible.\n", - "\n" - ] - }, - { - "metadata": { - "id": "XmOzc2rrcn8Q", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "cartpole_model = create_cartpole_model()\n", - "\n", - "smoothed_reward = util.LossHistory(smoothing_factor=0.9)\n", - "plotter = util.PeriodicPlotter(sec=5, xlabel='Iterations', ylabel='Rewards')\n", - "\n", - "\n", - "for i_episode in range(1000):\n", - "\n", - " plotter.plot(smoothed_reward.get())\n", - "\n", - " # Restart the environment\n", - " observation = env.reset()\n", - "\n", - " while True:\n", - " # using our observation, take an action\n", - " action = choose_action(cartpole_model, observation)\n", - " next_observation, reward, done, info = env.step(action)\n", - " # add to memory\n", - " memory.add_to_memory(observation, action, reward)\n", - " \n", - " # is the episode over? did you crash or do so well that you're done?\n", - " if done:\n", - " # determine total reward and keep a record of this\n", - " total_reward = sum(memory.rewards)\n", - " smoothed_reward.append( total_reward )\n", - " \n", - " # initiate training - remember we don't know anything about how the agent is doing until it's crashed!\n", - " train_step(cartpole_model, \n", - " optimizer, \n", - " observations = np.vstack(memory.observations),\n", - " actions = np.array(memory.actions),\n", - " discounted_rewards = discount_rewards(memory.rewards)\n", - " )\n", - " \n", - " memory.clear()\n", - " break\n", - " # update our observatons\n", - " observation = next_observation" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mkcUtGF1VE-K", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.6 Save a video of the trained model while it is balancing the pole" - ] - }, - { - "metadata": { - "id": "M40RoTBxo3HD", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def save_video_of_model(model, env_name, filename='agent.mp4'): \n", - " import skvideo.io\n", - " from pyvirtualdisplay import Display\n", - " display = Display(visible=0, size=(40, 30))\n", - " display.start()\n", - "\n", - " env = gym.make(env_name)\n", - " obs = env.reset()\n", - " shape = env.render(mode='rgb_array').shape[0:2]\n", - "\n", - " out = skvideo.io.FFmpegWriter(filename)\n", - "\n", - " done = False\n", - " while not done: \n", - " frame = env.render(mode='rgb_array')\n", - " out.writeFrame(frame)\n", - " \n", - " action = model(tf.convert_to_tensor(obs.reshape((1,-1)), tf.float32)).numpy().argmax()\n", - " obs, reward, done, info = env.step(action)\n", - " out.close()\n", - " print \"Successfully saved into {}!\".format(filename)\n", - "\n", - "save_video_of_model(cartpole_model, \"CartPole-v0\")" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "dvvqdwO7VV_L", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.7 Display the saved video\n" - ] - }, - { - "metadata": { - "id": "DBjhWQ0XwQ1d", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "from IPython.display import HTML\n", - "import io, base64\n", - "video = io.open('./agent.mp4', 'r+b').read()\n", - "encoded = base64.b64encode(video)\n", - "HTML(data='''\n", - "'''.format(encoded.decode('ascii')))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "CSbVNDpaVb3_", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Congratulations, well done! How does the agent perform? Could you train it for shorter amounts of time and still perform well? Would training longer help even more? " - ] - }, - { - "metadata": { - "id": "Eu6Mqxc720ST", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "#Part 2: Pong\n", - "\n", - "In Cart Pole, we dealt with an environment that was static--in other words, it didn't change over time. What happens if our environment is dynamic and unpredictable? Well that's exactly the case in Pong, since part of the environment is our opposing player. We don't know how our opponent will act or react to our actions, so the complexity of our problem increases. It also becomes much more interesting, since we can compete to beat our opponent." - ] - }, - { - "metadata": { - "id": "srZ4YE29isuA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.1 Define and inspect the environment" - ] - }, - { - "metadata": { - "id": "lbYHLr66i15n", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "env = gym.make(\"Pong-v0\")\n", - "env.seed(1) # reproducible, since RL has high variance" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "52uZ2Xhyi-MW", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Observations: \n", - "\n", - "1. RGB image of shape (210, 160, 3)\n", - "\n", - "We can again confirm the size of the observation space by query:" - ] - }, - { - "metadata": { - "id": "0yX4GWvxjnHS", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print \"Enviornment has observation space = {}\".format(env.observation_space)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "uuEC2TdSjx9D", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "At every time step, the agent has six actions to choose from: noop, fire, move right, move left, fire right, and fire left. Let's confirm the size of the action space by querying the environment:" - ] - }, - { - "metadata": { - "id": "Iuy9oPc1kag3", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "n_actions = env.action_space.n\n", - "print \"Number of possible actions that the agent can choose from = {}\".format(n_actions)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "9-fghDRigUE5", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.2 Define the Agent\n", - "\n", - "We'll define our agent again, but this time, we'll add convolutional layers to the network to increase the learning capacity of our network." - ] - }, - { - "metadata": { - "id": "IJiqbFYpgYRH", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def create_pong_model():\n", - " model = tf.keras.models.Sequential([\n", - " # Define and reshape inputs\n", - " tf.keras.layers.InputLayer(input_shape=(6400,), dtype=tf.float32),\n", - " tf.keras.layers.Reshape((80, 80, 1)),\n", - " \n", - " # Convolutional layers\n", - " tf.keras.layers.Conv2D(filters=16, kernel_size=(8,8), strides=(4,4), activation='relu', padding='same'),\n", - " # TODO: define a convolutional layer with 32 4x4 filters and 2x2 stride, ReLu activation\n", - " tf.keras.layers.Conv2D('''TODO''', '''TODO''', '''TODO''', '''TODO''', padding='same'), # TODO\n", - " tf.keras.layers.Flatten(),\n", - " \n", - " # Fully connected layer and output\n", - " tf.keras.layers.Dense(units=256, activation='relu'),\n", - " # TODO: define the output dimension of the last Dense layer\n", - " # Hint: think about that the space the agent needs to act in\n", - " tf.keras.layers.Dense('''TODO''', activation=None) # TODO\n", - " ])\n", - " return model\n", - "\n", - "pong_model = create_pong_model()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "yaeZ067olFiJ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Since we've already defined the action function, `choose_action(model, observation)`, we don't need to define it again. Instead, we'll be able to reuse it later on by passing in our new model we've just created, `pong_model`. " - ] - }, - { - "metadata": { - "id": "l0RvqOVkmc2r", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.3 Helper Functions" - ] - }, - { - "metadata": { - "id": "g4xtfog0mupM", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We've already implemented some functions in Part 1 (Cartpole), so we won't need to recreate them in this section. However, we might need to make some slight modifications. For example, we need to reset the reward to zero when a game ends. In Pong, we know a game has ended if the reward is +1 (we won!) or -1 (we lost unfortunately). Otherwise, we expect the reward at a timestep to be zero. Also, note that we've increased gamma from 0.95 to 0.99, so the rate of decay will be even more rapid." - ] - }, - { - "metadata": { - "id": "iEZG2o50luLu", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def discount_rewards(rewards, gamma=0.99): \n", - " discounted_rewards = np.zeros_like(rewards)\n", - " R = 0\n", - " for t in reversed(range(0, len(rewards))):\n", - " # NEW: Reset sum\n", - " if rewards[t] != 0:\n", - " R = 0\n", - " # update the total discounted reward as before\n", - " R = R * gamma + rewards[t]\n", - " discounted_rewards[t] = R\n", - " \n", - " return normalize(discounted_rewards)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HopLpb4IoOqA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Before we input an image into our network, we'll need to pre-process it by converting it into a 1D array of floating point numbers:" - ] - }, - { - "metadata": { - "id": "Drpkn38Goout", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def pre_process(image):\n", - " I = image[35:195] # Crop\n", - " I = I[::2, ::2, 0] # Downsample width and height by a factor of 2\n", - " I[I == 144] = 0 # Remove background type 1\n", - " I[I == 109] = 0 # Remove background type 2\n", - " I[I != 0] = 1 # Set remaining elements (paddles, ball, etc.) to 1\n", - " return I.astype(np.float).ravel()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "-tP8_Bna6pgJ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's use this function to visualize what an observation might look like before and after pre-processing" - ] - }, - { - "metadata": { - "id": "no5IIYtFm8pI", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "observation = env.reset()\n", - "for i in range(30):\n", - " observation, _,_,_ = env.step(0)\n", - "observation_pp = pre_process(observation)\n", - "\n", - "f = plt.figure(figsize=(10,3))\n", - "ax = f.add_subplot(121)\n", - "ax2 = f.add_subplot(122)\n", - "ax.imshow(observation); ax.grid('off');\n", - "ax2.imshow(observation_pp.reshape((80,80))); ax2.grid('off'); plt.title('Preprocessed Observation')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mRqcaDQ1pm3x", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.4: Training\n", - "We've already defined our loss function with `compute_loss`, which is great! If we want to use a different learning rate, though, we can reinitialize the `optimizer`:" - ] - }, - { - "metadata": { - "id": "cIjRZ8JUqBLV", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "learning_rate=1e-4\n", - "optimizer = tf.train.AdamOptimizer(learning_rate)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "IL2lMbTDn6Z3", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also implement a very simple variant of `plot_progress`. In Pong, rather than feeding our network one image at a time, it can actually improve performance to input the difference between two consecutive observations, which really gives us information about the movement between frames. We'll first pre-process the raw observation, `x`, and then we'll compute the difference with the image frame we saw one timestep before. We'll also increase the number of maximum iterations from 1000 to 10000, since we expect it to take many more iterations to learn a more complex game." - ] - }, - { - "metadata": { - "id": "xCwyQQrPnkZG", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "pong_model = create_pong_model()\n", - "MAX_ITERS = 10000\n", - "\n", - "smoothed_reward = util.LossHistory(smoothing_factor=0.9)\n", - "plotter = util.PeriodicPlotter(sec=5, xlabel='Iterations', ylabel='Rewards')\n", - "memory = Memory()\n", - "\n", - "for i_episode in range(MAX_ITERS):\n", - "\n", - " plotter.plot(smoothed_reward.get())\n", - "\n", - " # Restart the environment\n", - " observation = env.reset()\n", - " previous_frame = pre_process(observation)\n", - "\n", - "\n", - " while True:\n", - " # Pre-process image \n", - " current_frame = pre_process(observation)\n", - " \n", - " '''TODO: determine the observation change\n", - " Hint: this is the difference between the past two frames'''\n", - " obs_change = # TODO\n", - " \n", - " '''TODO: choose an action for the pong model, using the frame difference, and evaluate'''\n", - " action = # TODO \n", - " # Take the chosen action\n", - " next_observation, reward, done, info = env.step(action)\n", - " '''TODO: save the observed frame difference, the action that was taken, and the resulting reward!'''\n", - " # TODO\n", - " \n", - " # is the episode over? did you crash or do so well that you're done?\n", - " if done:\n", - " # determine total reward and keep a record of this\n", - " total_reward = sum(memory.rewards)\n", - " smoothed_reward.append( total_reward )\n", - " \n", - " # begin training\n", - " train_step(pong_model, \n", - " optimizer, \n", - " observations = np.vstack(memory.observations), \n", - " actions = np.array(memory.actions),\n", - " discounted_rewards = discount_rewards(memory.rewards))\n", - " \n", - " memory.clear()\n", - " break\n", - "\n", - " observation = next_observation\n", - " previous_frame = current_frame" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "nwXjQH-puH5D", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.5: Save and display video of training" - ] - }, - { - "metadata": { - "id": "8LiEY5Y_ts-Z", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can now save the video of our model learning:" - ] - }, - { - "metadata": { - "id": "TvHXbkL0tR6M", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "save_video_of_model(pong_model, \"Pong-v0\", filename='pong_agent.mp4') " - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "xmIcylIzuWaL", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "And display the result:" - ] - }, - { - "metadata": { - "id": "qoOBQSrXt2Ib", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "from IPython.display import HTML\n", - "import io, base64\n", - "video = io.open('./pong_agent.mp4', 'r+b').read()\n", - "encoded = base64.b64encode(video)\n", - "HTML(data='''\n", - "'''.format(encoded.decode('ascii')))" - ], - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/lab3/Lab3_rl_solution.ipynb b/lab3/Lab3_rl_solution.ipynb deleted file mode 100644 index 6dcb0801..00000000 --- a/lab3/Lab3_rl_solution.ipynb +++ /dev/null @@ -1,986 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Lab3_rl_solution.ipynb", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python2", - "display_name": "Python 2" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "metadata": { - "id": "WoXYKhfZMHiw", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - " \n", - " \n", - " \n", - "
\n", - " \n", - " Visit MIT Deep Learning\n", - " Run in Google Colab\n", - " View Source on GitHub
\n", - "\n", - "# Lab 3: Model-Free Reinforcement Learning\n", - "\n", - "Reinforcement learning (RL) is a subset of machine learning which poses learning problems as interactions between agents and environments. It often assumes agents have no prior knowledge of the given world, so they must learn to navigate environments by optimizing some provided reward function. Within a world, an agent can take certain actions and receive feedback--in the form of positive or negative rewards--with respect to their decision. As such, an agent's feedback loop is somewhat akin to the manner in which a child might learn to distinguish between \"good\" and \"bad\" actions. In practical terms, our RL agent will interact with the environment by taking an action at each timestep, receiving a corresponding reward, and updating its state according to what it's \"learned\". \n", - "\n", - "![alt text](https://www.kdnuggets.com/images/reinforcement-learning-fig1-700.jpg)\n", - "\n", - "## Why do we care about games? \n", - "While the ultimate goal of reinforcement learning is to teach agents to act in the real, physical world, games provide a set of very useful properties that we also care about: \n", - "\n", - "1. In many cases, games have perfectly describable enviornments. For example, all rules of chess can be formally written and programmed into a chess game simulator;\n", - "2. Massively parallelizable. Do not require running in the real world, therefore simultaneous environments can be run on large data clusters; \n", - "3. Fast prototyping of algorithms on simpler scenarios can speed up the development of algorithms that could eventually run in the real-world; and\n", - "4. ... Games are fun! \n", - "\n", - "In this lab, we focus on building a model-free reinforcement learning algorithm to master two different enviornments with varying complexity. \n", - "\n", - "1. **Cartpole: Balance a pole in an upright position by only moving your base left or right. Low-dimensional observation space.**\n", - "2. **Pong: Beat a classical AI system designed at the game of Pong. High-dimensional observational space -- learning directly from raw pixels! **\n" - ] - }, - { - "metadata": { - "id": "zmrHSiXKTXTY", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "#Part 1: Cartpole\n", - "\n", - "Since we're no longer dealing with a supervised learning task, let's take a step back and outline our approach to the problem. First, we'll need to create our environment and initialize our agent. Moreover, we'll need to provide our agent with some sort of mechanism for remembering action and reward history... in other words, a memory bank. Then we'll need to define our learning algorithm, much like we've done in previous labs.\n", - "\n", - "\n", - "First we'll import TensorFlow, enable Eager execution, and also import some dependencies." - ] - }, - { - "metadata": { - "id": "xk5qeNPWCm00", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "!apt-get install -y xvfb python-opengl > /dev/null 2>&1\n", - "!pip install gym pyvirtualdisplay scikit-video > /dev/null 2>&1\n", - "\n", - "import tensorflow as tf\n", - "tf.enable_eager_execution()\n", - "\n", - "\n", - "import gym\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from IPython import display as ipythondisplay\n", - "import time\n", - "\n", - "# Download the class repository\n", - "! git clone https://github.com/aamini/introtodeeplearning_labs.git > /dev/null 2>&1\n", - "% cd introtodeeplearning_labs \n", - "! git pull\n", - "% cd .. \n", - "\n", - "import introtodeeplearning_labs as util" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "UT7YL8KBJIIc", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.1 Define and inspect the environment\n", - "\n", - "In order to model our environment, we'll be using a toolkit developed by OpenAI, [OpenAI Gym](https://gym.openai.com/). It provides several pre-defined environments for training and testing reinforcement learning agents, including those for classic physics control tasks, Atari video games, and robotic simulations. To access the basic version of a control task, \"Cart Pole\", we can use `env = gym.make(\"CartPole-v0\")`. When we imported `gym`, we gained access to higher level functions in the package, including creating virtual worlds. Each environment has a specific identifier (for which you can read through [here](https://gym.openai.com/envs/#classic_control)) which is accessed by passing the environment name as a string variable.\n", - "One issue we might experience when developing RL algorithms is that many aspects of the learning process are inherently random: initializing game states, changes in the environment, and the agent's actions. As such, it can be helpful to set a random \"seed\" for one of these variables to ensure some level of reproducibility. Much like you might use `numpy.random.seed`, we can call the comparable function in gym, `seed`, with our defined environment to ensure the environment's random variables are initialized the same each time. " - ] - }, - { - "metadata": { - "id": "quv9SC0iIYFm", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "env = gym.make(\"CartPole-v0\")\n", - "env.seed(1) # reproducible, since RL has high variance" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mhEITUcKK455", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "\n", - "**CartPole Environment: ** \n", - "\n", - "A pole is attached by an un-actuated joint to a cart, which moves along a frictionless track. The system is controlled by applying a force of +1 or -1 to the cart. The pendulum starts upright, and the goal is to prevent it from falling over. A reward of +1 is provided for every timestep that the pole remains upright. The episode ends when the pole is more than 15 degrees from vertical, or the cart moves more than 2.4 units from the center.\n", - "\n", - "\n", - "\n", - "Observations:\n", - "\n", - "1. position of cart\n", - "2. velocity of cart\n", - "3. angle of pole\n", - "4. rotation rate of pole\n", - "\n", - "We can confirm the size of the space by querying the observation space:\n" - ] - }, - { - "metadata": { - "id": "UVJaEcbdIX82", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print \"Enviornment has observation space = {}\".format(env.observation_space)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "ZibGgjrALgPM", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "At every time step, the agent can move either right or left. Confirm the size of the action space by querying the environment:" - ] - }, - { - "metadata": { - "id": "qc9SIPxBIXrm", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "n_actions = env.action_space.n\n", - "print \"Number of possible actions that the agent can choose from = {}\".format(n_actions)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "pPfHME8aRKkb", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.2 Define the Agent\n", - "\n", - "Let's define our agent, which is simply a deep neural network which takes as input an observation of the enviornment and outputs the probability of taking each of the possible actions. \n" - ] - }, - { - "metadata": { - "id": "W-o_XK4oQ4eu", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def create_cartpole_model():\n", - " model = tf.keras.models.Sequential([\n", - " tf.keras.layers.Dense(units=32, activation='relu'),\n", - " # TODO: define the output dimension of the last Dense layer\n", - " # Hint: think about that the space the agent needs to act in\n", - " tf.keras.layers.Dense(units=n_actions, activation=None) # TODO\n", - " ])\n", - " return model\n", - "\n", - "cartpole_model = create_cartpole_model()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "d5D5NSIYS2IW", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Define the action function that executes a forward pass through the network and samples from the output. Take special note of the output activation of the model." - ] - }, - { - "metadata": { - "id": "E_vVZRr8Q4R_", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def choose_action(model, observation):\n", - " \n", - " observation = observation.reshape([1, -1])\n", - " '''TODO: feed the observations through the model to predict the log probabilities of each possible action.'''\n", - " logits = model.predict(observation) # TODO\n", - " \n", - " # pass the log probabilities through a softmax to compute true probabilities\n", - " prob_weights = tf.nn.softmax(logits).numpy()\n", - " \n", - " '''TODO: randomly sample from the prob_weights to pick an action.\n", - " Hint: carefully consider the dimensionality of the input probabilities (vector) and the output action (scalar)'''\n", - " action = np.random.choice(n_actions, size=1, p=prob_weights.flatten())[0]\n", - "\n", - " return action" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "_tR9uAWcTnkr", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.3 Create the agent's memory\n", - "\n", - "During training, the agent will need to remember all of its observations, actions so that once the episode ends, it can \"reinforce\" the good actions and punish the undesirable actions. Let's do this by defining a simple memory buffer that contains the agent's observations, actions, and received rewards from a given episode. " - ] - }, - { - "metadata": { - "id": "8MM6JwXVQ4JG", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "class Memory:\n", - " def __init__(self): \n", - " self.clear()\n", - "\n", - " def clear(self): \n", - " self.observations = []\n", - " self.actions = []\n", - " self.rewards = []\n", - "\n", - " def add_to_memory(self, new_observation, new_action, new_reward): \n", - " self.observations.append(new_observation)\n", - " '''TODO: update the list of actions with new action'''\n", - " self.actions.append(new_action) # TODO\n", - " '''TODO: update the list of rewards with new reward'''\n", - " self.rewards.append(new_reward) # TODO\n", - " \n", - "memory = Memory()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "D4YhtPaUVj5m", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We're almost ready to begin the learning algorithm for our agent! The final step is to compute the discounted rewards of our agent. Recall from lecture, we use reward discount to give more preference at getting rewards now rather than later in the future. The idea of discounting rewards is similar to discounting money in the case of interest and can be defined as: \n", - "\n", - ">$R_{t}=\\sum_{k=0}^\\infty\\gamma^kr_{t+k}$\n", - "\n", - "where $\\gamma$ is the discount factor. In other words, at the end of an episode, we'll want to depreciate any rewards received at later time steps. Since we can't play an infinite number of games, we'll be limited to the number of timesteps in an episode. When implementing the function, you can initialize a numpy array of zeros (with length of the number of time steps) and fill it with the real discounted reward values as you loop through the saved rewards from the episode. We'll also want to normalize our output, which you can do using information about the mean and standard deviation of the discounted rewards.\n" - ] - }, - { - "metadata": { - "id": "5_Q2OFYtQ32X", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def normalize(x):\n", - " x -= np.mean(x)\n", - " x /= np.std(x)\n", - " return x\n", - "\n", - "def discount_rewards(rewards, gamma=0.95): \n", - " discounted_rewards = np.zeros_like(rewards)\n", - " R = 0\n", - " for t in reversed(range(0, len(rewards))):\n", - " # update the total discounted reward\n", - " R = R * gamma + rewards[t]\n", - " discounted_rewards[t] = R\n", - " \n", - " return normalize(discounted_rewards)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "QzbY-mjGYcmt", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.4 Define the learning algorithm\n", - "\n", - "Now we can start to define the learing algorithm which will be used to reinforce good behaviors of the agent and discourage bad behaviours. Start by defining the optimizer we want to use." - ] - }, - { - "metadata": { - "id": "m3u6xDNMY0zg", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "learning_rate = 1e-3\n", - "optimizer = tf.train.AdamOptimizer(learning_rate)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "M-LJwWqTZegG", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "And now let's define the loss function. In this lab we are focusing on policy gradient methods which aim to **maximize** the likelihood of actions that result in large rewards. Equivalently, this means that we want to **minimize** the negative likelihood of these same actions. Like in supervised learning, we can use stochastic gradient descent methods to achieve this minimization. \n", - "\n", - "Since the log function is monotonically increasing, this means that minimizing negative **likelihood** is equivalent to minimizing negative **log-likelihood**. Recall that we can easily compute the negative log-likelihood of an discrete action by evaluting its softmax cross entropy (https://www.tensorflow.org/api_docs/python/tf/nn/sparse_softmax_cross_entropy_with_logits) " - ] - }, - { - "metadata": { - "id": "fsgZ3IDCY_Zn", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def compute_loss(logits, actions, rewards): \n", - " '''TODO: complete the call to compute the loss'''\n", - " neg_logprob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=actions) # TODO\n", - " '''TODO: scale the negative log probability by the rewards'''\n", - " loss = tf.reduce_mean( neg_logprob * rewards ) # TODO\n", - " return loss" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "Rr5vQ9fqbPpp", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Now let's use the loss function to define a backpropogation step of our learning algorithm." - ] - }, - { - "metadata": { - "id": "_50ada7nbZ7L", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def train_step(model, optimizer, observations, actions, discounted_rewards):\n", - " with tf.GradientTape() as tape:\n", - " # Forward propogate through the agent\n", - " observations = tf.convert_to_tensor(observations, dtype=tf.float32)\n", - " logits = model(observations)\n", - "\n", - " '''TODO: call the compute_loss function to compute the loss'''\n", - " loss = compute_loss(logits, actions, discounted_rewards) # TODO\n", - "\n", - " '''TODO: run backpropagation using the tape.gradient method'''\n", - " grads = tape.gradient(loss, model.variables) # TODO\n", - " optimizer.apply_gradients(zip(grads, model.variables), global_step=tf.train.get_or_create_global_step())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "XsjKXh6BcgjR", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.5 Let the agent go and watch it learn from scratch!\n", - "\n", - "Having had no prior knowledge of the environment, the agent will begin to learn how to balance the pole on the cart based only on the feedback received from the environment! Having defined how our agent can move, how it takes in new observations, and how it updates its state, we'll see how it gradually learns a policy of actions to optimize balancing the pole as long as possible.\n", - "\n" - ] - }, - { - "metadata": { - "id": "XmOzc2rrcn8Q", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "cartpole_model = create_cartpole_model()\n", - "\n", - "smoothed_reward = util.LossHistory(smoothing_factor=0.9)\n", - "plotter = util.PeriodicPlotter(sec=5, xlabel='Iterations', ylabel='Rewards')\n", - "\n", - "\n", - "for i_episode in range(1000):\n", - "\n", - " plotter.plot(smoothed_reward.get())\n", - "\n", - " # Restart the environment\n", - " observation = env.reset()\n", - "\n", - " while True:\n", - " # using our observation, take an action\n", - " action = choose_action(cartpole_model, observation)\n", - " next_observation, reward, done, info = env.step(action)\n", - " # add to memory\n", - " memory.add_to_memory(observation, action, reward)\n", - " \n", - " # is the episode over? did you crash or do so well that you're done?\n", - " if done:\n", - " # determine total reward and keep a record of this\n", - " total_reward = sum(memory.rewards)\n", - " smoothed_reward.append( total_reward )\n", - " \n", - " # initiate training - remember we don't know anything about how the agent is doing until it's crashed!\n", - " train_step(cartpole_model, \n", - " optimizer, \n", - " observations = np.vstack(memory.observations),\n", - " actions = np.array(memory.actions),\n", - " discounted_rewards = discount_rewards(memory.rewards)\n", - " )\n", - " \n", - " memory.clear()\n", - " break\n", - " # update our observatons\n", - " observation = next_observation" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mkcUtGF1VE-K", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.6 Save a video of the trained model while it is balancing the pole" - ] - }, - { - "metadata": { - "id": "M40RoTBxo3HD", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def save_video_of_model(model, env_name, filename='agent.mp4'): \n", - " import skvideo.io\n", - " from pyvirtualdisplay import Display\n", - " display = Display(visible=0, size=(40, 30))\n", - " display.start()\n", - "\n", - " env = gym.make(env_name)\n", - " obs = env.reset()\n", - " shape = env.render(mode='rgb_array').shape[0:2]\n", - "\n", - " out = skvideo.io.FFmpegWriter(filename)\n", - "\n", - " done = False\n", - " while not done: \n", - " frame = env.render(mode='rgb_array')\n", - " out.writeFrame(frame)\n", - " \n", - " action = model(tf.convert_to_tensor(obs.reshape((1,-1)), tf.float32)).numpy().argmax()\n", - " obs, reward, done, info = env.step(action)\n", - " out.close()\n", - " print \"Successfully saved into {}!\".format(filename)\n", - "\n", - "save_video_of_model(cartpole_model, \"CartPole-v0\")" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "dvvqdwO7VV_L", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 1.7 Display the saved video\n" - ] - }, - { - "metadata": { - "id": "DBjhWQ0XwQ1d", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "from IPython.display import HTML\n", - "import io, base64\n", - "video = io.open('./agent.mp4', 'r+b').read()\n", - "encoded = base64.b64encode(video)\n", - "HTML(data='''\n", - "'''.format(encoded.decode('ascii')))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "CSbVNDpaVb3_", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Congratulations, well done! How does the agent perform? Could you train it for shorter amounts of time and still perform well? Would training longer help even more? " - ] - }, - { - "metadata": { - "id": "Eu6Mqxc720ST", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "#Part 2: Pong\n", - "\n", - "In Cart Pole, we dealt with an environment that was static--in other words, it didn't change over time. What happens if our environment is dynamic and unpredictable? Well that's exactly the case in Pong, since part of the environment is our opposing player. We don't know how our opponent will act or react to our actions, so the complexity of our problem increases. It also becomes much more interesting, since we can compete to beat our opponent." - ] - }, - { - "metadata": { - "id": "srZ4YE29isuA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.1 Define and inspect the environment" - ] - }, - { - "metadata": { - "id": "lbYHLr66i15n", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "env = gym.make(\"Pong-v0\")\n", - "env.seed(1) # reproducible, since RL has high variance" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "52uZ2Xhyi-MW", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Observations: \n", - "\n", - "1. RGB image of shape (210, 160, 3)\n", - "\n", - "We can again confirm the size of the observation space by query:" - ] - }, - { - "metadata": { - "id": "0yX4GWvxjnHS", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "print \"Enviornment has observation space = {}\".format(env.observation_space)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "uuEC2TdSjx9D", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "At every time step, the agent has six actions to choose from: noop, fire, move right, move left, fire right, and fire left. Let's confirm the size of the action space by querying the environment:" - ] - }, - { - "metadata": { - "id": "Iuy9oPc1kag3", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "n_actions = env.action_space.n\n", - "print \"Number of possible actions that the agent can choose from = {}\".format(n_actions)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "9-fghDRigUE5", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.2 Define the Agent\n", - "\n", - "We'll define our agent again, but this time, we'll add convolutional layers to the network to increase the learning capacity of our network." - ] - }, - { - "metadata": { - "id": "IJiqbFYpgYRH", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def create_pong_model():\n", - " model = tf.keras.models.Sequential([\n", - " # Define and reshape inputs\n", - " tf.keras.layers.InputLayer(input_shape=(6400,), dtype=tf.float32),\n", - " tf.keras.layers.Reshape((80, 80, 1)),\n", - " \n", - " # Convolutional layers\n", - " tf.keras.layers.Conv2D(filters=16, kernel_size=(8,8), strides=(4,4), activation='relu', padding='same'),\n", - " # TODO: define a convolutional layer with 32 4x4 filters and 2x2 stride, ReLu activation\n", - " tf.keras.layers.Conv2D(filters=32, kernel_size=(4,4), strides=(2,2), activation='relu', padding='same'), # TODO\n", - " tf.keras.layers.Flatten(),\n", - " \n", - " # Fully connected layer and output\n", - " tf.keras.layers.Dense(units=256, activation='relu'),\n", - " # TODO: define the output dimension of the last Dense layer\n", - " # Hint: think about that the space the agent needs to act in\n", - " tf.keras.layers.Dense(units=n_actions, activation=None) # TODO\n", - " ])\n", - " return model\n", - "\n", - "pong_model = create_pong_model()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "yaeZ067olFiJ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Since we've already defined the action function, `choose_action(model, observation)`, we don't need to define it again. Instead, we'll be able to reuse it later on by passing in our new model we've just created, `pong_model`. " - ] - }, - { - "metadata": { - "id": "l0RvqOVkmc2r", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.3 Helper Functions" - ] - }, - { - "metadata": { - "id": "g4xtfog0mupM", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We've already implemented some functions in Part 1 (Cartpole), so we won't need to recreate them in this section. However, we might need to make some slight modifications. For example, we need to reset the reward to zero when a game ends. In Pong, we know a game has ended if the reward is +1 (we won!) or -1 (we lost unfortunately). Otherwise, we expect the reward at a timestep to be zero. Also, note that we've increased gamma from 0.95 to 0.99, so the rate of decay will be even more rapid." - ] - }, - { - "metadata": { - "id": "iEZG2o50luLu", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def discount_rewards(rewards, gamma=0.99): \n", - " discounted_rewards = np.zeros_like(rewards)\n", - " R = 0\n", - " for t in reversed(range(0, len(rewards))):\n", - " # NEW: Reset sum\n", - " if rewards[t] != 0:\n", - " R = 0\n", - " # update the total discounted reward as before\n", - " R = R * gamma + rewards[t]\n", - " discounted_rewards[t] = R\n", - " \n", - " return normalize(discounted_rewards)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "HopLpb4IoOqA", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Before we input an image into our network, we'll need to pre-process it by converting it into a 1D array of floating point numbers:" - ] - }, - { - "metadata": { - "id": "Drpkn38Goout", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "def pre_process(image):\n", - " I = image[35:195] # Crop\n", - " I = I[::2, ::2, 0] # Downsample width and height by a factor of 2\n", - " I[I == 144] = 0 # Remove background type 1\n", - " I[I == 109] = 0 # Remove background type 2\n", - " I[I != 0] = 1 # Set remaining elements (paddles, ball, etc.) to 1\n", - " return I.astype(np.float).ravel()" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "-tP8_Bna6pgJ", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "Let's use this function to visualize what an observation might look like before and after pre-processing" - ] - }, - { - "metadata": { - "id": "no5IIYtFm8pI", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "observation = env.reset()\n", - "for i in range(30):\n", - " observation, _,_,_ = env.step(0)\n", - "observation_pp = pre_process(observation)\n", - "\n", - "f = plt.figure(figsize=(10,3))\n", - "ax = f.add_subplot(121)\n", - "ax2 = f.add_subplot(122)\n", - "ax.imshow(observation); ax.grid('off');\n", - "ax2.imshow(observation_pp.reshape((80,80))); ax2.grid('off'); plt.title('Preprocessed Observation')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "mRqcaDQ1pm3x", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.4: Training\n", - "We've already defined our loss function with `compute_loss`, which is great! If we want to use a different learning rate, though, we can reinitialize the `optimizer`:" - ] - }, - { - "metadata": { - "id": "cIjRZ8JUqBLV", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "learning_rate=1e-4\n", - "optimizer = tf.train.AdamOptimizer(learning_rate)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "IL2lMbTDn6Z3", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can also implement a very simple variant of `plot_progress`. In Pong, rather than feeding our network one image at a time, it can actually improve performance to input the difference between two consecutive observations, which really gives us information about the movement between frames. We'll first pre-process the raw observation, `x`, and then we'll compute the difference with the image frame we saw one timestep before. We'll also increase the number of maximum iterations from 1000 to 10000, since we expect it to take many more iterations to learn a more complex game." - ] - }, - { - "metadata": { - "id": "xCwyQQrPnkZG", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "pong_model = create_pong_model()\n", - "MAX_ITERS = 10000\n", - "\n", - "smoothed_reward = util.LossHistory(smoothing_factor=0.9)\n", - "plotter = util.PeriodicPlotter(sec=5, xlabel='Iterations', ylabel='Rewards')\n", - "memory = Memory()\n", - "\n", - "for i_episode in range(MAX_ITERS):\n", - "\n", - " plotter.plot(smoothed_reward.get())\n", - "\n", - " # Restart the environment\n", - " observation = env.reset()\n", - " previous_frame = pre_process(observation)\n", - "\n", - "\n", - " while True:\n", - " # Pre-process image \n", - " current_frame = pre_process(observation)\n", - " \n", - " '''TODO: determine the observation change\n", - " Hint: this is the difference between the past two frames'''\n", - " obs_change = current_frame - previous_frame # TODO\n", - " \n", - " '''TODO: choose an action for the pong model, using the frame difference, and evaluate'''\n", - " action = choose_action(pong_model, obs_change) # TODO \n", - " # Take the chosen action\n", - " next_observation, reward, done, info = env.step(action)\n", - " '''TODO: save the observed frame difference, the action that was taken, and the resulting reward!'''\n", - " memory.add_to_memory(obs_change, action, reward) # TODO\n", - " \n", - " # is the episode over? did you crash or do so well that you're done?\n", - " if done:\n", - " # determine total reward and keep a record of this\n", - " total_reward = sum(memory.rewards)\n", - " smoothed_reward.append( total_reward )\n", - " \n", - " # begin training\n", - " train_step(pong_model, \n", - " optimizer, \n", - " observations = np.vstack(memory.observations), \n", - " actions = np.array(memory.actions),\n", - " discounted_rewards = discount_rewards(memory.rewards))\n", - " \n", - " memory.clear()\n", - " break\n", - "\n", - " observation = next_observation\n", - " previous_frame = current_frame" - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "nwXjQH-puH5D", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "### 2.5: Save and display video of training" - ] - }, - { - "metadata": { - "id": "8LiEY5Y_ts-Z", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "We can now save the video of our model learning:" - ] - }, - { - "metadata": { - "id": "TvHXbkL0tR6M", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "save_video_of_model(pong_model, \"Pong-v0\", filename='pong_agent.mp4') " - ], - "execution_count": 0, - "outputs": [] - }, - { - "metadata": { - "id": "xmIcylIzuWaL", - "colab_type": "text" - }, - "cell_type": "markdown", - "source": [ - "And display the result:" - ] - }, - { - "metadata": { - "id": "qoOBQSrXt2Ib", - "colab_type": "code", - "colab": {} - }, - "cell_type": "code", - "source": [ - "from IPython.display import HTML\n", - "import io, base64\n", - "video = io.open('./pong_agent.mp4', 'r+b').read()\n", - "encoded = base64.b64encode(video)\n", - "HTML(data='''\n", - "'''.format(encoded.decode('ascii')))" - ], - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file