{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## RNN Language Model\n", "\n", "Below is a diagram of the RNN computation that we will implement below. We're plugging characters into the RNN with a 1-hot encoding and expecting it to predict the next character. In this example the training data is the string \"hello\", so there are 4 letters in the vocabulary: [h,e,l,o]." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy as np\n", "np.random.seed(1337)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "data has 4573338 characters, 67 unique.\n" ] } ], "source": [ "# data I/O\n", "# get shakespeare from http://cs.stanford.edu/people/karpathy/shakespeare.txt\n", "data = open('shakespeare.txt', 'r').read() # should be simple plain text file\n", "chars = list(set(data))\n", "data_size, vocab_size = len(data), len(chars)\n", "print 'data has %d characters, %d unique.' % (data_size, vocab_size)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "char_to_ix = { ch:i for i,ch in enumerate(chars) }\n", "ix_to_char = { i:ch for i,ch in enumerate(chars) }" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "41" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "char_to_ix['a']" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " thing when he was young,\n" ] } ], "source": [ "# lets sample a batch of data\n", "seq_length = 25 # number of characters in the batch\n", "p = 220000 # point in the book to sample from\n", "print data[p:p+seq_length] # print a chunk of data" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 61, 49, 48, 55, 46, 2, 62, 49, 44, 55, 2, 49, 44, 2, 62, 41, 58, 2, 64, 54, 60, 55, 46, 7]\n", "[61, 49, 48, 55, 46, 2, 62, 49, 44, 55, 2, 49, 44, 2, 62, 41, 58, 2, 64, 54, 60, 55, 46, 7, 0]\n" ] } ], "source": [ "inputs = [char_to_ix[ch] for ch in data[p:p+seq_length]]\n", "targets = [char_to_ix[ch] for ch in data[p+1:p+seq_length+1]]\n", "print inputs\n", "print targets" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n" ] } ], "source": [ "# lets plug the first character into the RNN\n", "ix_input = inputs[0]\n", "ix_target = targets[0]\n", "# encode the input character with a 1-hot representation\n", "x = np.zeros((vocab_size,1))\n", "x[ix_input] = 1\n", "print x.ravel()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# create random starting parameters\n", "hidden_size = 10\n", "Wxh = np.random.randn(hidden_size, vocab_size)*0.01 # input to hidden\n", "Whh = np.random.randn(hidden_size, hidden_size)*0.01 # hidden to hidden\n", "Why = np.random.randn(vocab_size, hidden_size)*0.01 # hidden to output\n", "bh = np.zeros((hidden_size, 1)) # hidden bias\n", "by = np.zeros((vocab_size, 1)) # output bias" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[-0.00321813 0.00640499 0.00424507 0.00783602 -0.00428041 0.00900686\n", " -0.01618631 0.00071848 -0.01342806 -0.0048051 ]\n" ] } ], "source": [ "# compute the hidden state\n", "h_prev = np.zeros((hidden_size, 1))\n", "h = np.tanh(np.dot(Wxh, x) + np.dot(Whh, h_prev + bh))\n", "print h.ravel()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 3.83078834e-05 3.73893809e-05 -1.07305639e-04 2.67774461e-04\n", " 1.19325035e-04 -3.37354220e-04 -3.34852820e-04 3.32538588e-04\n", " 3.18794726e-04 -1.03554566e-05 1.36845629e-04 -5.38710213e-04\n", " -4.57711660e-04 2.99868693e-04 1.68690516e-04 1.78520042e-04\n", " 2.36693532e-04 -7.03401501e-05 -7.16902773e-05 1.27203335e-04\n", " 8.04252112e-05 1.59279072e-04 2.17314448e-04 -2.72573982e-05\n", " -7.02211895e-04 -2.42104646e-05 5.30702842e-04 1.94948893e-04\n", " -9.90711082e-05 4.03627462e-04 -2.93323333e-04 3.93383233e-04\n", " -4.05743771e-04 -3.38345251e-04 -5.29097616e-05 -4.80911954e-05\n", " 1.33355225e-04 4.75679274e-04 6.58103198e-05 1.94801460e-04\n", " -2.20233399e-04 3.08235108e-04 -2.53968781e-05 1.44684905e-04\n", " -8.29930806e-05 5.83661343e-04 7.77516275e-05 2.55059906e-04\n", " 1.81287457e-04 2.64252428e-04 1.78958318e-04 -2.92440820e-04\n", " -3.40954240e-04 8.32849829e-05 -6.05381172e-05 3.07491179e-04\n", " 3.90229048e-04 -1.39828111e-04 2.11848605e-04 -5.79932785e-04\n", " 6.02578409e-05 -2.12493371e-04 2.07956569e-04 -2.84122452e-04\n", " -2.30967665e-04 3.80355416e-04 9.87418965e-05]\n" ] } ], "source": [ "# compute the scores for next character\n", "y = np.dot(Why, h) + by\n", "print y.ravel()" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0.0149254 0.01492538 0.01492322 0.01492882 0.01492661 0.01491979\n", " 0.01491983 0.01492979 0.01492958 0.01492467 0.01492687 0.01491679\n", " 0.014918 0.0149293 0.01492734 0.01492749 0.01492836 0.01492378\n", " 0.01492376 0.01492672 0.01492603 0.0149272 0.01492807 0.01492442\n", " 0.01491435 0.01492446 0.01493275 0.01492774 0.01492335 0.01493085\n", " 0.01492045 0.0149307 0.01491877 0.01491978 0.01492404 0.01492411\n", " 0.01492682 0.01493193 0.01492581 0.01492773 0.01492154 0.01492943\n", " 0.01492445 0.01492699 0.01492359 0.01493354 0.01492599 0.01492863\n", " 0.01492753 0.01492877 0.0149275 0.01492046 0.01491974 0.01492607\n", " 0.01492392 0.01492942 0.01493065 0.01492274 0.01492799 0.01491617\n", " 0.01492572 0.01492165 0.01492793 0.01492059 0.01492138 0.0149305\n", " 0.0149263 ]\n", "probabilities sum to 1.0\n" ] } ], "source": [ "# the scores are unnormalized log probabilities. compute the probabilities\n", "p = np.exp(y) / np.sum(np.exp(y))\n", "print p.ravel()\n", "print 'probabilities sum to ', p.sum()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "probability assigned to the correct next character is right now: 0.0149216543899\n" ] } ], "source": [ "print 'probability assigned to the correct next character is right now: ', p[ix_target,0]" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "the cross-entropy (softmax) loss is 4.20494180632\n" ] } ], "source": [ "loss = -np.log(p[ix_target,0])\n", "print 'the cross-entropy (softmax) loss is ', loss" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0.0149254 0.01492538 0.01492322 0.01492882 0.01492661 0.01491979\n", " 0.01491983 0.01492979 0.01492958 0.01492467 0.01492687 0.01491679\n", " 0.014918 0.0149293 0.01492734 0.01492749 0.01492836 0.01492378\n", " 0.01492376 0.01492672 0.01492603 0.0149272 0.01492807 0.01492442\n", " 0.01491435 0.01492446 0.01493275 0.01492774 0.01492335 0.01493085\n", " 0.01492045 0.0149307 0.01491877 0.01491978 0.01492404 0.01492411\n", " 0.01492682 0.01493193 0.01492581 0.01492773 0.01492154 0.01492943\n", " 0.01492445 0.01492699 0.01492359 0.01493354 0.01492599 0.01492863\n", " 0.01492753 0.01492877 0.0149275 0.01492046 0.01491974 0.01492607\n", " 0.01492392 0.01492942 0.01493065 0.01492274 0.01492799 0.01491617\n", " 0.01492572 -0.98507835 0.01492793 0.01492059 0.01492138 0.0149305\n", " 0.0149263 ]\n", "sum of dy is 1.45716771982e-16\n", "the gradient for the correct character (t) is: -0.98507834561\n", "the gradient for the character (a) is: 0.0149294265437\n" ] } ], "source": [ "# compute the gradient on y\n", "dy = np.copy(p)\n", "dy[ix_target] -= 1\n", "print dy.ravel()\n", "print 'sum of dy is ', dy.sum()\n", "print 'the gradient for the correct character (%s) is: %s' % (ix_to_char[ix_target], dy[ix_target,0])\n", "print 'the gradient for the character (a) is: ', dy[char_to_ix['a'],0]" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "the hidden vector activations were:\n", "[-0.00321813 0.00640499 0.00424507 0.00783602 -0.00428041 0.00900686\n", " -0.01618631 0.00071848 -0.01342806 -0.0048051 ]\n", "the gradients are:\n", "[-0.00983172 -0.01049054 0.00911112 -0.01110877 -0.00134586 0.00686193\n", " -0.01532285 0.0099507 -0.00530998 0.01267197]\n", "the gradients dWhy have size: (67, 10)\n", "a small sample is:\n", "[[ -4.80319012e-05 9.55970187e-05 6.33594305e-05 1.16955768e-04]\n", " [ -4.80318571e-05 9.55969309e-05 6.33593723e-05 1.16955661e-04]\n", " [ -4.80249076e-05 9.55830995e-05 6.33502052e-05 1.16938739e-04]\n", " [ -4.80429242e-05 9.56189576e-05 6.33739710e-05 1.16982609e-04]]\n" ] } ], "source": [ "# we computed [y = np.dot(Why, h) + by]; Backpropagate to Why, h, and by\n", "dWhy = np.dot(dy, h.T)\n", "dh = np.dot(Why.T, dy)\n", "dby = np.copy(dy)\n", "print 'the hidden vector activations were:'\n", "print h.ravel()\n", "print 'the gradients are:'\n", "print dh.ravel()\n", "print 'the gradients dWhy have size: ', dWhy.shape\n", "print 'a small sample is:'\n", "print dWhy[:4,:4]" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "small sample of Whh:\n", "[[-0.0028736 -0.00195895 0.00885911 -0.00349354]\n", " [-0.00773272 -0.00051873 0.00219991 -0.00234756]\n", " [ 0.01687054 -0.01221995 0.00125455 -0.00568523]\n", " [-0.00031645 0.00514377 0.01194564 0.0070584 ]]\n" ] } ], "source": [ "# we computed [h = np.tanh(np.dot(Wxh, x) + np.dot(Whh, h_prev + bh))]; \n", "# Backprop into Wxh, x, Whh, h_prev, bh:\n", "dh_before_tanh = (1-h**2)*dh\n", "dbh = np.copy(dh_before_tanh)\n", "dWxh = np.dot(dh_before_tanh, x.T)\n", "dWhh = np.dot(dh_before_tanh, h.T)\n", "dh_prev = np.dot(Whh.T, dh_before_tanh)\n", "print 'small sample of Whh:'\n", "print Whh[:4,:4]" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# we now have the gradients for all parameters! (Wxh, Whh, Why, bh, by)\n", "# lets do a parameter update\n", "learning_rate = 0.1\n", "Wxh2 = Wxh - learning_rate * dWxh\n", "Whh2 = Whh - learning_rate * dWhh\n", "Why2 = Why - learning_rate * dWhy\n", "bh2 = bh - learning_rate * dbh\n", "by2 = by - learning_rate * dby" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "probability assigned to the correct next character was: 0.0149216543899\n", "probability assigned to the correct next character is now: 0.0164678301753\n", "the cross-entropy (softmax) loss was 4.20494180632\n", "the loss is now 4.10634648754\n" ] } ], "source": [ "# these parameters should be much better! lets try it out:\n", "h2 = np.tanh(np.dot(Wxh2, x) + np.dot(Whh2, h_prev + bh2))\n", "y2 = np.dot(Why2, h2) + by2\n", "p2 = np.exp(y2) / np.sum(np.exp(y2))\n", "print 'probability assigned to the correct next character was: ', p[ix_target,0]\n", "print 'probability assigned to the correct next character is now: ', p2[ix_target,0]\n", "loss2 = -np.log(p2[ix_target,0])\n", "print 'the cross-entropy (softmax) loss was ', loss\n", "print 'the loss is now ', loss2" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# note: the probability for the correct character went up! (and the loss went down)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# putting it together with loops\n", "def lossFun(inputs, targets, hprev):\n", " \"\"\"\n", " inputs,targets are both list of integers.\n", " hprev is Hx1 array of initial hidden state\n", " returns the loss, gradients on model parameters, and last hidden state\n", " \"\"\"\n", " xs, hs, ys, ps = {}, {}, {}, {}\n", " hs[-1] = np.copy(hprev)\n", " loss = 0\n", " \n", " # forward pass\n", " for t in xrange(len(inputs)):\n", " xs[t] = np.zeros((vocab_size,1)) # encode in 1-of-k representation\n", " xs[t][inputs[t]] = 1\n", " hs[t] = np.tanh(np.dot(Wxh, xs[t]) + np.dot(Whh, hs[t-1]) + bh) # hidden state\n", " ys[t] = np.dot(Why, hs[t]) + by # unnormalized log probabilities for next chars\n", " ps[t] = np.exp(ys[t]) / np.sum(np.exp(ys[t])) # probabilities for next chars\n", " loss += -np.log(ps[t][targets[t],0]) # softmax (cross-entropy loss)\n", " \n", " # backward pass: compute gradients going backwards\n", " dWxh, dWhh, dWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)\n", " dbh, dby = np.zeros_like(bh), np.zeros_like(by)\n", " dhnext = np.zeros_like(hs[0])\n", " for t in reversed(xrange(len(inputs))):\n", " dy = np.copy(ps[t])\n", " dy[targets[t]] -= 1 # backprop into y\n", " dWhy += np.dot(dy, hs[t].T)\n", " dby += dy\n", " dh = np.dot(Why.T, dy) + dhnext # backprop into h\n", " dhraw = (1 - hs[t] * hs[t]) * dh # backprop through tanh nonlinearity\n", " dbh += dhraw\n", " dWxh += np.dot(dhraw, xs[t].T)\n", " dWhh += np.dot(dhraw, hs[t-1].T)\n", " dhnext = np.dot(Whh.T, dhraw)\n", " \n", " # clip to mitigate exploding gradients\n", " for dparam in [dWxh, dWhh, dWhy, dbh, dby]:\n", " np.clip(dparam, -5, 5, out=dparam)\n", " \n", " return loss, dWxh, dWhh, dWhy, dbh, dby, hs[len(inputs)-1]" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "105.118896505\n" ] } ], "source": [ "loss, dWxh, dWhh, dWhy, dbh, dby, hnew = lossFun(inputs, targets, h_prev)\n", "print loss" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# TODO: write the sampling code\n", "def sample(h, seed_ix, n):\n", " \"\"\" \n", " sample a sequence of integers from the model \n", " h is initial memory state, seed_ix is seed letter for first time step\n", " n is the number of time steps to sample for\n", " \"\"\"\n", " x = np.zeros((vocab_size, 1))\n", " x[seed_ix] = 1\n", " ixes = [] # sampled indices\n", " for t in xrange(n):\n", " pass # TODO: run the RNN for one time step, sample from distribution\n", " return ixes\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "iter 0, loss: 105.117314\n", "iter 100, loss: 104.983384\n", "iter 200, loss: 104.623511\n", "iter 300, loss: 104.093896\n", "iter 400, loss: 103.407954\n", "iter 500, loss: 102.742497\n", "iter 600, loss: 101.886946\n", "iter 700, loss: 101.017334\n", "iter 800, loss: 100.224049\n", "iter 900, loss: 99.275074\n", "iter 1000, loss: 98.310447\n", "iter 1100, loss: 97.280136\n", "iter 1200, loss: 96.170347\n", "iter 1300, loss: 95.026980\n", "iter 1400, loss: 94.074431\n", "iter 1500, loss: 93.214796\n", "iter 1600, loss: 92.194884\n", "iter 1700, loss: 91.461468\n", "iter 1800, loss: 90.884004\n", "iter 1900, loss: 90.051538\n", "iter 2000, loss: 89.025933\n", "iter 2100, loss: 88.348015\n", "iter 2200, loss: 87.853860\n", "iter 2300, loss: 87.232155\n", "iter 2400, loss: 86.868957\n", "iter 2500, loss: 86.633172\n", "iter 2600, loss: 86.099010\n", "iter 2700, loss: 85.847026\n", "iter 2800, loss: 85.920993\n", "iter 2900, loss: 85.654873\n", "iter 3000, loss: 85.194774\n", "iter 3100, loss: 85.314185\n", "iter 3200, loss: 85.286007\n", "iter 3300, loss: 85.060589\n", "iter 3400, loss: 84.918822\n", "iter 3500, loss: 84.606756\n", "iter 3600, loss: 84.445501\n", "iter 3700, loss: 84.407657\n", "iter 3800, loss: 84.323040\n", "iter 3900, loss: 84.133951\n", "iter 4000, loss: 84.064946\n", "iter 4100, loss: 84.004744\n", "iter 4200, loss: 83.680242\n", "iter 4300, loss: 83.838111\n", "iter 4400, loss: 83.538384\n", "iter 4500, loss: 83.244682\n", "iter 4600, loss: 82.926760\n", "iter 4700, loss: 82.978359\n", "iter 4800, loss: 83.063037\n", "iter 4900, loss: 83.094751\n", "iter 5000, loss: 82.961633\n", "iter 5100, loss: 82.787609\n", "iter 5200, loss: 82.812643\n", "iter 5300, loss: 82.653842\n", "iter 5400, loss: 82.512128\n", "iter 5500, loss: 82.471460\n", "iter 5600, loss: 82.328936\n", "iter 5700, loss: 82.100785\n", "iter 5800, loss: 82.109023\n", "iter 5900, loss: 82.088454\n", "iter 6000, loss: 81.998958\n", "iter 6100, loss: 82.107872\n", "iter 6200, loss: 82.203081\n", "iter 6300, loss: 82.139286\n", "iter 6400, loss: 82.375904\n", "iter 6500, loss: 82.276112\n", "iter 6600, loss: 82.344397\n", "iter 6700, loss: 82.709979\n", "iter 6800, loss: 82.775993\n", "iter 6900, loss: 82.987775\n", "iter 7000, loss: 82.979527\n", "iter 7100, loss: 83.100577\n", "iter 7200, loss: 83.124201\n", "iter 7300, loss: 83.255949\n", "iter 7400, loss: 83.229047\n", "iter 7500, loss: 83.334554\n", "iter 7600, loss: 83.281780\n", "iter 7700, loss: 83.155654\n", "iter 7800, loss: 83.017638\n", "iter 7900, loss: 82.702089\n", "iter 8000, loss: 82.610772\n", "iter 8100, loss: 82.449181\n", "iter 8200, loss: 82.512648\n", "iter 8300, loss: 82.518510\n", "iter 8400, loss: 82.448900\n", "iter 8500, loss: 82.438597\n", "iter 8600, loss: 82.449625\n", "iter 8700, loss: 82.450940\n", "iter 8800, loss: 82.330407\n", "iter 8900, loss: 82.704262\n", "iter 9000, loss: 82.595555\n", "iter 9100, loss: 82.738328\n", "iter 9200, loss: 82.954857\n", "iter 9300, loss: 82.893699\n", "iter 9400, loss: 82.574069\n", "iter 9500, loss: 82.386784\n", "iter 9600, loss: 82.385382\n", "iter 9700, loss: 82.287088\n", "iter 9800, loss: 82.185769\n", "iter 9900, loss: 81.809823\n" ] } ], "source": [ "# Stochastic Gradient Descent\n", "n, p = 0, 0\n", "smooth_loss = -np.log(1.0/vocab_size)*seq_length # loss at iteration 0\n", "learning_rate = 1e-3\n", "while n < 10000:\n", " # prepare inputs (we're sweeping from left to right in steps seq_length long)\n", " if p+seq_length+1 >= len(data) or n == 0: \n", " hprev = np.zeros((hidden_size,1)) # reset RNN memory\n", " p = 0 # go from start of data\n", " inputs = [char_to_ix[ch] for ch in data[p:p+seq_length]]\n", " targets = [char_to_ix[ch] for ch in data[p+1:p+seq_length+1]]\n", "\n", " # forward seq_length characters through the net and fetch gradient\n", " loss, dWxh, dWhh, dWhy, dbh, dby, hprev = lossFun(inputs, targets, hprev)\n", " smooth_loss = smooth_loss * 0.999 + loss * 0.001\n", " if n % 100 == 0: print 'iter %d, loss: %f' % (n, smooth_loss) # print progress\n", "\n", " # perform parameter update with Adagrad\n", " for param, dparam in zip([Wxh, Whh, Why, bh, by], \n", " [dWxh, dWhh, dWhy, dbh, dby]):\n", " param += -learning_rate * dparam\n", "\n", " p += seq_length # move data pointer\n", " n += 1 # iteration counter " ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# TODO: Implement a sampling function that lets us generate from the model." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.11" } }, "nbformat": 4, "nbformat_minor": 0 }