Update the Colorbot demo to use a Keras model in addition to the Estimator.
authorA. Unique TensorFlower <gardener@tensorflow.org>
Thu, 19 Apr 2018 13:58:34 +0000 (06:58 -0700)
committerTensorFlower Gardener <gardener@tensorflow.org>
Thu, 19 Apr 2018 14:01:18 +0000 (07:01 -0700)
PiperOrigin-RevId: 193508874

tensorflow/contrib/autograph/examples/notebooks/rnn_keras_estimator.ipynb [moved from tensorflow/contrib/autograph/examples/notebooks/rnn_colorbot_estimator.ipynb with 50% similarity]

@@ -62,7 +62,7 @@
         }
       },
       "source": [
-        "# Case study: building an RNN\n"
+        "# Case study: training a custom RNN, using Keras and Estimators\n"
       ]
     },
     {
         "  length = tf.cast(tf.shape(chars)[0], dtype=tf.int64)\n",
         "  return rgb, chars, length\n",
         "\n",
+        "\n",
+        "def set_static_batch_shape(batch_size):\n",
+        "  def apply(rgb, chars, length):\n",
+        "    rgb.set_shape((batch_size, None))\n",
+        "    chars.set_shape((batch_size, None, 256))\n",
+        "    length.set_shape((batch_size,))\n",
+        "    return rgb, chars, length\n",
+        "  return apply\n",
+        "\n",
+        "\n",
         "def load_dataset(data_dir, url, batch_size, training=True):\n",
         "  \"\"\"Loads the colors data at path into a tf.PaddedDataset.\"\"\"\n",
         "  path = tf.keras.utils.get_file(os.path.basename(url), url, cache_dir=data_dir)\n",
         "  if training:\n",
         "    dataset = dataset.shuffle(buffer_size=3000)\n",
         "  dataset = dataset.padded_batch(\n",
-        "      batch_size, padded_shapes=([None], [None, None], []))\n",
+        "      batch_size, padded_shapes=((None,), (None, 256), ()))\n",
+        "  # To simplify the model code, we statically set as many of the shapes that we\n",
+        "  # know.\n",
+        "  dataset = dataset.map(set_static_batch_shape(batch_size))\n",
         "  return dataset"
       ]
     },
       "source": [
         "To show the use of control flow, we write the RNN loop by hand, rather than using a pre-built RNN model.\n",
         "\n",
-        "Note how we write the model code in Eager style, with regular `if` and `while` statements. Then, we annotate the functions with `@autograph.convert` to have them automatically compiled to run in graph mode."
+        "Note how we write the model code in Eager style, with regular `if` and `while` statements. Then, we annotate the functions with `@autograph.convert` to have them automatically compiled to run in graph mode.\n",
+        "We use Keras to define the model, and we will train it using Estimators."
       ]
     },
     {
       },
       "outputs": [],
       "source": [
-        "class RnnColorbot(object):\n",
-        "  \"\"\"Holds the parameters of the colorbot model.\"\"\"\n",
+        "@autograph.convert()\n",
+        "class RnnColorbot(tf.keras.Model):\n",
+        "  \"\"\"RNN Colorbot model.\"\"\"\n",
         "\n",
         "  def __init__(self):\n",
+        "    super(RnnColorbot, self).__init__()\n",
         "    self.lower_cell = tf.contrib.rnn.LSTMBlockCell(256)\n",
         "    self.upper_cell = tf.contrib.rnn.LSTMBlockCell(128)\n",
         "    self.relu_layer = tf.layers.Dense(3, activation=tf.nn.relu)\n",
         "\n",
+        "\n",
+        "  def _rnn_layer(self, chars, cell, batch_size, training):\n",
+        "    \"\"\"A single RNN layer.\n",
+        "\n",
+        "    Args:\n",
+        "      chars: A Tensor of shape (max_sequence_length, batch_size, input_size)\n",
+        "      cell: An object of type tf.contrib.rnn.LSTMBlockCell\n",
+        "      batch_size: Int, the batch size to use\n",
+        "      training: Boolean, whether the layer is used for training\n",
+        "\n",
+        "    Returns:\n",
+        "      A Tensor of shape (max_sequence_length, batch_size, output_size).\n",
+        "    \"\"\"\n",
+        "    hidden_outputs = []\n",
+        "    autograph.utils.set_element_type(hidden_outputs, tf.float32)\n",
+        "    state, output = cell.zero_state(batch_size, tf.float32)\n",
+        "    for ch in chars:\n",
+        "      cell_output, (state, output) = cell.call(ch, (state, output))\n",
+        "      hidden_outputs.append(cell_output)\n",
+        "    hidden_outputs = hidden_outputs.stack()\n",
+        "    if training:\n",
+        "      hidden_outputs = tf.nn.dropout(hidden_outputs, 0.5)\n",
+        "    return hidden_outputs\n",
+        "\n",
+        "  def build(self, _):\n",
+        "    \"\"\"Creates the model variables. See keras.Model.build().\"\"\"\n",
         "    self.lower_cell.build(tf.TensorShape((None, 256)))\n",
         "    self.upper_cell.build(tf.TensorShape((None, 256)))\n",
-        "    self.relu_layer.build(tf.TensorShape((None, 128)))\n",
+        "    self.relu_layer.build(tf.TensorShape((None, 128)))    \n",
+        "    self.built = True\n",
         "\n",
         "\n",
-        "def rnn_layer(chars, cell, batch_size, training):\n",
-        "  \"\"\"A simple RNN layer.\n",
-        "  \n",
-        "  Args:\n",
-        "    chars: A Tensor of shape (max_sequence_length, batch_size, input_size)\n",
-        "    cell: An object of type tf.contrib.rnn.LSTMBlockCell\n",
-        "    batch_size: Int, the batch size to use\n",
-        "    training: Boolean, whether the layer is used for training\n",
+        "  def call(self, inputs, training=False):\n",
+        "    \"\"\"The RNN model code. Uses Eager and \n",
         "\n",
-        "  Returns:\n",
-        "    A Tensor of shape (max_sequence_length, batch_size, output_size).\n",
-        "  \"\"\"\n",
-        "  hidden_outputs = []\n",
-        "  autograph.utils.set_element_type(hidden_outputs, tf.float32)\n",
-        "  state, output = cell.zero_state(batch_size, tf.float32)\n",
-        "  for ch in chars:\n",
-        "    cell_output, (state, output) = cell.call(ch, (state, output))\n",
-        "    hidden_outputs.append(cell_output)\n",
-        "  hidden_outputs = hidden_outputs.stack()\n",
-        "  if training:\n",
-        "    hidden_outputs = tf.nn.dropout(hidden_outputs, 0.5)\n",
-        "  return hidden_outputs\n",
+        "    The model consists of two RNN layers (made by lower_cell and upper_cell),\n",
+        "    followed by a fully connected layer with ReLU activation.\n",
         "\n",
+        "    Args:\n",
+        "      inputs: A tuple (chars, length)\n",
+        "      training: Boolean, whether the layer is used for training\n",
         "\n",
-        "@autograph.convert(recursive=True)\n",
-        "def model(inputs, colorbot, batch_size, training):\n",
-        "  \"\"\"RNNColorbot model.\n",
-        "  \n",
-        "  The model consists of two RNN layers (made by lower_cell and upper_cell),\n",
-        "  followed by a fully connected layer with ReLU activation.\n",
-        "  \n",
-        "  Args:\n",
-        "    inputs: A tuple (chars, length)\n",
-        "    colorbot: An object of type RnnColorbot\n",
-        "    batch_size: Int, the batch size to use\n",
-        "    training: Boolean, whether the layer is used for training\n",
-        "    \n",
-        "  Returns:\n",
-        "    A Tensor of shape (batch_size, 3) - the model predictions.\n",
-        "  \"\"\"\n",
-        "  (chars, length) = inputs\n",
-        "  seq = tf.transpose(chars, [1, 0, 2])\n",
-        "  seq.set_shape((None, batch_size, 256))\n",
+        "    Returns:\n",
+        "      A Tensor of shape (batch_size, 3) - the model predictions.\n",
+        "    \"\"\"\n",
+        "    chars, length = inputs\n",
+        "    batch_size = chars.shape[0]\n",
+        "    seq = tf.transpose(chars, (1, 0, 2))\n",
         "\n",
-        "  seq = rnn_layer(seq, colorbot.lower_cell, batch_size, training)\n",
-        "  seq = rnn_layer(seq, colorbot.upper_cell, batch_size, training)\n",
+        "    seq = self._rnn_layer(seq, self.lower_cell, batch_size, training)\n",
+        "    seq = self._rnn_layer(seq, self.upper_cell, batch_size, training)\n",
         "\n",
-        "  # Grab just the end-of-sequence from each output.\n",
-        "  indices = tf.stack([length - 1, range(batch_size)], axis=1)\n",
-        "  sequence_ends = tf.gather_nd(seq, indices)\n",
-        "  return colorbot.relu_layer(sequence_ends)\n",
+        "    # Grab just the end-of-sequence from each output.\n",
+        "    indices = tf.stack([length - 1, range(batch_size)], axis=1)\n",
+        "    sequence_ends = tf.gather_nd(seq, indices)\n",
+        "    return self.relu_layer(sequence_ends)\n",
         "\n",
         "@autograph.convert()\n",
         "def loss_fn(labels, predictions):\n",
         }
       },
       "source": [
-        "We will now create the model function for the estimator.\n",
+        "We will now create the model function for the custom Estimator.\n",
         "\n",
-        "In the model function, we simply call the converted functions that we defined above - that's it!"
+        "In the model function, we simply use the model class we defined above - that's it!"
       ]
     },
     {
         "  sequence_length = features['sequence_length']\n",
         "  inputs = (chars, sequence_length)\n",
         "\n",
-        "  # Create the model components.\n",
-        "  # Simply calling the AutoGraph-ed functions and objects just works!\n",
+        "  # Create the model. Simply using the AutoGraph-ed class just works!\n",
         "  colorbot = RnnColorbot()\n",
-        "  \n",
-        "  batch_size = params['batch_size']\n",
+        "  colorbot.build(None)\n",
         "\n",
         "  if mode == tf.estimator.ModeKeys.TRAIN:\n",
-        "    predictions = model(inputs, colorbot, batch_size, training=True)\n",
+        "    predictions = colorbot(inputs, training=True)\n",
         "    loss = loss_fn(labels, predictions)\n",
         "\n",
         "    learning_rate = params['learning_rate']\n",
         "    return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)\n",
         "\n",
         "  elif mode == tf.estimator.ModeKeys.EVAL:\n",
-        "    predictions = model(inputs, colorbot, batch_size, training=False)\n",
+        "    predictions = colorbot(inputs)\n",
         "    loss = loss_fn(labels, predictions)\n",
         "\n",
         "    return tf.estimator.EstimatorSpec(mode, loss=loss)\n",
-        "  \n",
+        "\n",
         "  elif mode == tf.estimator.ModeKeys.PREDICT:\n",
-        "    # For prediction, we expect single tensors.\n",
-        "    predictions = model(inputs, colorbot, 1, training=False)\n",
+        "    predictions = colorbot(inputs)\n",
         "\n",
         "    predictions = tf.minimum(predictions, 1.0)\n",
         "    return tf.estimator.EstimatorSpec(mode, predictions=predictions)"
     },
     {
       "cell_type": "code",
-      "execution_count": 0,
+      "execution_count": 7,
       "metadata": {
         "colab": {
           "autoexec": {
         },
         "colab_type": "code",
         "executionInfo": {
-          "elapsed": 10064,
+          "elapsed": 10604,
           "status": "ok",
-          "timestamp": 1523580419240,
+          "timestamp": 1524095272039,
           "user": {
             "displayName": "",
             "photoUrl": "",
           "user_tz": 240
         },
         "id": "2pg1AfbxBJQq",
-        "outputId": "41894b16-3d3a-4e30-f6e4-5a9c837a2210",
+        "outputId": "9c924b4f-06e1-4538-976c-a3e1ddac5660",
         "slideshow": {
           "slide_type": "-"
         }
           "name": "stdout",
           "output_type": "stream",
           "text": [
-            "Eval loss at step 100: 0.0665446\n"
+            "Eval loss at step 100: 0.0674834\n"
           ]
         }
       ],
     },
     {
       "cell_type": "code",
-      "execution_count": 0,
+      "execution_count": 8,
       "metadata": {
         "colab": {
           "autoexec": {
         },
         "colab_type": "code",
         "executionInfo": {
-          "elapsed": 31286,
+          "elapsed": 7990,
           "status": "ok",
-          "timestamp": 1523580450579,
+          "timestamp": 1524095280105,
           "user": {
             "displayName": "",
             "photoUrl": "",
           "user_tz": 240
         },
         "id": "dxHex2tUN_10",
-        "outputId": "b3dc558d-b800-4e9b-e60e-3441124e80d8",
+        "outputId": "2b889e5a-b9ed-4645-bf03-d98f26c72101",
         "slideshow": {
           "slide_type": "slide"
         }
               "\u003clink rel=stylesheet type=text/css href='/nbextensions/google.colab/tabbar.css'\u003e\u003c/link\u003e"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.HTML at 0x7f4112527e90\u003e"
+              "\u003cIPython.core.display.HTML at 0x7f3f36aa6cd0\u003e"
             ]
           },
           "metadata": {
               "\u003cscript src='/nbextensions/google.colab/tabbar_main.min.js'\u003e\u003c/script\u003e"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.HTML at 0x7f4112527f10\u003e"
+              "\u003cIPython.core.display.HTML at 0x7f3eca67f7d0\u003e"
             ]
           },
           "metadata": {
               "\u003cdiv id=\"id1\"\u003e\u003c/div\u003e"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.HTML at 0x7f4112527f50\u003e"
+              "\u003cIPython.core.display.HTML at 0x7f3eca67f8d0\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"2c60f474-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = colab_lib.createTabBar({\"initialSelection\": 0, \"location\": \"top\", \"contentHeight\": [\"initial\"], \"borderColor\": [\"#a7a7a7\"], \"contentBorder\": [\"0px\"], \"tabNames\": [\"RNN Colorbot\"], \"elementId\": \"id1\"});\n",
-              "//# sourceURL=js_a0db480422"
+              "window[\"e8ddfa22-4362-11e8-91ec-c8d3ffb5fbe0\"] = colab_lib.createTabBar({\"contentBorder\": [\"0px\"], \"elementId\": \"id1\", \"borderColor\": [\"#a7a7a7\"], \"contentHeight\": [\"initial\"], \"tabNames\": [\"RNN Colorbot\"], \"location\": \"top\", \"initialSelection\": 0});\n",
+              "//# sourceURL=js_71b9087b6d"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd1d0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67f950\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"2c60f475-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_d2a46ea291"
+              "window[\"e8ddfa23-4362-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
+              "//# sourceURL=js_e390445f33"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd0d0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67f990\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"2c60f476-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
-              "//# sourceURL=js_0a8262c6e9"
+              "window[\"e8ddfa24-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
+              "//# sourceURL=js_241dd76d85"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd390\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fc50\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"2c60f477-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
-              "//# sourceURL=js_e32f85ccd2"
+              "window[\"e8ddfa25-4362-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
+              "//# sourceURL=js_60c64e3d50"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd490\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fd90\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"2c60f478-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"2c60f477-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_eaee748b21"
+              "window[\"e8ddfa26-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"e8ddfa25-4362-11e8-91ec-c8d3ffb5fbe0\"]);\n",
+              "//# sourceURL=js_14ea437cbd"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd550\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fe10\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"2c60f479-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_2befe06587"
+              "window[\"e8ddfa27-4362-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
+              "//# sourceURL=js_09294c2226"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f4112527f10\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fcd0\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"354d7b1a-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"2c60f476-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_8ec4aeeb25"
+              "window[\"ec965514-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"e8ddfa24-4362-11e8-91ec-c8d3ffb5fbe0\"]);\n",
+              "//# sourceURL=js_e5e8266997"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd690\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fe10\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"354d7b1b-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
-              "//# sourceURL=js_9f9f4574f1"
+              "window[\"ec965515-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
+              "//# sourceURL=js_07a097f0ee"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd350\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fc90\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"354d7b1c-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
-              "//# sourceURL=js_bcccd8f300"
+              "window[\"ec965516-4362-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
+              "//# sourceURL=js_790d669ca8"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd6d0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67f8d0\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"354d7b1d-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"354d7b1c-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_2c056cee72"
+              "window[\"ec965517-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"ec965516-4362-11e8-91ec-c8d3ffb5fbe0\"]);\n",
+              "//# sourceURL=js_d30df771f0"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd490\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fd90\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"354d7b1e-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_c853c3f58b"
+              "window[\"ec965518-4362-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
+              "//# sourceURL=js_8a43a2da4b"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd610\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fc50\u003e"
             ]
           },
           "metadata": {
         },
         {
           "data": {
-            "application/javascript": [
-              "window[\"354d7b1f-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"354d7b1b-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_e5730ab00d"
-            ],
+            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQwAAAENCAYAAAD60Fs2AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAACMBJREFUeJzt3F+I1XX+x/G32zjiFERUpgaFd2JBzOg5joX4h0SiMgmM\n/uhVGIlgFBlERGB3hUEkhkRdtDfRP1ACL6KpLBqcguxCjEAkmGamQcSohFHzsxe7O6zssvsydtff\n+ns8rs758j3f8z7fiyef7/k3o7XWCiDwh4s9APC/QzCAmGAAMcEAYoIBxAQDiAkGF8XTTz9d3W63\n7rvvvhoZGakVK1Zc7JEICMYlbvXq1TU8PHyxxzjPV199VcPDw/XZZ5/V22+/XVVVM2bMuMhTkRAM\n/qt+++23+uGHH+r666+vWbNmXexxuECCcQl76qmnanx8vLZs2VIDAwP1+uuv1zfffFP3339/dTqd\nWr9+fY2MjEzvv2nTpnr55ZfrgQceqIGBgXr44Yfr5MmTVVV1+vTp2r59ey1durQ6nU5t2LChTpw4\nUVVVk5OTtWXLllq6dGmtXbu23nnnnelj7tq1q7Zt21bbt2+vJUuW1HvvvVfPPvtsHTp0qAYGBmrX\nrl1/N/fRo0dr06ZN1el06u67766hoaGqqhodHa1OpzO93zPPPFO33nrr9P3t27fXm2+++e89iZyv\ncUlbtWpVGx4ebq21NjEx0brdbjtw4EBrrbUvvviidbvdduLEidZaaxs3bmxr1qxp33//fZuammob\nN25sO3fubK219tZbb7VHH320TU1NtXPnzrXDhw+3X375pbXW2kMPPdR27NjRTp8+3Y4cOdIGBwen\nn/OVV15pN910U/voo49aa61NTU21999/vz344IPTMx48eLCtWLGitdbamTNn2po1a9qePXvamTNn\n2vDwcOvv72/Hjh2bfj2HDx9urbW2du3advvtt7ejR4+21lpbuXJlO3LkyH/qVNJas8L4f6D95edC\n+/btq5UrV9by5curqmrZsmV1880316effjq977333ls33HBD9fb21h133FFHjhypqqqenp46efJk\nHTt2rGbMmFGLFi2qyy+/vCYmJurrr7+uJ598smbOnFkLFy6sDRs21N69e6eP2d/fX6tXr66qqt7e\n3n8666FDh+rUqVP1yCOPVE9PTw0ODtaqVavqgw8+qKqqJUuW1MjISB0/fryqqtauXVtffvlljY6O\n1q+//loLFy78N501/pGeiz0A/z1jY2O1f//++vjjj6vqzyE5e/ZsLVu2bHqfa665Zvr27Nmz69Sp\nU1VVdc8999TExEQ98cQT9fPPP9e6devq8ccfr8nJybryyitr9uzZ04+bP39+HT58ePr+3Llz4xkn\nJydr3rx5522bP39+TU5OVlVVp9OpoaGhuu6666rb7Va32629e/dWb29vLV68+ALOBr+HYFzi/vbT\nh3nz5tX69etrx44dF3ycnp6e2rp1a23durXGxsZq8+bNtWDBgrrtttvqp59+qlOnTlVfX19VVY2P\nj9ecOXP+4Qz/ypw5c2p8fPy8bWNjY7VgwYKqqup2u/Xiiy/WvHnzqtPp1MDAQD333HPV29tb3W73\ngl8XF8YlySXu2muvrdHR0aqqWrduXQ0NDdXnn39e586dq6mpqRoZGakff/zxXx7n4MGD9d1339W5\nc+eqr6+venp66rLLLqu5c+dWf39/vfTSS3X69On69ttv6913361169b9rnlvueWW6uvrq9dee63O\nnj1bBw8erE8++aTuvPPOqqq68cYba9asWbVv377qdDp1xRVX1NVXX10ffvjheW+I8p8hGJe4zZs3\n1+7du6vb7db+/ftr9+7dtWfPnlq2bFmtWrWq3njjjen3OP7ZSuD48eO1bdu2Wrx4cd111121dOnS\n6Sjs3LmzRkdHa/ny5bVt27Z67LHHzrvMuRAzZ86sV199tQ4cOFCDg4P1/PPP1wsvvDC9wqj68yrj\nqquumr7U+WsoFi1a9Luek9yM1vyBDpCxwgBiggHEBAOICQYQ+z/7PYzjf/QRGVxM12z68u+2WWEA\nMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHE\nBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhAT\nDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEww\ngJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEA\nYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOI\nCQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAm\nGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhg\nADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIB\nxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQ\nEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBM\nMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHB\nAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQD\niAkGEBMMIDajtdYu9hDA/wYrDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEA\nYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4j9CY2LTAbbRbWuAAAAAElFTkSuQmCC\n",
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a2050\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"354d7b20-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
-              "//# sourceURL=js_a897ef7e24"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a2250\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"354d7b21-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
-              "//# sourceURL=js_565fa3d154"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f4113124d90\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"354d7b22-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"354d7b21-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_222e0dc6af"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f4113124c10\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"354d7b23-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_831db7458f"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f4113124310\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fab4-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"354d7b20-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_adb576c6eb"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f990850\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fab5-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
-              "//# sourceURL=js_9418f2d32f"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f990850\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fab6-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
-              "//# sourceURL=js_3fad25f306"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f4112527ed0\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fab7-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3803fab6-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_45b9340e7b"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f990c90\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fab8-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_bec9896d44"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f990a10\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fab9-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3803fab5-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_460b91ad4a"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3a10\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803faba-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
-              "//# sourceURL=js_7dedd0b037"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3890\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fabb-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
-              "//# sourceURL=js_4b1c977dc7"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3bd0\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fabc-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3803fabb-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_d64fedfcf9"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3410\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3803fabd-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_3e8c929c3f"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3c50\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3b9b986c-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3803faba-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_9f9cf2b76f"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd590\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3b9b986d-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
-              "//# sourceURL=js_b402e6b587"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3d90\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3b9b986e-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
-              "//# sourceURL=js_9b7d66db72"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3b10\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3b9b986f-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3b9b986e-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_11ec213a3f"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3950\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "application/javascript": [
-              "window[\"3b9b9870-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_9c055e4bc0"
-            ],
-            "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41b21d3850\u003e"
-            ]
-          },
-          "metadata": {
-            "tags": [
-              "id1_content_0",
-              "outputarea_id1"
-            ]
-          },
-          "output_type": "display_data"
-        },
-        {
-          "data": {
-            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQwAAAENCAYAAAD60Fs2AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAACMRJREFUeJzt3F+IlfW+x/Gvp3FECyIqU4PCO7EgZnQtnUJ0JJGoTDoY\n/dGrMBJhosggIgK7KwwiMdxRF11F/0AJvIisLBqcguxCjEAkmNQGcRvVwIzm71zsc4Yje7P3x9h7\nz97u1+tqrYdnPeu7nos3v2f9m9FaawUQ+K/pHgD49yEYQEwwgJhgADHBAGKCAcQEg2nx9NNPV7fb\nrfvuu69GRkZq5cqV0z0SAcG4xK1evbqGh4ene4wLfPXVVzU8PFyfffZZvf3221VVNWPGjGmeioRg\n8E/122+/1Q8//FDXX399zZo1a7rH4SIJxiXsqaeeqhMnTtSWLVuqv7+/Xn/99frmm2/q/vvvr06n\nU+vXr6+RkZGp/Tdt2lQvv/xyPfDAA9Xf318PP/xwnTlzpqqqJicna9u2bbVs2bLqdDq1YcOGOn36\ndFVVjY2N1ZYtW2rZsmW1du3aeuedd6aOuXPnzhoaGqpt27bV0qVL67333qtnn322Dh06VP39/bVz\n584/m/vo0aO1adOm6nQ6dffdd9f+/furqmp0dLQ6nc7Ufs8880zdeuutU/e3bdtWb7755t/3JHKh\nxiVtcHCwDQ8Pt9ZaO3nyZOt2u+3AgQOttda++OKL1u122+nTp1trrW3cuLGtWbOmff/9921iYqJt\n3Lix7dixo7XW2ltvvdUeffTRNjEx0c6fP98OHz7cfvnll9Zaaw899FDbvn17m5ycbEeOHGnLly+f\nes5XXnml3XTTTe2jjz5qrbU2MTHR3n///fbggw9OzXjw4MG2cuXK1lprZ8+ebWvWrGm7d+9uZ8+e\nbcPDw62vr68dO3Zs6vUcPny4tdba2rVr2+23396OHj3aWmtt1apV7ciRI/+oU0lrzQrjP0D7358L\n7d27t1atWlUrVqyoqqqBgYG6+eab69NPP53a9957760bbrihent764477qgjR45UVVVPT0+dOXOm\njh07VjNmzKjFixfX5ZdfXidPnqyvv/66nnzyyZo5c2YtWrSoNmzYUHv27Jk6Zl9fX61evbqqqnp7\ne//qrIcOHarx8fF65JFHqqenp5YvX16Dg4P1wQcfVFXV0qVLa2RkpE6dOlVVVWvXrq0vv/yyRkdH\n69dff61Fixb9nc4af0nPdA/AP8/x48dr37599fHHH1fVn0Jy7ty5GhgYmNrnmmuumbo9e/bsGh8f\nr6qqe+65p06ePFlPPPFE/fzzz7Vu3bp6/PHHa2xsrK688sqaPXv21OMWLFhQhw8fnro/b968eMax\nsbGaP3/+BdsWLFhQY2NjVVXV6XRq//79dd1111W3261ut1t79uyp3t7eWrJkyUWcDX4PwbjE/f9P\nH+bPn1/r16+v7du3X/Rxenp6auvWrbV169Y6fvx4bd68uRYuXFi33XZb/fTTTzU+Pl5z5sypqqoT\nJ07U3Llz/+IMf8vcuXPrxIkTF2w7fvx4LVy4sKqqut1uvfjiizV//vzqdDrV399fzz33XPX29la3\n273o18XFcUlyibv22mtrdHS0qqrWrVtX+/fvr88//7zOnz9fExMTNTIyUj/++OPfPM7Bgwfru+++\nq/Pnz9ecOXOqp6enLrvsspo3b1719fXVSy+9VJOTk/Xtt9/Wu+++W+vWrftd895yyy01Z86ceu21\n1+rcuXN18ODB+uSTT+rOO++sqqobb7yxZs2aVXv37q1Op1NXXHFFXX311fXhhx9e8IYo/xiCcYnb\nvHlz7dq1q7rdbu3bt6927dpVu3fvroGBgRocHKw33nhj6j2Ov7YSOHXqVA0NDdWSJUvqrrvuqmXL\nlk1FYceOHTU6OlorVqyooaGheuyxxy64zLkYM2fOrFdffbUOHDhQy5cvr+eff75eeOGFqRVG1Z9W\nGVddddXUpc7/hWLx4sW/6znJzWjNH+gAGSsMICYYQEwwgJhgALF/2e9h/PEP/z3dI8B/tKseee/P\ntllhADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEA\nYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOI\nCQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAm\nGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhg\nADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIB\nxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQ\nEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBM\nMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHB\nAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQD\niAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHEBAOICQYQEwwg\nJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICY\nYAAxwQBiggHEBAOICQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEwwgJhgADHBAGKC\nAcQEA4gJBhATDCA2o7XWpnsI4N+DFQYQEwwgJhhATDCAmGAAMcEAYoIBxAQDiAkGEBMMICYYQEww\ngJhgADHBAGKCAcQEA4gJBhATDCAmGEBMMICYYAAxwQBiggHE/gfh60wGjfc7LQAAAABJRU5ErkJg\ngg==\n",
-            "text/plain": [
-              "\u003cmatplotlib.figure.Figure at 0x7f4113124310\u003e"
+              "\u003cmatplotlib.figure.Figure at 0x7f3ecc00bf10\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3b9b9871-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3b9b986d-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_ba6a061307"
+              "window[\"ec965519-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"ec965515-4362-11e8-91ec-c8d3ffb5fbe0\"]);\n",
+              "//# sourceURL=js_893ad561f4"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd890\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31b55c90\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3b9b9872-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
-              "//# sourceURL=js_83e3496927"
+              "window[\"ec96551a-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.getActiveOutputArea();\n",
+              "//# sourceURL=js_2d99e0ac17"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd590\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67fe50\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3b9b9873-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
-              "//# sourceURL=js_f437bab20d"
+              "window[\"ec96551b-4362-11e8-91ec-c8d3ffb5fbe0\"] = document.querySelector(\"#id1_content_0\");\n",
+              "//# sourceURL=js_5c19462e32"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a22d0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31b55dd0\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3b9b9874-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3b9b9873-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_93aa63450e"
+              "window[\"ec96551c-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"ec96551b-4362-11e8-91ec-c8d3ffb5fbe0\"]);\n",
+              "//# sourceURL=js_b9c8b7567b"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a2b90\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31b55a50\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3b9b9875-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
-              "//# sourceURL=js_aca189bea5"
+              "window[\"ec96551d-4362-11e8-91ec-c8d3ffb5fbe0\"] = window[\"id1\"].setSelectedTabIndex(0);\n",
+              "//# sourceURL=js_fd05186348"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd4d0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31b55810\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "text/html": [
-              "\u003cdiv class=id_100313201 style=\"margin-right:10px; display:flex;align-items:center;\"\u003e\u003cspan style=\"margin-right: 3px;\"\u003e\u003c/span\u003e\u003c/div\u003e"
+              "\u003cdiv class=id_888646481 style=\"margin-right:10px; display:flex;align-items:center;\"\u003e\u003cspan style=\"margin-right: 3px;\"\u003e\u003c/span\u003e\u003c/div\u003e"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.HTML at 0x7f410f990a90\u003e"
+              "\u003cIPython.core.display.HTML at 0x7f3f32414810\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3b9b9876-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = jQuery(\".id_100313201 span\");\n",
-              "//# sourceURL=js_5df1fe383e"
+              "window[\"ec96551e-4362-11e8-91ec-c8d3ffb5fbe0\"] = jQuery(\".id_888646481 span\");\n",
+              "//# sourceURL=js_efef96e882"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f410f8fd490\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31b55710\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3b9b9877-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"3b9b9876-3eb4-11e8-91ec-c8d3ffb5fbe0\"].text(\"Give me a color name (or press 'enter' to exit): \");\n",
-              "//# sourceURL=js_c62c7174ad"
+              "window[\"ec96551f-4362-11e8-91ec-c8d3ffb5fbe0\"] = window[\"ec96551e-4362-11e8-91ec-c8d3ffb5fbe0\"].text(\"Give me a color name (or press 'enter' to exit): \");\n",
+              "//# sourceURL=js_6eca889864"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a2390\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3eca67f990\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3ed76584-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = jQuery(\".id_100313201 input\");\n",
-              "//# sourceURL=js_2e2201ddc4"
+              "window[\"ed8ea972-4362-11e8-91ec-c8d3ffb5fbe0\"] = jQuery(\".id_888646481 input\");\n",
+              "//# sourceURL=js_f02070cc60"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a2810\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31b553d0\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3ed76585-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"3ed76584-3eb4-11e8-91ec-c8d3ffb5fbe0\"].remove();\n",
-              "//# sourceURL=js_288e5283d6"
+              "window[\"ed8ea973-4362-11e8-91ec-c8d3ffb5fbe0\"] = window[\"ed8ea972-4362-11e8-91ec-c8d3ffb5fbe0\"].remove();\n",
+              "//# sourceURL=js_ed9faba660"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a26d0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31a95450\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3ed76586-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = jQuery(\".id_100313201 span\");\n",
-              "//# sourceURL=js_2f31d19cde"
+              "window[\"ed8ea974-4362-11e8-91ec-c8d3ffb5fbe0\"] = jQuery(\".id_888646481 span\");\n",
+              "//# sourceURL=js_f3458d7074"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a2fd0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31a95250\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3ed76587-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = window[\"3ed76586-3eb4-11e8-91ec-c8d3ffb5fbe0\"].text(\"Give me a color name (or press 'enter' to exit): \");\n",
-              "//# sourceURL=js_2fbbcda050"
+              "window[\"ed8ea975-4362-11e8-91ec-c8d3ffb5fbe0\"] = window[\"ed8ea974-4362-11e8-91ec-c8d3ffb5fbe0\"].text(\"Give me a color name (or press 'enter' to exit): \");\n",
+              "//# sourceURL=js_3ffd97bd6f"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f4112527e90\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31a953d0\u003e"
             ]
           },
           "metadata": {
         {
           "data": {
             "application/javascript": [
-              "window[\"3ed76588-3eb4-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"3b9b9872-3eb4-11e8-91ec-c8d3ffb5fbe0\"]);\n",
-              "//# sourceURL=js_f94d975cf3"
+              "window[\"ed8ea976-4362-11e8-91ec-c8d3ffb5fbe0\"] = google.colab.output.setActiveOutputArea(window[\"ec96551a-4362-11e8-91ec-c8d3ffb5fbe0\"]);\n",
+              "//# sourceURL=js_7f73e8bcca"
             ],
             "text/plain": [
-              "\u003cIPython.core.display.Javascript at 0x7f41127a2fd0\u003e"
+              "\u003cIPython.core.display.Javascript at 0x7f3f31b55710\u003e"
             ]
           },
           "metadata": {
         "def predict_input_fn(color_name):\n",
         "  \"\"\"An input function for prediction.\"\"\"\n",
         "  _, chars, sequence_length = parse(color_name)\n",
-        "  \n",
+        "\n",
         "  # We create a batch of a single element.\n",
         "  features = {\n",
         "      'chars': tf.expand_dims(chars, 0),\n",
     "colab": {
       "collapsed_sections": [],
       "default_view": {},
-      "name": "RNN Colorbot using Estimators",
+      "last_runtime": {
+        "build_target": "",
+        "kind": "local"
+      },
+      "name": "RNN Colorbot using Keras and Estimators",
       "provenance": [
         {
           "file_id": "1CtzefX39ffFibX_BqE6cRbT0UW_DdVKl",