{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 13 - Introduction to TensorFlow\n", "\n", "by [Fabio A. González](http://dis.unal.edu.co/~fgonza/), Universidad Nacional de Colombia\n", "\n", "version 1.0, June 2018\n", "\n", "## Part of the class [Applied Deep Learning](https://github.com/albahnsen/AppliedDeepLearningClass)\n", "\n", "\n", "This notebook is licensed under a [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/deed.en_US). \n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/fgonza/anaconda3/envs/TF/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n", " from ._conv import register_converters as _register_converters\n" ] } ], "source": [ "import tensorflow as tf\n", "from IPython.display import clear_output, Image, display, HTML\n", "import numpy as np\n", "import pylab as pl\n", "from sklearn.datasets.samples_generator import make_blobs\n", "\n", "%matplotlib inline\n", "\n", "\n", "# Helper functions to inline visualization of computing graphs\n", "# Extracted from: \n", "# https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb\n", "def strip_consts(graph_def, max_const_size=32):\n", " \"\"\"Strip large constant values from graph_def.\"\"\"\n", " strip_def = tf.GraphDef()\n", " for n0 in graph_def.node:\n", " n = strip_def.node.add() \n", " n.MergeFrom(n0)\n", " if n.op == 'Const':\n", " tensor = n.attr['value'].tensor\n", " size = len(tensor.tensor_content)\n", " if size > max_const_size:\n", " tensor.tensor_content = \"\"%size\n", " return strip_def\n", "\n", "def show_graph(graph_def, max_const_size=32):\n", " \"\"\"Visualize TensorFlow graph.\"\"\"\n", " if hasattr(graph_def, 'as_graph_def'):\n", " graph_def = graph_def.as_graph_def()\n", " strip_def = strip_consts(graph_def, max_const_size=max_const_size)\n", " code = \"\"\"\n", " \n", " \n", "
\n", " \n", "
\n", " \"\"\".format(data=repr(str(strip_def)), id='graph'+str(np.random.rand()))\n", "\n", " iframe = \"\"\"\n", " \n", " \"\"\".format(code.replace('\"', '"'))\n", " display(HTML(iframe))\n", "\n", "# Functions for plotting 2D data and decision regions\n", "\n", "def plot_data(X, y):\n", " y_unique = np.unique(y)\n", " colors = pl.cm.rainbow(np.linspace(0.0, 1.0, y_unique.size))\n", " for this_y, color in zip(y_unique, colors):\n", " this_X = X[y == this_y]\n", " pl.scatter(this_X[:, 0], this_X[:, 1], c=color,\n", " alpha=0.5, edgecolor='k',\n", " label=\"Class %s\" % this_y)\n", " pl.legend(loc=\"best\")\n", " pl.title(\"Data\")\n", "\n", "def plot_decision_region(X, pred_fun):\n", " min_x = np.min(X[:, 0])\n", " max_x = np.max(X[:, 0])\n", " min_y = np.min(X[:, 1])\n", " max_y = np.max(X[:, 1])\n", " min_x = min_x - (max_x - min_x) * 0.05\n", " max_x = max_x + (max_x - min_x) * 0.05\n", " min_y = min_y - (max_y - min_y) * 0.05\n", " max_y = max_y + (max_y - min_y) * 0.05\n", " x_vals = np.linspace(min_x, max_x, 30)\n", " y_vals = np.linspace(min_y, max_y, 30)\n", " XX, YY = np.meshgrid(x_vals, y_vals)\n", " grid_r, grid_c = XX.shape\n", " ZZ = np.zeros((grid_r, grid_c))\n", " for i in range(grid_r):\n", " for j in range(grid_c):\n", " ZZ[i, j] = pred_fun(XX[i, j], YY[i, j])\n", " pl.contourf(XX, YY, ZZ, 30, cmap = pl.cm.coolwarm, vmin= -1, vmax=2)\n", " pl.colorbar()\n", " pl.xlabel(\"x\")\n", " pl.ylabel(\"y\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1. TensorFlow basics\n", "\n", "First we will create a simple computing graph and visualize it. The visualization is interactive, so you can expand and collapse nodes, zoom in, zoom out, pan, etc." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "graph = tf.Graph()\n", "\n", "with graph.as_default():\n", " a = tf.constant(10, tf.float32, name= 'a')\n", " b = tf.constant(-5, tf.float32, name= 'b')\n", " c = tf.constant(4, tf.float32, name= 'c')\n", "\n", " x = tf.placeholder(tf.float32, name= 'x')\n", " new_exp = x + c\n", " y = a * x * x + b * x + c\n", " \n", "show_graph(graph.as_graph_def())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we try to evaluate `y` it produces an object, not a value:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ " dtype=float32>" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To evaluate the expression we have to give a value to create a session and run the graph giving a value to `x`:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y = 9.0\n" ] } ], "source": [ "with graph.as_default():\n", " sess = tf.Session()\n", " result = sess.run(new_exp, {x: 5.0})\n", " sess.close()\n", "\n", "print('y =', result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can calculate the gradient of `y` with respect to a variable (or placeholder) in the graph:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "with graph.as_default():\n", " y_prime = tf.gradients(y, [x])\n", " \n", " sess = tf.Session()\n", " result = sess.run(y_prime, {x: 5.0})\n", " sess.close()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[95.0]\n" ] } ], "source": [ "print(result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This expands the graph with the gradient calculation component:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_graph(graph.as_graph_def())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use gradient descent to find a minimum of the polynomial represented in the graph. Here we need to change `x` to be a variable because its value is going to be updated for different sucessive evaluations of the graph." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 0.099999994 4.0\n", "1 0.16 3.6\n", "2 0.196 3.456\n", "3 0.21759999 3.446496\n", "4 0.23055999 3.3854978\n", "5 0.238336 3.378779\n", "6 0.2430016 3.3763604\n", "7 0.24580096 3.3754897\n", "8 0.24748057 3.3751762\n", "9 0.24848834 3.3750634\n", "10 0.24909301 3.375023\n", "11 0.24945581 3.375008\n", "12 0.24967349 3.3744578\n", "13 0.2498041 3.3750012\n", "14 0.24988246 3.3750002\n", "15 0.24992947 3.375\n", "16 0.24995768 3.375\n", "17 0.24997461 3.375\n", "18 0.24998477 3.375\n", "19 0.24999087 3.375\n" ] } ], "source": [ "graph = tf.Graph()\n", "with graph.as_default():\n", " a = tf.constant(10, tf.float32, name= 'a')\n", " b = tf.constant(-5, tf.float32, name= 'b')\n", " c = tf.constant(4, tf.float32, name= 'c')\n", " x = tf.Variable(0.0, name= 'x')\n", " y = a * x * x + b * x + c\n", "\n", " optimizer = tf.train.GradientDescentOptimizer(0.02)\n", " update = optimizer.minimize(y)\n", "\n", " # Graph execution\n", " sess = tf.Session()\n", " sess.run(tf.global_variables_initializer())\n", " for i in range(20):\n", " val_y, val_x, _ = sess.run([y, x, update])\n", " print(i, val_x, val_y)\n", " sess.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again the graph is expanded to contain the gradient calculations and the update rules of the optimizer. You can see two new containers `gradients` and `GradientDescent` which can be expanded. " ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_graph(graph.as_graph_def())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. Neural network training \n", "\n", "Now we will implement a logistic regression model to classify the following data:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "X, Y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=0)\n", "pl.figure(figsize=(8, 6))\n", "plot_data(X, Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following graph implements a logistic regression model. Scopes help to organize the graph \n", "in submodules. `x` and `y_true` are the main inputs to the model. `None` in the shape indicates\n", "that they can fit inputs with different number of samples, so we can present the whole training dataset\n", "or minibatches. The `inference` module corresponds to the prediction part of the module. Notice that `y_pred` is just the lineal combination, it does not apply the logistic function. This is done directly in the loss function. The `loss` module specify the loss function to use, in this case, `sigmoid_cross_entropy_with_logits` the *logits* correspond to the linear combination in `y_pred`. The reduce `tf.reduce_mean` function calculates a mean loss for all the samples that were presented at once. The `train` module includes a gradien descent optimizer." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "graph = tf.Graph()\n", "with graph.as_default():\n", " x = tf.placeholder(tf.float32,shape=[None,2])\n", " y_true = tf.placeholder(tf.float32,shape=None)\n", " \n", " with tf.name_scope('inference') as scope:\n", " w = tf.Variable([[0,0]],dtype=tf.float32,name='weights')\n", " b = tf.Variable(0,dtype=tf.float32,name='bias')\n", " y_pred = tf.matmul(w,tf.transpose(x)) + b\n", "\n", " with tf.name_scope('loss') as scope:\n", " loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=y_true,logits=y_pred)\n", " loss = tf.reduce_mean(loss)\n", " \n", " with tf.name_scope('train') as scope:\n", " learning_rate = 1.0\n", " optimizer = tf.train.GradientDescentOptimizer(learning_rate)\n", " train = optimizer.minimize(loss)\n", "\n", " init = tf.global_variables_initializer()\n", "\n", "show_graph(graph.as_graph_def())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The optimization algorithm is run for `num_epochs` iterations or epochs. In each epoch the whole training dataset is presented.\n", "Each five iterations, we run the model to calculate the loss, which is stored and later plotted. Notice that the session is not closed since we will need the values of the variables to predict additional samples." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "num_epochs = 50\n", "losses = []\n", "\n", "with graph.as_default():\n", " sess = tf.Session()\n", " sess.run(init) \n", " for step in range(num_epochs):\n", " sess.run(train,{x: X, y_true: Y})\n", " if (step % 5 == 0):\n", " losses.append(sess.run(loss, {x: X, y_true: Y}))\n", " \n", "pl.figure(figsize = (8,16/3))\n", "pl.plot(losses)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we use the `plot_decision_function`, defined at the beginning of the handout, to visualize the decision region. Notice the that the graph is run as many times as different values the visualization grid has, this is very inefficient! The efficient way to do it is passing all the values at the same time to the graph. However, for this example the inefficient method works just fine." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1.3167489 -1.5882863]]\n", "[[0.07089913]]\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def sigmoid(x):\n", " return 1.0/(1.0 + np.exp(-x))\n", "\n", "with graph.as_default():\n", " wval = sess.run(w)\n", " print(wval)\n", " result = sess.run(y_pred, {x:np.array([[1,2]])})\n", " print(result)\n", " def pred_fun(x1, x2):\n", " xval = np.array([[x1, x2]])\n", " return sigmoid(sess.run(y_pred,{x: xval}))\n", "\n", "pl.figure(figsize = (8,16/3)) \n", "plot_decision_region(X, pred_fun)\n", "plot_data(X, Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Clossing the session." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ " sess.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3. Using TensorBoard" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TensorBoard is an application provided by TensorFlow that allows to monitor the training process. TensorBoard uses as input log files which are created by a summary mechanism. Summaries correspond to operators in the graph that calculate statistics of other graph variables.\n", "\n", "The following function calculates different summary statistics for a given variable:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "def variable_summaries(var):\n", " with tf.name_scope('summaries'):\n", " mean = tf.reduce_mean(var)\n", " tf.summary.scalar('mean', mean)\n", " with tf.name_scope('stddev'):\n", " stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))\n", " tf.summary.scalar('stddev', stddev)\n", " tf.summary.scalar('max', tf.reduce_max(var))\n", " tf.summary.scalar('min', tf.reduce_min(var))\n", " tf.summary.histogram('histogram', var)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We define a new graph that includes these summaries:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "graph = tf.Graph()\n", "with graph.as_default():\n", " x = tf.placeholder(tf.float32,shape=[None,2])\n", " y_true = tf.placeholder(tf.float32,shape=None)\n", " \n", " with tf.name_scope('inference') as scope:\n", " w = tf.Variable([[0,0]],dtype=tf.float32,name='weights')\n", " b = tf.Variable(0,dtype=tf.float32,name='bias')\n", " y_pred = tf.matmul(w,tf.transpose(x)) + b\n", " variable_summaries(w)\n", " variable_summaries(b)\n", "\n", " with tf.name_scope('loss') as scope:\n", " loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=y_true,logits=y_pred)\n", " loss = tf.reduce_mean(loss)\n", " variable_summaries(loss)\n", " \n", " with tf.name_scope('train') as scope:\n", " learning_rate = 1.0\n", " optimizer = tf.train.GradientDescentOptimizer(learning_rate)\n", " train = optimizer.minimize(loss)\n", "\n", " merged = tf.summary.merge_all()\n", " init = tf.global_variables_initializer()\n", "\n", "show_graph(graph.as_graph_def())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will split the dataset in train and test, so that we\n", "can compute both the training and validation loss.\n", "We create a `train_writer` and a `test_writer` that that work as handles to write the respective logs. " ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 0.6931472 0.43206224\n", "20 0.16180742 0.27600694\n", "40 0.14276873 0.27437234\n", "60 0.13373153 0.27041867\n", "80 0.12786473 0.2650913\n", "100 0.123512484 0.2591867\n", "120 0.12005596 0.25315437\n", "140 0.11720215 0.24724531\n", "160 0.11478849 0.24159819\n", "180 0.112713665 0.23628533\n", "200 0.110909075 0.23133859\n", "220 0.1093251 0.22676502\n", "240 0.10792431 0.22255598\n", "260 0.10667751 0.218694\n", "280 0.105561465 0.21515647\n", "300 0.104557216 0.21191847\n", "320 0.10364933 0.20895454\n", "340 0.10282493 0.20623972\n", "360 0.1020733 0.20375048\n", "380 0.101385444 0.20146467\n" ] } ], "source": [ "x_train = X[:50]\n", "x_test = X[50:]\n", "y_train = Y[:50]\n", "y_test = Y[50:]\n", "\n", "LOG_DIR = 'logs'\n", "train_writer = tf.summary.FileWriter(LOG_DIR + '/train',\n", " graph=graph)\n", "test_writer = tf.summary.FileWriter(LOG_DIR + '/test')\n", "\n", "num_epochs = 400\n", "\n", "with graph.as_default():\n", " with tf.Session() as sess:\n", " sess.run(init) \n", " for step in range(num_epochs):\n", " summary, train_loss, _ = sess.run([merged, loss, train] ,{x: x_train, y_true: y_train})\n", " train_writer.add_summary(summary, step)\n", " summary, val_loss = sess.run([merged, loss] ,{x: x_test, y_true: y_test})\n", " test_writer.add_summary(summary, step)\n", " if step % 20 == 0:\n", " print(step, train_loss, val_loss)\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we can launch TensorBoard from the console wiht the \n", "following command:\n", "\n", "`tensorboard --logdir=logs/`\n", "\n", "After launching it, we need to visit: http://localhost:6006 or whatever address TensroBoard tells us." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" } }, "nbformat": 4, "nbformat_minor": 2 }