{"nbformat": 4, "nbformat_minor": 0, "metadata": {"language_info": {"name": "python", "version": "3.6.1", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "file_extension": ".py", "codemirror_mode": {"name": "ipython", "version": 3}, "mimetype": "text/x-python"}, "kernelspec": {"display_name": "Python 3", "name": "python3", "language": "python"}}, "cells": [{"execution_count": null, "source": "I'm just learning to use TensorFlow, following the [official tutorial][1]\n\n\n  [1]: https://www.tensorflow.org/get_started/get_started", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "6ac71b9b503d82729af86e8f25499a5db05b7025", "_cell_guid": "466233c8-78fa-48d3-8031-076fd9a9d735"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nfrom subprocess import check_output\nprint(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))", "metadata": {"_execution_state": "idle", "trusted": false, "_cell_guid": "e3362a6b-8745-4560-b81d-248772bb6491", "_uuid": "8f253058a0a1e9d2a1981f4c9c9f373149173486"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "So nice of you, Kaggle, now let's import TensorFlow", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "511d183add16cf8e1b45188da1de9dc98b39ef67", "_cell_guid": "ce09583d-3c0b-4a02-83d5-192df605ce3f"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "import tensorflow as tf", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "e19802ad23a0ff1402e61718e04648a1cd4d56e9", "_cell_guid": "5c9e4db9-a1cc-4b1e-9b1c-c5e9173cf55a"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "So, it looks like TensorFlow has it's own \"variable\" system, which is separate from Python variables. TensorFlow variables are \"executed\", or better, evaluated when the graph is run. I'm going too fast.", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "4b671320198601aee609c407cb195ea40eaf6c3a", "_cell_guid": "b333eaee-e920-40a7-b471-542928306999"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "node1 = tf.constant(3.0, dtype=tf.float32)\nnode2 = tf.constant(4.0) # also tf.float32 implicitly\nprint(node1, node2)", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "659fd2aac287097312e6138d362f6155285931b1", "_cell_guid": "33dddf6f-61f7-4311-992a-778c80770cc8"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "No mention of the 3.0 or 4.0 in the output! That's because the two constants have not been evaluated yet. They're just dumb containers with a constant value at graph-execution time.", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "0a97a9efb6da85accf8b9b781d0a6c2a117e76ec", "_cell_guid": "8bebdced-f8c0-4e57-a95b-3462627cbaf9"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "sess = tf.Session()", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "4fa5212c5557592860905165b3601938eb9751c4", "_cell_guid": "fe6a2e29-970d-4bf1-849e-d2829ffe4c65"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "A Session is like a Manager, that takes the variables and execution steps and evaluates them. Evaluating a constant for example means getting it's value. Evaluating an addition, getting the result", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "5d6cc61c-088f-4edb-b205-c2ab813ab28a", "_uuid": "016a096e95fb571692d493040cd5015deed78eaa"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "print(sess.run([node1, node2]))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "68fe3831-619e-4a1e-a75b-f42fa9ece322", "_uuid": "822dc609d857536d9f159b21654ae01962a6b776"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "As expected we get the constant values!", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "b25c520d-0086-47f6-9f66-24171f1f0217", "_uuid": "f3de53085e2b1ea5f1a13cb5bed9c6c57197ca49"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "node3 = tf.add(node1, node2)\nprint(node3)\nprint(sess.run(node3))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "60cd1e93-b28a-4093-b81e-f6200fe8d231", "_uuid": "5b81a18514a49a596955bc0e9a0810e37ff395de"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "As per node1 and node2, node3 is just an abstraction of an addition operation with the two addends, node1 and node2. The actual addition is only performed when we use the Session.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "ce837dae-aa96-4ee1-8d23-dafa994bcbb9", "_uuid": "2f82402dd5c830cdcff2641cc597041d09a55cbb"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "a = tf.placeholder(tf.float32)\nb = tf.placeholder(tf.float32)\nadder_node = a + b # same as tf.add(a, b)", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "4dae4818-8701-43fc-a3ff-e046aec480c7", "_uuid": "05fef46d9f7b0013f3042b81b356ed99dfe24518"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Instead of using boring constants, let's use placeholders, variables whose value is defined only when we run the session. This doesn't forbid us to create an adder_node that evaluates to the sum of two unknown values though.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "2dbc106d-c0f9-499f-88bd-06661d6e66e8", "_uuid": "9ca2df5e89070f9709e7cbd4f4571b46ebb39fce"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "print(adder_node)\nprint(sess.run(adder_node, { a: 3, b: 4.5 }))\nprint(sess.run(adder_node, { a: [1, 3], b: [2, 4] }))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "2224bb9b-85bc-4266-8177-5b2a551467ad", "_uuid": "65e3c392274b3b27795062f346b4b6d13655bdc2"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Again, printing the adder_node doesn't provide anything as we are literally trying to print an \"operation\", not it's value.\n\nUsing sess.run we pass the values for the placeholders that we defined in the previous step.\n\nIt looks like you can pass arrays and TensorFlow will apply the addition pairwise, which will have great uses in a few steps.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "ae1e54d9-f462-4458-a552-55ce242a459d", "_uuid": "b94c43bdc3f93f69cfd698b630c3cd4e295777a5"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "add_and_triple = adder_node * 3.\nprint(sess.run(add_and_triple, { a: 3, b: 4.5 }))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "bc5c7f2e-55e4-445c-bc67-3c87af3380ca", "_uuid": "7e5da4d83324b6d50f8b3ce0cba4f119c5997e24"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Well, just to make a more complex example, we're now taking the addition node and multiplying whatever result by 3.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "4ded0842-988b-4d12-b50e-3078287dcc9d", "_uuid": "30f934bc05650993ba746b197362bc9d3c72b4ee"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "W = tf.Variable([.3], dtype=tf.float32)\nb = tf.Variable([-.3], dtype=tf.float32)\nx = tf.placeholder(tf.float32)\nlinear_model = W * x + b", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "b7b0463b-6caf-4c9c-a652-eb0c48a80146", "_uuid": "44f39d06bf0350fd59e4cc43a5cf7668f98ec4e9"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Now things start to get interesting. We defined two W and b Variables. But what is a variable? Is it different from a placeholder or constant?\n\nYes.\n\n - A constant is something whose value will never change. \n - A placeholder value is defined by the program when we call sess.run\n - A variable is something that TensorFlow itself can change, and here is where the IA kicks in. With appropriate operations, we instruct TF to alter the variables to match the expected results.\n\nWith the last line we defined the equation of a straight line, with W and b to be altered by TF and with x provided by the session.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "7e41682d-736b-45d0-a6b0-5dff7b8a1a8e", "_uuid": "2d23d5d5cca05147b23d7144607e86124e790989"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "init = tf.global_variables_initializer()\nsess.run(init)", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "9d7805a1-c895-4f18-9c63-ec9e7dfde87e", "_uuid": "eadde73869239b423879efd698ecca5c0364a8f8"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "When we defined the tf.Variables we passed an initial value, that however is not set.\n\nFor reasons that are not completely clear yet to me, variables, unlike constants,  must be initialized in a separate session run.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "e833cfbd-06df-4dec-9992-43cfda4c6abb", "_uuid": "33b1dc7cc7a9f42fb71770826fc12354bc505133"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "print(sess.run(linear_model, { x: [1, 2, 3, 4] }))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "c70d7e52-e567-4895-8b40-e3027a5ada0b", "_uuid": "a5ac73072f09bd0e7594c38bc326f38b1e5a60b0"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "We evaluated the values of the \"straight line\" equation for some values of `x`, with the starting values of W and b. This operation still does not change them.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "2e5b4041-3e7f-4157-ad41-883e29ee4158", "_uuid": "2c791f745882bc717ceb5aa2ff57c6f1f6a74614"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "y = tf.placeholder(tf.float32)\nsquared_deltas = tf.square(linear_model - y)", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "450b717e-88bc-4732-9bf8-81929ccd5562", "_uuid": "0d76ec03874b2c397ee75da161217896de6c38bc"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Things are getting intersting now. We defined a second placeholder `y` that will contain the \"expected values\" for the result of the evaluation.\n\nThen we define a squared_deltas as the squared distance between the value evaluated by the straight line and the expected y. This will be \"how much the model is bad for value `x`\".", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "96358e79-dccf-4e52-aab4-f2194ee1ce30", "_uuid": "3a3a949b6061b22696ecbcee9df37d5cf0179fb2"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "loss = tf.reduce_sum(squared_deltas)\nprint(sess.run(loss, { x: [1, 2, 3, 4], y: [0, -1, -2, -3] }))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "00b6fdb0-8152-4da7-9e85-6aeb8e2cc83d", "_uuid": "927695c0783bad184a0e7b3a826ecd3687e65ac5"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "We then define the loss function as the sum of the previously calculated \"errors\".\n\nAnd we give it a run. We get 22.66 as the total error.\n\n**The objective of a Machine Learning software is to minimize the loss function**. In this case to find the best values for W and b, in order to have a near-perfect match between the computed line function and the desired value of `y`.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "30b618ca-343c-4065-8932-8b5f903c5eae", "_uuid": "b910b0e908384e52e67342ff165f1cd2fae3684b"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "fixW = tf.assign(W, [-1.])\nfixb = tf.assign(b, [1.])\nsess.run([fixW, fixb])\nprint(sess.run(loss, { x: [1, 2, 3, 4], y: [0, -1, -2, -3] }))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "51da1523-57ae-46ba-a32f-1346229b44f4", "_uuid": "7e3f25d7acb6789cb05b051085b278045bca0af9"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "But wait, who needs an IA? Any 7th grader can find the W and b values for a set of points.\n\nGreat but the only purpose of an IA is to do this automatically and with larger sets of points, and worse, with functions of any shape and number of dimensions.\n\nCan your 7th grader do that?", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "aefd6274-5822-465d-a052-2b05a7b418a8", "_uuid": "62418a69be2579da92c8b3fc3e6fe6aa2df4d1b9"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "sess.run(init)", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "66ce9576-8cf1-4b2a-b6a1-6b8c80d45c10", "_uuid": "192ac2b5680bde9bb764ef7af6ddf7fdf0926d8c"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Reset W and b to it's initial incorrect values so that the ML algorithm can do its job", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "2b1bf3d7-d411-4c24-830d-ee699ab3d61c", "_uuid": "ebc52632c1c6292c2c2fce4926f0ebaf79f055f9"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "optimizer = tf.train.GradientDescentOptimizer(0.01)\ntrain = optimizer.minimize(loss)", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "666f5682-9aca-4a04-8e30-68cf8bbb2360", "_uuid": "bc98edd047d4baa67c43ee3c5dace7b75d8ae067"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Skipping all the relevant theory, we are now initialising a Gradient Descent optimiser that will follow the derivatives of our loss function to find it's local minimum, and at each step of the session will apply a small change to the W and b variables to go in that direction.\n\nThe train object again is just an operation, not an actual execution of the operation, which is still done by the session.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "5138e124-47ec-4932-9841-d8143f6cbfdb", "_uuid": "e47d7140a212ef9638b53c54809f64102433c6ff"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "for i in range(1000):\n  sess.run(train, { x: [1, 2, 3, 4], y: [0, -1, -2, -3] })\n\nprint(sess.run([W, b]))", "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_cell_guid": "9b04ac10-37a0-4764-aebf-aef01c6badde", "_uuid": "539af0f1dfea3ffc1093f07bdd95852c1cc6fee4"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Here's the real deal, we are now running the GD optimizer on our dataset of Xs and Ys and with every step we get closer to the perfect matching solution.\n\nWhen after the training we print the values of W and b we can see that they are incredibly close to the expected values of [-1, 1].\n\nLet's now rewrite the program using the tf.contrib library which provides shortcuts and libraries to assist in the definition of learning models:", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "a50fcf1d-d5ed-4c26-a29d-d9af26af1606", "_uuid": "256c896efe6890aa921c7cda995c5422a6850351"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "a2a599f59fd8d8c2281d87aee354825aebbada7f", "_cell_guid": "5f4ef1e6-0f4a-43a0-989a-a7a65e432c39"}, "source": "features = [tf.contrib.layers.real_valued_column('x', dimension=1)]", "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "It is quite unclear what's happening here. Looks like we're defining an X feature of dimension 1 (??) and type real.", "metadata": {"_execution_state": "idle", "collapsed": false, "_cell_guid": "f903696e-8eb0-4a6e-a1a5-8bc31b66a788", "_uuid": "56a7bb0c49e118bd099c6d72719dbb51f67efa2e"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "8cadc17f952e709bd20ea58e2c89dd76d2d57de0", "_cell_guid": "f2273ffa-9545-4bc4-ace2-ab4fa0a23225"}, "source": "estimator = tf.contrib.learn.LinearRegressor(feature_columns=features)", "cell_type": "code", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "b8bc37087abc26ac147bb4ea4d94e63a81794784", "_cell_guid": "107da2e3-ae2f-41fd-bab5-e4d4d4b03558"}, "source": "??? We defined a LinearRegressor to optimize our model. There are many types of optimizers. This one tries to optimize the values of `W` and `b` in the equation Y = W * X + b", "cell_type": "markdown", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "240e31a578ae596add738260271e94271dfaf4f5", "_cell_guid": "2cead0a2-7cc2-454b-84a8-01fdf76e125c"}, "source": "x_train = np.array([1., 2., 3., 4.])\ny_train = np.array([0., -1., -2., -3.])", "cell_type": "code", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "d6018444128945d71ad56009b2d756d2e8346fa1", "_cell_guid": "3d0ff9fd-ccb6-4e0a-b6a0-44467b36d0b6"}, "source": "This is quite easy: we're filling up two arrays of matching X and Y values that we want to use to train our learning program. But, what's that np.array? Why not a python list? Turns out that python lists are quite slow when growing to millions of items (very likely in Machine Learning scenarios), and numpy helps with lists with a smaller memory footprint but with less features", "cell_type": "markdown", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "8457c5f2fbacc9c84250df8e0839ee9819b2026b", "_cell_guid": "c96c2534-2f91-406c-b9e4-ed73099714e5"}, "source": "input_fn = tf.contrib.learn.io.numpy_input_fn({\"x\":x_train}, y_train,\n                                              batch_size=4,\n                                              num_epochs=1000)", "cell_type": "code", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "859e660cf3261cafa55c9985a8c48ea5309dc513", "_cell_guid": "450520cd-576a-4095-8c7b-427df9151e0e"}, "source": "This somewhat perverse function generates a more complex training set from our initial dataset. The Gradient Descent algorithm works by taking batches of examples and optimizing its variables to bridge the gap with the Y set.\n\nThe `batch_size` parameter defines how large should this batches be (useful for more advanced models). In this case, all the batches cover the whole dataset of 4 examples.\n\nThe `num_epochs` is even more contrived. It indicates the number of times that the trainer has to \"visit\" the whole data set. So let's say that we have 10000 examples. If we set batch_size to 5 and num_epochs to 4, the trainer will run 2000 times to cover the whole dataset, and repeat the process 4 times. We also have steps, which we'll see in a second:", "cell_type": "markdown", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "38754521b96c1200696453c43d8f350c8eb81ff7", "_cell_guid": "347611a8-7801-4f96-81b9-264eb6660f72"}, "source": "x_eval = np.array([2., 5., 8., 1.])\ny_eval = np.array([-1.01, -4.1, -7, 0.])\neval_input_fn = tf.contrib.learn.io.numpy_input_fn({\"x\":x_eval}, y_eval,\n                                                   batch_size=4,\n                                                   num_epochs=1000)", "cell_type": "code", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "cd684aed7199675b8986937d8127fc5b4c919a6a", "_cell_guid": "3ee5be79-7169-4d4c-bc0d-0206f23bc363"}, "source": "We're creating a second group of examples. These examples will not be used to train the program, but will be used to validate it's effectiveness. So after you trained it, you want to check how it does perform on real data, and you use the evaluation dataset.\n\nFor reasons that are not completely clear to me, we are setting epochs here too, but they should have no meaning, since the number of epochs is strictly related to the training phase, not the evaluating phase.", "cell_type": "markdown", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "trusted": false, "collapsed": false, "_uuid": "4672bd3e520c68778c60b6aab5251baacd7dca6f", "_cell_guid": "a998ead1-5868-4f14-bb70-04b8900449c9"}, "source": "estimator.fit(input_fn=input_fn, steps=10000)", "cell_type": "code", "outputs": []}, {"execution_count": null, "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "9629bde7b4b530e3638384bcdf50017300c1d5c0", "_cell_guid": "4b108675-2cbd-4a43-ba42-30b798339cba"}, "source": "Time to exercise. We're finally training the variables to the input_function, with 1000 steps per batch, using Gradient Descent.", "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "train_loss = estimator.evaluate(input_fn=input_fn)\nprint(\"train loss: %r\"% train_loss)", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "84bcd7ec2836cdeed063ba3e60b0b105eb9f94ca"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "Now, without further changes to the variables, let's see how close the model is to the data. Compute the error of the model compared to the training set.\n\nLooks like we have a near 0 error (1.5 * 10^-8), which is what we expected, since we are optimizing against this dataset", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "e6f3a925e57b289ad6031c74a8c20bbf4d640c35"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "eval_loss = estimator.evaluate(input_fn=eval_input_fn)\nprint(\"eval loss: %r\"% eval_loss)", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "4441631049f1cbfd82f12906c96a9caf6155cf13"}, "cell_type": "code", "outputs": []}, {"execution_count": null, "source": "We've now tried to validate the model against new examples not present in the training dataset. We are getting a much bigger error, but still close to 0, which means that our model has been quite good at optimizing for the general case, and not just for the training set (overfitting).\n\nNotice that the eval set is voluntarly skewed to make it impossible to define a perfect linear relationship between Xs and Ys. (for example -1.01 and 4.1)", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "7c0e472b267b00f481ac716e7dfad9916014364f"}, "cell_type": "markdown", "outputs": []}, {"execution_count": null, "source": "", "metadata": {"_execution_state": "idle", "collapsed": false, "_uuid": "0364c89b07723f03a20469317370ded9d5c29e2d"}, "cell_type": "code", "outputs": []}]}