{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'2.0.8'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import keras\n",
    "keras.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Advanced usage of recurrent neural networks\n",
    "\n",
    "This notebook contains the code samples found in Chapter 6, Section 3 of [Deep Learning with Python](https://www.manning.com/books/deep-learning-with-python?a_aid=keras&a_bid=76564dff). Note that the original text features far more content, in particular further explanations and figures: in this notebook, you will only find source code and related comments.\n",
    "\n",
    "---\n",
    "\n",
    "In this section, we will review three advanced techniques for improving the performance and generalization power of recurrent neural \n",
    "networks. By the end of the section, you will know most of what there is to know about using recurrent networks with Keras. We will \n",
    "demonstrate all three concepts on a weather forecasting problem, where we have access to a timeseries of data points coming from sensors \n",
    "installed on the roof of a building, such as temperature, air pressure, and humidity, which we use to predict what the temperature will be \n",
    "24 hours after the last data point collected. This is a fairly challenging problem that exemplifies many common difficulties encountered \n",
    "when working with timeseries.\n",
    "\n",
    "We will cover the following techniques:\n",
    "\n",
    "* *Recurrent dropout*, a specific, built-in way to use dropout to fight overfitting in recurrent layers.\n",
    "* *Stacking recurrent layers*, to increase the representational power of the network (at the cost of higher computational loads).\n",
    "* *Bidirectional recurrent layers*, which presents the same information to a recurrent network in different ways, increasing accuracy and \n",
    "mitigating forgetting issues."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A temperature forecasting problem\n",
    "\n",
    "Until now, the only sequence data we have covered has been text data, for instance the IMDB dataset and the Reuters dataset. But sequence \n",
    "data is found in many more problems than just language processing. In all of our examples in this section, we will be playing with a weather \n",
    "timeseries dataset recorded at the Weather Station at the Max-Planck-Institute for Biogeochemistry in Jena, Germany: http://www.bgc-jena.mpg.de/wetter/.\n",
    "\n",
    "In this dataset, fourteen different quantities (such air temperature, atmospheric pressure, humidity, wind direction, etc.) are recorded \n",
    "every ten minutes, over several years. The original data goes back to 2003, but we limit ourselves to data from 2009-2016. This dataset is \n",
    "perfect for learning to work with numerical timeseries. We will use it to build a model that takes as input some data from the recent past (a \n",
    "few days worth of data points) and predicts the air temperature 24 hours in the future."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's take a look at the data:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['\"Date Time\"', '\"p (mbar)\"', '\"T (degC)\"', '\"Tpot (K)\"', '\"Tdew (degC)\"', '\"rh (%)\"', '\"VPmax (mbar)\"', '\"VPact (mbar)\"', '\"VPdef (mbar)\"', '\"sh (g/kg)\"', '\"H2OC (mmol/mol)\"', '\"rho (g/m**3)\"', '\"wv (m/s)\"', '\"max. wv (m/s)\"', '\"wd (deg)\"']\n",
      "420551\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "data_dir = '/home/ubuntu/data/'\n",
    "fname = os.path.join(data_dir, 'jena_climate_2009_2016.csv')\n",
    "\n",
    "f = open(fname)\n",
    "data = f.read()\n",
    "f.close()\n",
    "\n",
    "lines = data.split('\\n')\n",
    "header = lines[0].split(',')\n",
    "lines = lines[1:]\n",
    "\n",
    "print(header)\n",
    "print(len(lines))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's convert all of these 420,551 lines of data into a Numpy array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "float_data = np.zeros((len(lines), len(header) - 1))\n",
    "for i, line in enumerate(lines):\n",
    "    values = [float(x) for x in line.split(',')[1:]]\n",
    "    float_data[i, :] = values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For instance, here is the plot of temperature (in degrees Celsius) over time:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\nAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f33d00b0ef0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from matplotlib import pyplot as plt\n",
    "\n",
    "temp = float_data[:, 1]  # temperature (in degrees Celsius)\n",
    "plt.plot(range(len(temp)), temp)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "On this plot, you can clearly see the yearly periodicity of temperature.\n",
    "\n",
    "Here is a more narrow plot of the first ten days of temperature data (since the data is recorded every ten minutes, we get 144 data points \n",
    "per day):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f336e862da0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(range(1440), temp[:1440])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "On this plot, you can see daily periodicity, especially evident for the last 4 days. We can also note that this ten-days period must be \n",
    "coming from a fairly cold winter month.\n",
    "\n",
    "If we were trying to predict average temperature for the next month given a few month of past data, the problem would be easy, due to the \n",
    "reliable year-scale periodicity of the data. But looking at the data over a scale of days, the temperature looks a lot more chaotic. So is \n",
    "this timeseries predictable at a daily scale? Let's find out."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preparing the data\n",
    "\n",
    "\n",
    "The exact formulation of our problem will be the following: given data going as far back as `lookback` timesteps (a timestep is 10 minutes) \n",
    "and sampled every `steps` timesteps, can we predict the temperature in `delay` timesteps?\n",
    "\n",
    "We will use the following parameter values:\n",
    "\n",
    "* `lookback = 720`, i.e. our observations will go back 5 days.\n",
    "* `steps = 6`, i.e. our observations will be sampled at one data point per hour.\n",
    "* `delay = 144`, i.e. our targets will be 24 hours in the future.\n",
    "\n",
    "To get started, we need to do two things:\n",
    "\n",
    "* Preprocess the data to a format a neural network can ingest. This is easy: the data is already numerical, so we don't need to do any \n",
    "vectorization. However each timeseries in the data is on a different scale (e.g. temperature is typically between -20 and +30, but \n",
    "pressure, measured in mbar, is around 1000). So we will normalize each timeseries independently so that they all take small values on a \n",
    "similar scale.\n",
    "* Write a Python generator that takes our current array of float data and yields batches of data from the recent past, alongside with a \n",
    "target temperature in the future. Since the samples in our dataset are highly redundant (e.g. sample `N` and sample `N + 1` will have most \n",
    "of their timesteps in common), it would be very wasteful to explicitly allocate every sample. Instead, we will generate the samples on the \n",
    "fly using the original data.\n",
    "\n",
    "We preprocess the data by subtracting the mean of each timeseries and dividing by the standard deviation. We plan on using the first \n",
    "200,000 timesteps as training data, so we compute the mean and standard deviation only on this fraction of the data:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "mean = float_data[:200000].mean(axis=0)\n",
    "float_data -= mean\n",
    "std = float_data[:200000].std(axis=0)\n",
    "float_data /= std"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Now here is the data generator that we will use. It yields a tuple `(samples, targets)` where `samples` is one batch of input data and \n",
    "`targets` is the corresponding array of target temperatures. It takes the following arguments:\n",
    "\n",
    "* `data`: The original array of floating point data, which we just normalized in the code snippet above.\n",
    "* `lookback`: How many timesteps back should our input data go.\n",
    "* `delay`: How many timesteps in the future should our target be.\n",
    "* `min_index` and `max_index`: Indices in the `data` array that delimit which timesteps to draw from. This is useful for keeping a segment \n",
    "of the data for validation and another one for testing.\n",
    "* `shuffle`: Whether to shuffle our samples or draw them in chronological order.\n",
    "* `batch_size`: The number of samples per batch.\n",
    "* `step`: The period, in timesteps, at which we sample data. We will set it 6 in order to draw one data point every hour."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def generator(data, lookback, delay, min_index, max_index,\n",
    "              shuffle=False, batch_size=128, step=6):\n",
    "    if max_index is None:\n",
    "        max_index = len(data) - delay - 1\n",
    "    i = min_index + lookback\n",
    "    while 1:\n",
    "        if shuffle:\n",
    "            rows = np.random.randint(\n",
    "                min_index + lookback, max_index, size=batch_size)\n",
    "        else:\n",
    "            if i + batch_size >= max_index:\n",
    "                i = min_index + lookback\n",
    "            rows = np.arange(i, min(i + batch_size, max_index))\n",
    "            i += len(rows)\n",
    "\n",
    "        samples = np.zeros((len(rows),\n",
    "                           lookback // step,\n",
    "                           data.shape[-1]))\n",
    "        targets = np.zeros((len(rows),))\n",
    "        for j, row in enumerate(rows):\n",
    "            indices = range(rows[j] - lookback, rows[j], step)\n",
    "            samples[j] = data[indices]\n",
    "            targets[j] = data[rows[j] + delay][1]\n",
    "        yield samples, targets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Now let's use our abstract generator function to instantiate three generators, one for training, one for validation and one for testing. \n",
    "Each will look at different temporal segments of the original data: the training generator looks at the first 200,000 timesteps, the \n",
    "validation generator looks at the following 100,000, and the test generator looks at the remainder."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "lookback = 1440\n",
    "step = 6\n",
    "delay = 144\n",
    "batch_size = 128\n",
    "\n",
    "train_gen = generator(float_data,\n",
    "                      lookback=lookback,\n",
    "                      delay=delay,\n",
    "                      min_index=0,\n",
    "                      max_index=200000,\n",
    "                      shuffle=True,\n",
    "                      step=step, \n",
    "                      batch_size=batch_size)\n",
    "val_gen = generator(float_data,\n",
    "                    lookback=lookback,\n",
    "                    delay=delay,\n",
    "                    min_index=200001,\n",
    "                    max_index=300000,\n",
    "                    step=step,\n",
    "                    batch_size=batch_size)\n",
    "test_gen = generator(float_data,\n",
    "                     lookback=lookback,\n",
    "                     delay=delay,\n",
    "                     min_index=300001,\n",
    "                     max_index=None,\n",
    "                     step=step,\n",
    "                     batch_size=batch_size)\n",
    "\n",
    "# This is how many steps to draw from `val_gen`\n",
    "# in order to see the whole validation set:\n",
    "val_steps = (300000 - 200001 - lookback) // batch_size\n",
    "\n",
    "# This is how many steps to draw from `test_gen`\n",
    "# in order to see the whole test set:\n",
    "test_steps = (len(float_data) - 300001 - lookback) // batch_size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A common sense, non-machine learning baseline\n",
    "\n",
    "\n",
    "Before we start leveraging black-box deep learning models to solve our temperature prediction problem, let's try out a simple common-sense \n",
    "approach. It will serve as a sanity check, and it will establish a baseline that we will have to beat in order to demonstrate the \n",
    "usefulness of more advanced machine learning models. Such common-sense baselines can be very useful when approaching a new problem for \n",
    "which there is no known solution (yet). A classic example is that of unbalanced classification tasks, where some classes can be much more \n",
    "common than others. If your dataset contains 90% of instances of class A and 10% of instances of class B, then a common sense approach to \n",
    "the classification task would be to always predict \"A\" when presented with a new sample. Such a classifier would be 90% accurate overall, \n",
    "and any learning-based approach should therefore beat this 90% score in order to demonstrate usefulness. Sometimes such elementary \n",
    "baseline can prove surprisingly hard to beat.\n",
    "\n",
    "In our case, the temperature timeseries can safely be assumed to be continuous (the temperatures tomorrow are likely to be close to the \n",
    "temperatures today) as well as periodical with a daily period. Thus a common sense approach would be to always predict that the temperature \n",
    "24 hours from now will be equal to the temperature right now. Let's evaluate this approach, using the Mean Absolute Error metric (MAE). \n",
    "Mean Absolute Error is simply equal to:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "np.mean(np.abs(preds - targets))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's our evaluation loop:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.289735972991\n"
     ]
    }
   ],
   "source": [
    "def evaluate_naive_method():\n",
    "    batch_maes = []\n",
    "    for step in range(val_steps):\n",
    "        samples, targets = next(val_gen)\n",
    "        preds = samples[:, -1, 1]\n",
    "        mae = np.mean(np.abs(preds - targets))\n",
    "        batch_maes.append(mae)\n",
    "    print(np.mean(batch_maes))\n",
    "    \n",
    "evaluate_naive_method()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It yields a MAE of 0.29. Since our temperature data has been normalized to be centered on 0 and have a standard deviation of one, this \n",
    "number is not immediately interpretable. It translates to an average absolute error of `0.29 * temperature_std` degrees Celsius, i.e. \n",
    "2.57˚C. That's a fairly large average absolute error -- now the game is to leverage our knowledge of deep learning to do better. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A basic machine learning approach\n",
    "\n",
    "In the same way that it is useful to establish a common sense baseline before trying machine learning approaches, it is useful to try \n",
    "simple and cheap machine learning models (such as small densely-connected networks) before looking into complicated and computationally \n",
    "expensive models such as RNNs. This is the best way to make sure that any further complexity we throw at the problem later on is legitimate \n",
    "and delivers real benefits.\n",
    "\n",
    "Here is a simply fully-connected model in which we start by flattening the data, then run it through two `Dense` layers. Note the lack of \n",
    "activation function on the last `Dense` layer, which is typical for a regression problem. We use MAE as the loss. Since we are evaluating \n",
    "on the exact same data and with the exact same metric as with our common sense approach, the results will be directly comparable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/20\n",
      "500/500 [==============================] - 10s - loss: 1.5009 - val_loss: 0.4131\n",
      "Epoch 2/20\n",
      "500/500 [==============================] - 10s - loss: 0.4272 - val_loss: 0.2994\n",
      "Epoch 3/20\n",
      "500/500 [==============================] - 9s - loss: 0.2837 - val_loss: 0.3115\n",
      "Epoch 4/20\n",
      "500/500 [==============================] - 9s - loss: 0.2629 - val_loss: 0.3213\n",
      "Epoch 5/20\n",
      "500/500 [==============================] - 9s - loss: 0.2486 - val_loss: 0.3156\n",
      "Epoch 6/20\n",
      "500/500 [==============================] - 9s - loss: 0.2405 - val_loss: 0.3144\n",
      "Epoch 7/20\n",
      "500/500 [==============================] - 9s - loss: 0.2351 - val_loss: 0.3165\n",
      "Epoch 8/20\n",
      "500/500 [==============================] - 9s - loss: 0.2289 - val_loss: 0.3151\n",
      "Epoch 9/20\n",
      "500/500 [==============================] - 9s - loss: 0.2248 - val_loss: 0.3238\n",
      "Epoch 10/20\n",
      "500/500 [==============================] - 9s - loss: 0.2215 - val_loss: 0.3442\n",
      "Epoch 11/20\n",
      "500/500 [==============================] - 9s - loss: 0.2161 - val_loss: 0.3247\n",
      "Epoch 12/20\n",
      "500/500 [==============================] - 9s - loss: 0.2136 - val_loss: 0.3282\n",
      "Epoch 13/20\n",
      "500/500 [==============================] - 9s - loss: 0.2117 - val_loss: 0.3404\n",
      "Epoch 14/20\n",
      "500/500 [==============================] - 9s - loss: 0.2087 - val_loss: 0.3359\n",
      "Epoch 15/20\n",
      "500/500 [==============================] - 9s - loss: 0.2076 - val_loss: 0.3567\n",
      "Epoch 16/20\n",
      "500/500 [==============================] - 9s - loss: 0.2055 - val_loss: 0.3316\n",
      "Epoch 17/20\n",
      "500/500 [==============================] - 9s - loss: 0.2030 - val_loss: 0.3437\n",
      "Epoch 18/20\n",
      "500/500 [==============================] - 9s - loss: 0.2016 - val_loss: 0.3312\n",
      "Epoch 19/20\n",
      "500/500 [==============================] - 9s - loss: 0.1985 - val_loss: 0.3472\n",
      "Epoch 20/20\n",
      "500/500 [==============================] - 9s - loss: 0.1985 - val_loss: 0.3545\n"
     ]
    }
   ],
   "source": [
    "from keras.models import Sequential\n",
    "from keras import layers\n",
    "from keras.optimizers import RMSprop\n",
    "\n",
    "model = Sequential()\n",
    "model.add(layers.Flatten(input_shape=(lookback // step, float_data.shape[-1])))\n",
    "model.add(layers.Dense(32, activation='relu'))\n",
    "model.add(layers.Dense(1))\n",
    "\n",
    "model.compile(optimizer=RMSprop(), loss='mae')\n",
    "history = model.fit_generator(train_gen,\n",
    "                              steps_per_epoch=500,\n",
    "                              epochs=20,\n",
    "                              validation_data=val_gen,\n",
    "                              validation_steps=val_steps)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's display the loss curves for validation and training:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3317e5a2b0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\nfvgNG4beKK1bh5p/uly4tWgR9O0Ld9wR/v75z6Hd/je/gQEDwgnvVBJP0l8CdDOzrmbWGBgDzIst\nYGbdYl5+E1gbTW8XnQjGzI4BugHrExG4iNSMZ56Byy+H008PSbxhJTp2t28fkl5OTjhJWVhYU1Gm\nhgcfhDPOCCdmV66E554LJ7RT+WR2hUnf3fOBa4AFwGpgrruvNLMpUU8dgGvMbKWZLQMmAZdE008F\nlkfT/wJMcPePE/4uRMrhDrffDg88kOxIUt8//xm6Y2ZlheTftGnl1zFoUGjD/tvfYPr0xMcYa88e\nePPNmt1Gafbvh+9/P7TZf+MbsHhx6LpaJ8TTBlSbD7XpSyIVFrr/6EehnRXcb7892RGlrtdfd2/e\n3L13b/ft26u3rsJC9+9+1z0jw/0f/0hMfCU9/bR7p07hcx092n3TpprZTkl5ee6nnRa2+5OfuOfn\n1852K0KcbfpJT/IlH0r6kkg33xy+5ddcE05IgvuUKcmOKvUsXx5OPh57bOKS5+7d7j17urdr5/7h\nh4lZp7t7To77iBHhszz+ePcbbnBv0sS9VSv33/++Zk+cLl/u3qVL2N7jj9fcdqpCSV/S3tSp4Rt+\n5ZWh90l+vvtFF4Vpt96a7OiqZs8e99/+1n3u3MQl57Vr3du3d+/Qwf399xOzziKrV7u3aOF+8snu\nX3xRvXXt2+c+fbp7s2bhceedYZq7+5o1oecQhL9r1lQ38kP99a/hl1CHDu6LFyd+/dWlpC9p7e67\nw7d73LiDf37n57tfckmY9/Of1153ukR4/nn3zp29uKkK3I85xv3ii90fesh91arKv58PPwzrzMx0\nX7myJqJ2//OfQ6wTJ1Z9Ha+9Fmr1EGr5GzYcWqagINT0W7UKNfGpUw8cFKqjoMD9l78M2x440H3j\nxuqvsyYo6Uva+t3vwjf7vPNC3/GS8vPdL7sslLnlltRP/Bs3hjZrcO/Rw33hQvc33nCfMcP93HND\n80nRQSAzMyTF6dPd//Of8mvXW7e6d+/u3rKl+5IlNfsefvzjEN+sWZVbbvt29/Hjw7JHHeX+zDMV\nL7Np04H91adP9Wrle/YcWNfFF7t/9lnV11XTlPQlLf3xj+5m7mefXX7CKyhwv+KK8B9w002pmfjz\n88MFUi1bujdtGmqupb2nwkL3d991f/hh98svd//qVw8cBJo2dT/1VPcbb3R/4QX3Tz4Jy+zY4d6/\n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\njSjpi4ikkf8PQHVe3fAN/ToAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3317ee2e80>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "loss = history.history['loss']\n",
    "val_loss = history.history['val_loss']\n",
    "\n",
    "epochs = range(len(loss))\n",
    "\n",
    "plt.figure()\n",
    "\n",
    "plt.plot(epochs, loss, 'bo', label='Training loss')\n",
    "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
    "plt.title('Training and validation loss')\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Some of our validation losses get close to the no-learning baseline, but not very reliably. This goes to show the merit of having had this baseline in the first place: it turns out not to be so easy to outperform. Our \n",
    "common sense contains already a lot of valuable information that a machine learning model does not have access to.\n",
    "\n",
    "You may ask, if there exists a simple, well-performing model to go from the data to the targets (our common sense baseline), why doesn't \n",
    "the model we are training find it and improve on it? Simply put: because this simple solution is not what our training setup is looking \n",
    "for. The space of models in which we are searching for a solution, i.e. our hypothesis space, is the space of all possible 2-layer networks \n",
    "with the configuration that we defined. These networks are already fairly complicated. When looking for a solution with a space of \n",
    "complicated models, the simple well-performing baseline might be unlearnable, even if it's technically part of the hypothesis space. That \n",
    "is a pretty significant limitation of machine learning in general: unless the learning algorithm is hard-coded to look for a specific kind \n",
    "of simple model, parameter learning can sometimes fail to find a simple solution to a simple problem."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A first recurrent baseline\n",
    "\n",
    "\n",
    "Our first fully-connected approach didn't do so well, but that doesn't mean machine learning is not applicable to our problem. The approach \n",
    "above consisted in first flattening the timeseries, which removed the notion of time from the input data. Let us instead look at our data \n",
    "as what it is: a sequence, where causality and order matter. We will try a recurrent sequence processing model -- it should be the perfect \n",
    "fit for such sequence data, precisely because it does exploit the temporal ordering of data points, unlike our first approach.\n",
    "\n",
    "Instead of the `LSTM` layer introduced in the previous section, we will use the `GRU` layer, developed by Cho et al. in 2014. `GRU` layers \n",
    "(which stands for \"gated recurrent unit\") work by leveraging the same principle as LSTM, but they are somewhat streamlined and thus cheaper \n",
    "to run, albeit they may not have quite as much representational power as LSTM. This trade-off between computational expensiveness and \n",
    "representational power is seen everywhere in machine learning."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/20\n",
      "500/500 [==============================] - 169s - loss: 0.3216 - val_loss: 0.2738\n",
      "Epoch 2/20\n",
      "500/500 [==============================] - 168s - loss: 0.2846 - val_loss: 0.2654\n",
      "Epoch 3/20\n",
      "500/500 [==============================] - 168s - loss: 0.2772 - val_loss: 0.2653\n",
      "Epoch 4/20\n",
      "500/500 [==============================] - 168s - loss: 0.2707 - val_loss: 0.2663\n",
      "Epoch 5/20\n",
      "500/500 [==============================] - 168s - loss: 0.2643 - val_loss: 0.2680\n",
      "Epoch 6/20\n",
      "500/500 [==============================] - 169s - loss: 0.2584 - val_loss: 0.2644\n",
      "Epoch 7/20\n",
      "500/500 [==============================] - 168s - loss: 0.2553 - val_loss: 0.2658\n",
      "Epoch 8/20\n",
      "500/500 [==============================] - 168s - loss: 0.2508 - val_loss: 0.2672\n",
      "Epoch 9/20\n",
      "500/500 [==============================] - 165s - loss: 0.2455 - val_loss: 0.2728\n",
      "Epoch 10/20\n",
      "500/500 [==============================] - 164s - loss: 0.2423 - val_loss: 0.2801\n",
      "Epoch 11/20\n",
      "500/500 [==============================] - 164s - loss: 0.2386 - val_loss: 0.2750\n",
      "Epoch 12/20\n",
      "500/500 [==============================] - 164s - loss: 0.2364 - val_loss: 0.2774\n",
      "Epoch 13/20\n",
      "500/500 [==============================] - 165s - loss: 0.2313 - val_loss: 0.2810\n",
      "Epoch 14/20\n",
      "500/500 [==============================] - 165s - loss: 0.2283 - val_loss: 0.2855\n",
      "Epoch 15/20\n",
      "500/500 [==============================] - 165s - loss: 0.2246 - val_loss: 0.2879\n",
      "Epoch 16/20\n",
      "500/500 [==============================] - 165s - loss: 0.2194 - val_loss: 0.2894\n",
      "Epoch 17/20\n",
      "500/500 [==============================] - 164s - loss: 0.2181 - val_loss: 0.2941\n",
      "Epoch 18/20\n",
      "500/500 [==============================] - 164s - loss: 0.2139 - val_loss: 0.2982\n",
      "Epoch 19/20\n",
      "500/500 [==============================] - 164s - loss: 0.2100 - val_loss: 0.2973\n",
      "Epoch 20/20\n",
      "500/500 [==============================] - 165s - loss: 0.2074 - val_loss: 0.3034\n"
     ]
    }
   ],
   "source": [
    "from keras.models import Sequential\n",
    "from keras import layers\n",
    "from keras.optimizers import RMSprop\n",
    "\n",
    "model = Sequential()\n",
    "model.add(layers.GRU(32, input_shape=(None, float_data.shape[-1])))\n",
    "model.add(layers.Dense(1))\n",
    "\n",
    "model.compile(optimizer=RMSprop(), loss='mae')\n",
    "history = model.fit_generator(train_gen,\n",
    "                              steps_per_epoch=500,\n",
    "                              epochs=20,\n",
    "                              validation_data=val_gen,\n",
    "                              validation_steps=val_steps)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let look at our results:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3317e755f8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAEICAYAAACzliQjAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XmYVNW19/HvAhlkEBBwAqRRidAgMrSoQYIgMagRLoYY\nEFQcLmpCvNGYG64YY0i4ryJxDDHiFAeUGI2KUSSJkqjXqDSIIFNoEbCZIQIiTk2v9499uinaHqq7\nq2vo+n2ep56qc84+VatOda/atc8+e5u7IyIi2aFBqgMQEZHkUdIXEckiSvoiIllESV9EJIso6YuI\nZBElfRGRLKKkL9ViZg3NbI+ZHZ3IsqlkZseZWcL7LpvZUDNbG7O8yswGxlO2Bq91v5ldX9P9K3ne\nX5nZ7xP9vJI6B6U6AKlbZrYnZrEZ8DmwL1q+wt1nVef53H0f0CLRZbOBux+fiOcxs8uBce5+esxz\nX56I55b6T0m/nnP30qQb1SQvd/e/VVTezA5y96JkxCYiyafmnSwX/Xz/g5k9YWYfA+PM7FQze9PM\ndprZJjO7y8waReUPMjM3s5xo+bFo+1wz+9jM/mlmXapbNtp+lpn9y8x2mdndZvZ/Zja+grjjifEK\nMysws4/M7K6YfRua2e1mtsPM1gDDKjk+k81sdpl1M8zstujx5Wa2Ino/70e18Iqeq9DMTo8eNzOz\nR6PYlgH9ypS9wczWRM+7zMyGR+tPAH4DDIyazrbHHNubYva/MnrvO8zsWTM7Mp5jUxUzGxnFs9PM\nXjGz42O2XW9mG81st5mtjHmvp5jZomj9FjO7Nd7Xkzrg7rplyQ1YCwwts+5XwBfAuYRKwMHAScDJ\nhF+CxwD/AiZG5Q8CHMiJlh8DtgN5QCPgD8BjNSh7GPAxMCLadi3wJTC+gvcST4zPAa2AHODfJe8d\nmAgsAzoCbYFXw79Cua9zDLAHaB7z3FuBvGj53KiMAUOAT4Fe0bahwNqY5yoETo8eTwf+DrQBOgPL\ny5Q9Hzgy+kwuiGI4PNp2OfD3MnE+BtwUPT4zirE30BT4LfBKPMemnPf/K+D30ePuURxDos/oemBV\n9LgHsA44IirbBTgmerwAGBM9bgmcnOr/hWy+qaYvAK+7+/PuXuzun7r7And/y92L3H0NMBMYVMn+\nT7l7vrt/CcwiJJvqlv02sNjdn4u23U74gihXnDH+P3ff5e5rCQm25LXOB25390J33wHcXMnrrAHe\nI3wZAXwT+Mjd86Ptz7v7Gg9eAV4Gyj1ZW8b5wK/c/SN3X0eovce+7pPuvin6TB4nfGHnxfG8AGOB\n+919sbt/BkwCBplZx5gyFR2byowG5rj7K9FndDPhi+NkoIjwBdMjaiL8IDp2EL68u5pZW3f/2N3f\nivN9SB1Q0heAD2MXzKybmb1gZpvNbDcwBWhXyf6bYx7vpfKTtxWVPSo2Dnd3Qs24XHHGGNdrEWqo\nlXkcGBM9viBaLonj22b2lpn928x2EmrZlR2rEkdWFoOZjTezd6NmlJ1AtzifF8L7K30+d98NfAR0\niClTnc+souctJnxGHdx9FfBjwuewNWouPCIqegmQC6wys7fN7Ow434fUASV9gfBzP9a9hNrtce5+\nCHAjofmiLm0iNLcAYGbGgUmqrNrEuAnoFLNcVZfSJ4GhZtaBUON/PIrxYOAp4P8Rml5aA3+JM47N\nFcVgZscA9wBXAW2j510Z87xVdS/dSGgyKnm+loRmpA1xxFWd521A+Mw2ALj7Y+4+gNC005BwXHD3\nVe4+mtCE92vgaTNrWstYpIaU9KU8LYFdwCdm1h24Igmv+Wegr5mda2YHAf8FtK+jGJ8EfmRmHcys\nLfDTygq7+2bgdeD3wCp3Xx1tagI0BrYB+8zs28AZ1YjhejNrbeE6hokx21oQEvs2wvfffxJq+iW2\nAB1LTlyX4wngMjPrZWZNCMn3NXev8JdTNWIebmanR6/9E8J5mLfMrLuZDY5e79PoVkx4AxeaWbvo\nl8Gu6L0V1zIWqSElfSnPj4GLCf/Q9xJOuNYpd98CfA+4DdgBHAu8Q7iuINEx3kNoe19KOMn4VBz7\nPE44MVvatOPuO4FrgGcIJ0NHEb684vFzwi+OtcBc4JGY510C3A28HZU5HohtB/8rsBrYYmaxzTQl\n+79EaGZ5Jtr/aEI7f624+zLCMb+H8IU0DBgete83AaYRzsNsJvyymBztejawwkLvsOnA99z9i9rG\nIzVjoelUJL2YWUNCc8Iod38t1fGI1Beq6UvaMLNhUXNHE+BnhF4fb6c4LJF6RUlf0slpwBpC08G3\ngJHuXlHzjojUgJp3RESyiGr6IiJZJO0GXGvXrp3n5OSkOgwRkYyycOHC7e5eWTdnIA2Tfk5ODvn5\n+akOQ0Qko5hZVVeWA2reERHJKkr6IiJZRElfRCSLpF2bvogk15dffklhYSGfffZZqkORODRt2pSO\nHTvSqFFFQy9VTklfJMsVFhbSsmVLcnJyCIObSrpyd3bs2EFhYSFdunSpeody1JvmnVmzICcHGjQI\n97OqNd23SPb67LPPaNu2rRJ+BjAz2rZtW6tfZfWipj9rFkyYAHv3huV168IywNhajy0oUv8p4WeO\n2n5W9aKmP3ny/oRfYu/esF5ERPaLK+lHox+uMrMCM5tUzvYrzWypmS02s9fNLDda/00zWxhtW2hm\nQxL9BgDWr6/eehFJHzt27KB379707t2bI444gg4dOpQuf/FFfMPuX3LJJaxatarSMjNmzGBWgtp9\nTzvtNBYvXpyQ50q2Kpt3onHNZxAmhC4EFpjZHHdfHlPscXf/XVR+OGEijGGECRXOdfeNZtYTmEfl\nU+DVyNFHhyad8taLSGLNmhV+Ra9fH/7Hpk6tXTNq27ZtSxPoTTfdRIsWLbjuuusOKOPuuDsNGpRf\nT33ooYeqfJ0f/OAHNQ+yHomnpt8fKHD3NdFsN7MJ84SWiiZeLtGcaA5Pd3/H3TdG65cBB0djpSfU\n1KnQrNmB65o1C+tFJHFKzp+tWwfu+8+f1UXHiYKCAnJzcxk7diw9evRg06ZNTJgwgby8PHr06MGU\nKVNKy5bUvIuKimjdujWTJk3ixBNP5NRTT2Xr1q0A3HDDDdxxxx2l5SdNmkT//v05/vjjeeONNwD4\n5JNP+M53vkNubi6jRo0iLy+vyhr9Y489xgknnEDPnj25/vrrASgqKuLCCy8sXX/XXXcBcPvtt5Ob\nm0uvXr0YN25cwo9ZPOI5kdsB+DBmuRA4uWwhM/sBcC1hztDymnG+Aywqb3x0M5sATAA4ugbV85Ja\nRiJrHyLyVZWdP6uL/7eVK1fyyCOPkJeXB8DNN9/MoYceSlFREYMHD2bUqFHk5uYesM+uXbsYNGgQ\nN998M9deey0PPvggkyZ9pVUad+ftt99mzpw5TJkyhZdeeom7776bI444gqeffpp3332Xvn37Vhpf\nYWEhN9xwA/n5+bRq1YqhQ4fy5z//mfbt27N9+3aWLl0KwM6dOwGYNm0a69ato3HjxqXrki1hJ3Ld\nfYa7H0uYZPqG2G1m1gO4hQomr3b3me6e5+557dtXOUhcucaOhbVrobg43CvhiyRess+fHXvssaUJ\nH+CJJ56gb9++9O3blxUrVrB8+fKv7HPwwQdz1llnAdCvXz/Wrl1b7nOfd955Xynz+uuvM3r0aABO\nPPFEevToUWl8b731FkOGDKFdu3Y0atSICy64gFdffZXjjjuOVatWcfXVVzNv3jxatWoFQI8ePRg3\nbhyzZs2q8cVVtRVP0t8AdIpZ7hitq8hs4D9KFsysI2GC5ovc/f2aBCki6aGiH+J1df6sefPmpY9X\nr17NnXfeySuvvMKSJUsYNmxYuf3VGzduXPq4YcOGFBUVlfvcTZo0qbJMTbVt25YlS5YwcOBAZsyY\nwRVXhPruvHnzuPLKK1mwYAH9+/dn3759CX3deMST9BcAXc2si5k1BkYDc2ILmFnXmMVzgNXR+tbA\nC8Akd/+/xIQsIqmSyvNnu3fvpmXLlhxyyCFs2rSJefPmJfw1BgwYwJNPPgnA0qVLy/0lEevkk09m\n/vz57Nixg6KiImbPns2gQYPYtm0b7s53v/tdpkyZwqJFi9i3bx+FhYUMGTKEadOmsX37dvaWbStL\ngirb9N29yMwmEnreNAQedPdlZjYFyHf3OcBEMxtKmMj6I+DiaPeJwHHAjWZ2Y7TuTHffmug3IiJ1\nL5Xnz/r27Utubi7dunWjc+fODBgwIOGv8cMf/pCLLrqI3Nzc0ltJ00x5OnbsyC9/+UtOP/103J1z\nzz2Xc845h0WLFnHZZZfh7pgZt9xyC0VFRVxwwQV8/PHHFBcXc91119GyZcuEv4eqpN0cuXl5ea5J\nVESSZ8WKFXTv3j3VYaSFoqIiioqKaNq0KatXr+bMM89k9erVHHRQeg1eUN5nZmYL3T2vgl1Kpdc7\nERFJoT179nDGGWdQVFSEu3PvvfemXcKvrfr1bkREaqF169YsXLgw1WHUqXox9o6IiMRHSV9EJIso\n6YuIZBElfRGRLKKkLyIpNXjw4K9caHXHHXdw1VVXVbpfixYtANi4cSOjRo0qt8zpp59OVV3A77jj\njgMukjr77LMTMi7OTTfdxPTp02v9PImmpC8iKTVmzBhmz559wLrZs2czZsyYuPY/6qijeOqpp2r8\n+mWT/osvvkjr1q1r/HzpTklfRFJq1KhRvPDCC6UTpqxdu5aNGzcycODA0n7zffv25YQTTuC55577\nyv5r166lZ8+eAHz66aeMHj2a7t27M3LkSD799NPScldddVXpsMw///nPAbjrrrvYuHEjgwcPZvDg\nwQDk5OSwfft2AG677TZ69uxJz549S4dlXrt2Ld27d+c///M/6dGjB2eeeeYBr1OexYsXc8opp9Cr\nVy9GjhzJRx99VPr6JUMtlwz09o9//KN0Epk+ffrw8ccf1/jYlkf99EWk1I9+BImeEKp3b4jyZbkO\nPfRQ+vfvz9y5cxkxYgSzZ8/m/PPPx8xo2rQpzzzzDIcccgjbt2/nlFNOYfjw4RXOE3vPPffQrFkz\nVqxYwZIlSw4YGnnq1Kkceuih7Nu3jzPOOIMlS5Zw9dVXc9tttzF//nzatWt3wHMtXLiQhx56iLfe\negt35+STT2bQoEG0adOG1atX88QTT3Dfffdx/vnn8/TTT1c6Pv5FF13E3XffzaBBg7jxxhv5xS9+\nwR133MHNN9/MBx98QJMmTUqblKZPn86MGTMYMGAAe/bsoWnTptU42lVTTV9EUi62iSe2acfduf76\n6+nVqxdDhw5lw4YNbNmypcLnefXVV0uTb69evejVq1fptieffJK+ffvSp08fli1bVuVgaq+//joj\nR46kefPmtGjRgvPOO4/XXnsNgC5dutC7d2+g8uGbIYzvv3PnTgYNGgTAxRdfzKuvvloa49ixY3ns\nscdKr/wdMGAA1157LXfddRc7d+5M+BXBqumLSKnKauR1acSIEVxzzTUsWrSIvXv30q9fPwBmzZrF\ntm3bWLhwIY0aNSInJ6fc4ZSr8sEHHzB9+nQWLFhAmzZtGD9+fI2ep0TJsMwQhmauqnmnIi+88AKv\nvvoqzz//PFOnTmXp0qVMmjSJc845hxdffJEBAwYwb948unXrVuNYy1JNX0RSrkWLFgwePJhLL730\ngBO4u3bt4rDDDqNRo0bMnz+fdeVNhh3jG9/4Bo8//jgA7733HkuWLAHCsMzNmzenVatWbNmyhblz\n55bu07Jly3LbzQcOHMizzz7L3r17+eSTT3jmmWcYOHBgtd9bq1ataNOmTemvhEcffZRBgwZRXFzM\nhx9+yODBg7nlllvYtWsXe/bs4f333+eEE07gpz/9KSeddBIrV66s9mtWRjV9EUkLY8aMYeTIkQf0\n5Bk7diznnnsuJ5xwAnl5eVXWeK+66iouueQSunfvTvfu3Ut/MZx44on06dOHbt260alTpwOGZZ4w\nYQLDhg3jqKOOYv78+aXr+/bty/jx4+nfvz8Al19+OX369Km0KaciDz/8MFdeeSV79+7lmGOO4aGH\nHmLfvn2MGzeOXbt24e5cffXVtG7dmp/97GfMnz+fBg0a0KNHj9JZwBJFQyuLZDkNrZx5ajO0spp3\nRESyiJK+iEgWUdIXEdKtmVcqVtvPSklfJMs1bdqUHTt2KPFnAHdnx44dtbpgS713RLJcx44dKSws\nZNu2bakOReLQtGlTOnbsWOP9lfRFslyjRo3o0qVLqsOQJFHzjohIGnCHBI+tVi4lfRGRFFu3Dr71\nLTj//JD865KSvohIihQXw29/Cz17wj//CcOH1/1rqk1fRCQFCgrg8svhH/+Ab34T7rsPOneu+9dV\nTV9EJIn27YPbb4devcLcBQ88APPmJSfhQ5xJ38yGmdkqMysws0nlbL/SzJaa2WIze93McmO2/U+0\n3yoz+1YigxcRySQrV8LAgXDttTBkCCxbBpdeChXMCVMnqkz6ZtYQmAGcBeQCY2KTeuRxdz/B3XsD\n04Dbon1zgdFAD2AY8Nvo+UREskZREdx8c5hFbNUqeOwxeP556NAh+bHEU9PvDxS4+xp3/wKYDYyI\nLeDuu2MWmwMl559HALPd/XN3/wAoiJ5PRCQrLF0Kp5wC//M/cM45oXY/dmxya/ex4kn6HYAPY5YL\no3UHMLMfmNn7hJr+1dXcd4KZ5ZtZvq4KFJH64Isv4Be/gH79YP16ePJJePppOOKI1MaVsBO57j7D\n3Y8FfgrcUM19Z7p7nrvntW/fPlEhiYjEzT10oUyEhQvhpJPgppvgu9+F5cvDfTqIp8vmBqBTzHLH\naF1FZgP31HBfEZGk+vhjeOghuPNO+PBDOPJIOOqoim8dOkCrVuU3z3z2GUyZAtOmwWGHwXPPJafv\nfXXEk/QXAF3NrAshYY8GLogtYGZd3X11tHgOUPJ4DvC4md0GHAV0Bd5OROAiIrWxYQPcdRfcey/s\n2gUDBoTa+KZNsHFj6Gnzyiuwc+dX9z344K9+GRx+ODz8MKxYAZdcAr/+NbRpk/z3VZUqk767F5nZ\nRGAe0BB40N2XmdkUIN/d5wATzWwo8CXwEXBxtO8yM3sSWA4UAT9w93119F5ERKq0eHFIyLNnh+ac\n73wHfvxjOPnk8svv3bv/i2DjxvBlUfJ440ZYtCj0xNm7Fzp1grlzYdiw5L6n6tAcuSJS7xUXw0sv\nhWT/yivQvHm4Gva//gsSMcCoO+zeHZ73oBSNcxDvHLkahkFE6q3PPgt94m+7LTS7dOgAt9wCEyZA\n69aJex2z0M6fCZT0RaTe2b49DGQ2YwZs3Rouinr00TCKZePGqY4utZT0RaTeWLUqjGvz8MOhln/2\n2aG9fvDg1F0MlW6U9EUk4737brgQ6tlnQ03+wgvhmmsgt+yAMaKkLyKZa9mycAHUU0+FNvXJk2Hi\nxNB9UsqnpC8iGWflynAR1OzZ0KIF/OxnoWafjv3i042SvohkjIKCkOxnzQoXSP30p3DdddC2baoj\nyxxK+iKS9j74AH71q3CCtnHjMB79T34ShjqQ6lHSF5G0tX49TJ0KDz4IDRvCD38YavepHqkykynp\ni0ja2bAB/vd/w7yxZnDFFWE8+lRMOlLfKOmLSNrYvDnMMPW734W5ZC+7DK6/Ho4+OtWR1R9K+iKS\nEl9+CWvWhOERVq6E996DP/0pTD4yfnzofpmIcXHkQEr6IlKndu4MV8quXHngraAgzB1b4qijwjAJ\nN9wAxx2XunjrOyV9EUmIzZvDlbFlk/vmzfvLNGoEXbuGK2XPOw+6dQu344+HQw5JXezZRElfRGpk\nxw74xz/CUMWvvBKaaUq0aQPdu4exb0oSe7duobkmVUMPS6DDLyJx2b0bXnttf5J/990wjnzz5vCN\nb8Cll0L//iHZt2unAc7SlZK+iJTr00/hjTf2J/kFC0KPmiZN4OtfD1fGDhkSJgBv1CjV0Uq8lPQj\ns2aF3gLr14fuYVOnwtixqY5KJHm+/BLefnt/kn/jjdCTpmHDUIOfNCkk+VNPDUMgSGZS0ick/AkT\nwhyXAOvWhWVQ4pf675NPwuTgt94aTrqaQZ8+cPXVIcmfdhq0bJnqKCVRNEcukJMTEn1ZnTvD2rVJ\nDUUkafbsCbNLTZ8O27bBGWfAVVeFCUcOPTTV0Ul1aY7cali/vnrrRTLZ7t3wm9+EeWN37IBvfSsM\nTTxgQKojk2RokOoA0kFFl3jr0m+pT3buDLNLde4czl+deiq89Ra89JISfjZR0iectG3W7MB1zZqF\n9SKZbseOUJPv3DnMMnX66ZCfD88/H07QSnZR0iecrJ05M/xTmIX7mTN1Elcy27ZtYWTKnJwwFv2Z\nZ8LixfDMM9CvX6qjk1RRm35k7FgleakftmwJJ2d/+9vQ1/573wvNOT17pjoySQdx1fTNbJiZrTKz\nAjObVM72a81suZktMbOXzaxzzLZpZrbMzFaY2V1muk5PpC5s2BDmic3JCSdpzzsPli+HJ55Qwpf9\nqkz6ZtYQmAGcBeQCY8wst0yxd4A8d+8FPAVMi/b9OjAA6AX0BE4CBiUsepEsV1QU2uZHjAjNknff\nDaNHh4HOHn00jHcjEiue5p3+QIG7rwEws9nACGB5SQF3nx9T/k1gXMkmoCnQGDCgEbCl9mGLJNa+\nfeECpY4d4dxz03/cmIKCMIXg738PmzbB4YeHCcInTIBjjkl1dJLO4kn6HYAPY5YLgZMrKX8ZMBfA\n3f9pZvOBTYSk/xt3X1F2BzObAEwAOFr9JCXJduwI53PmzQvLp50Wrk495ZTUxlXWp5+GSUbuvx/+\n/ndo0CCMYnn55eFe499IPBLae8fMxgF5wK3R8nFAd6Aj4ctjiJkNLLufu8909zx3z2vfvn0iQxKp\nVH5+6Mkyfz7cc0+o7RcUhD7s3/0urF6d6gjhnXdg4sQwyci4cfsnC1+/fn/TjhK+xCuepL8B6BSz\n3DFadwAzGwpMBoa7++fR6pHAm+6+x933EH4BnFq7kNPTrFnhBFqDBuF+1qxURyRVuf/+cFFScTG8\n/jpceWVoHlm9OlzE9NJLYbKPiRNh69bkxrZzZ/gS6tcP+vYNsZ59dhgIbfXqMG+sJgmXGnH3Sm+E\nJqA1QBdC2/y7QI8yZfoA7wNdy6z/HvC36DkaAS8D51b2ev369fNM89hj7s2auYfRxcOtWbOwXtLP\n3r3ul14aPqdvftN927byy23e7P7977s3bOjeooX7L3/pvmdP3cVVXOz+97+7X3ihe9OmIb4TT3S/\n+273f/+77l5X6gcg36vI5x7+rOIoBGcD/4oS++Ro3RRCrZ4osW8BFke3OdH6hsC9wArCid/bqnqt\nTEz6nTsfmPBLbp07pzoyKWvNGve+fcPnc8MN7kVFVe+zcqX7eeeFfY480v2++9y//DIx8WzY4P7o\no+6XXOJ+9NHhNQ45xP3KK93z88MXgUg84k36GmUzARo0CGm+LLPQdCDpYe7ccMK2uDh0Zzz33Ort\n/3//B//932Gc+dxcuPlm+Pa3q9fTZ8eOcBK2ZMz6lSvD+jZtwuiWI0bAqFFfHRZEpCrxjrKpYRgS\nQAO2pbfi4jDmzDnnhM9k4cLqJ3wI7f+vvx560BQVwfDhIVG//XbF++zeDS+8AD/+cRijvn37kNQf\neSR0rZw+HRYtgu3b4emn4aKLlPCljsXzcyCZt0xs3lGbfvrascP9rLPCZ3LRRe6ffJKY5/3iC/ff\n/tb9sMPCc59/vntBQThf8PLL7tdf737KKeF8ALg3aeI+ZIj7r37l/sYbYX+RRELNO8ml6RbTz6JF\n8J3vhOEJ7roLrrgi8RddffxxqK1Pn75/asHPPw/3J58cZp4qmWKwadPEvrZIrHibd+pV0i8qgoM0\nhJwQrlb9/vdDc8pTT4UEXJc2bYJf/zo8PuMMTTEoyZd1M2dt2RJqVL/4RWgzlez02Wfwwx+Gfu1D\nh8Ljj4fEX9eOPDLU9kXSXb05kdu4cegBcf754aIWyT5r14Ya9v33h4uXXnopOQlfJJPUm6Tfpg38\n5S+hh8b3vx9q/GnWciV1ZN8+mDEDevcOV6s+91w4p9KwYaojE0k/9SbpQ+jq9qc/wcUXhy56EyeG\nhJAJNIxDzeTnh/b6iRPhpJPCydvhw1MdlUj6qjdt+iUaNYKHHoLDDgsjJW7fHvpEN2mS6sgqNmtW\nGPNl796wvG5dWAb1AKrIzp2ht9Q998ARR8Ds2aFpL92HRBZJtXpV0y9hBtOmhduTT4arJj/+ONVR\nVWzy5P0Jv8TevWG9HMgdHnsMjj8efve7cNJ2xYowJaASvkjV6mXSL/GTn4RJJubPDz17tm1LdUTl\nW7++euuz1cqVoTvkhReGJrAFC+DOO6FVq1RHJpI56nXSh9C+/+yz8N57oWfH2rWpjuirNIxD5Up+\n9fTqFcaW/93vwvg3ffumOjKRzFPvkz6E5p2//S2MiT5gQPgCSCdTp351vJVmzcL6bPfnP0OPHvC/\n/wtjxsCqVeHKWvXMEamZrEj6EJL9a6+FxwMHhhET08XYsTBzZpjY2izcz5yZ3Sdx16+HkSPDwGjN\nmoWRKR9+OJygF5Gaq1fDMMRj3To488yQVP74x/ArIJP9+9+wdGm4rVgBJ54Io0fDIYekOrKa+fJL\nuP32cJ0FwI03wjXXhIvvRKRiWTcMQ7w6dw7D4559NvzHf8ADD4R2/3T3xRfhRObSpbBkyf77DTET\nVzZrFtq/r7kmzO966aXhV02692opLg7v4513wpW0y5aFceXvvDN8XiKSOFmX9CFcmv/KK3DeeTB+\nfOjVc911qY4qcIfCwgMT+9KlIeEXFYUyjRqFSTwGDw4nN084IdwfeWQY2/2BB0K/9Ycfhq5dQ/K/\n+OKwPVWKi2HjxnDFbEFBuC95/P778OmnoVznzjBnTs3GuxeRqmVd806szz8PyfAPfwjdO2+5pe5r\nxfv2hcHhCgvhww8PvF+/HpYvh1279pc/+uj9Sb3k/mtfC4m/Mp98EkaXfOCBcC6jYcPw6+ayy8J9\nVfvXRHFxGG0yNqGXPI5N7BCaa449Nnwpde0Kxx0X7r/+dTj44MTHJlLfqXknDk2ahKth27ULV+9u\n3RqaRhowsY4pAAAO60lEQVQ0CEmyujez8KuhbDKPfbxx4/4ae2wcnTpBx46hh0pJcu/ZE1q3ju+9\nlDee/8UXh9u//hWGGn74YXj+eTj88DBD06WXQrdu1T9uX3wREvnKleE8wooV4fHKlQdeZNa4cZgd\nqmvXcB6lJLF37Rreq3rgiCRfVtf0S7jDL38JP/954p+7adOQ4EqSenmP27at3S+MssM4QGjfL9sD\nqKgozBP7wAOhK+S+faFX02WXhXMALVoc+Ly7du1P7LEJfs2aA8c0Ovpo6N49fIF87Wv7E3unTkrs\nIsmSlZOo1Nbbb4cTivv2Vf9WXBzu27Xbn9Q7dYJDD637JqOcnNArqazOnSu+GG3z5jAm0QMPhF8C\nLVqEsWuaNt2f4Ddt2l++UaOQyLt335/gu3cPwyE0b14X70pEqkNJP4s0aFD+MNJm4cuoMu7h6tYH\nHgjjFDVseGBSL3l8zDGalUwknalNP4scfXT5Nf14hnEwC008AwbAffeFL5B07+IpIjWXNVfk1meJ\nGsah5GS0iNRfSvr1gIZxEJF4qXmnnhg7VkleRKoWV03fzIaZ2SozKzCzSeVsv9bMlpvZEjN72cw6\nx2w72sz+YmYrojI5iQtfRESqo8qkb2YNgRnAWUAuMMbMcssUewfIc/dewFPAtJhtjwC3unt3oD+w\nNRGBi4hI9cVT0+8PFLj7Gnf/ApgNjIgt4O7z3b3k0qA3gY4A0ZfDQe7+16jcnphyIiKSZPEk/Q7A\nhzHLhdG6ilwGzI0efw3YaWZ/MrN3zOzW6JfDAcxsgpnlm1n+tnSd07CemzUrXOTVoEG4nzUr1RGJ\nSF1IaO8dMxsH5AG3RqsOAgYC1wEnAccA48vu5+4z3T3P3fPat2+fyJAkDiXDOKxbFy7WWrcuLCvx\ni9Q/8ST9DUCnmOWO0boDmNlQYDIw3N0/j1YXAoujpqEi4FlAM5ummcmTDxy3B/bPSysi9Us8SX8B\n0NXMuphZY2A0MCe2gJn1Ae4lJPytZfZtbWYl1fchwPLahy2JtH599daLSOaqMulHNfSJwDxgBfCk\nuy8zsylmNjwqdivQAvijmS02sznRvvsITTsvm9lSwID76uB9SC1UNFxDPMM4iEhmiatN391fdPev\nufux7j41Wneju5ck96Hufri7945uw2P2/au793L3E9x9fNQDSNJIIoZx0IlgkcygYRik1sM46ESw\nSObQ0MpSazUZz19EEiveoZVV05da04lgkcyhpC+1phPBIplDSV9qLVHj+YtI3VPSl1rTeP4imUPj\n6UtCaDx/kcygmr6kBfXzF0kO1fQl5Ur6+ZeM/1PSzx/060Ek0VTTl5TTgG8iyaOkLymnfv4iyaOk\nLymnfv4iyaOkLymnfv4iyaOkLymnfv4iyaPeO5IW1M9fJDlU0xcRySJK+lIv6OIukfioeUcyni7u\nEomfavqS8XRxl0j8lPQl4+niLpH4KelLxtPFXSLxU9KXjJeIi7t0IliyhZK+ZLzaXtxVciJ43Tpw\n338iWIlf6iNz91THcIC8vDzPz89PdRiSRXJyQqIvq3NnWLs22dGI1IyZLXT3vKrKqaYvWU8ngiWb\nxJX0zWyYma0yswIzm1TO9mvNbLmZLTGzl82sc5nth5hZoZn9JlGBiySKTgRLNqky6ZtZQ2AGcBaQ\nC4wxs9wyxd4B8ty9F/AUMK3M9l8Cr9Y+XJHE0yifkk3iqen3BwrcfY27fwHMBkbEFnD3+e5ecnnM\nm0DHkm1m1g84HPhLYkIWSSyN8inZJJ6k3wH4MGa5MFpXkcuAuQBm1gD4NXBdZS9gZhPMLN/M8rdt\n2xZHSCKJNXZsOGlbXBzuq5vw1eVTMkVCx94xs3FAHjAoWvV94EV3LzSzCvdz95nATAi9dxIZk0hd\n09g/kkniqelvADrFLHeM1h3AzIYCk4Hh7v55tPpUYKKZrQWmAxeZ2c21ilgkzWjsH8kk8dT0FwBd\nzawLIdmPBi6ILWBmfYB7gWHuvrVkvbuPjSkznnCy9yu9f0Qymbp8Siapsqbv7kXARGAesAJ40t2X\nmdkUMxseFbsVaAH80cwWm9mcOotYJM0kosunzglIsuiKXJFaKtumD6HLZ7w9gGq7vwjoilyRpKlt\nl0+dE5BkUk1fJMUaNAgDvZVlFrqQisRDNX2RDKFhICSZlPRFUkzDQEgyKemLpJiGgZBkSugVuSJS\nM2PHKslLcqimL1IPqJ+/xEs1fZEMp7F/pDpU0xfJcOrnL9WhpC+S4TT2j1SHkr5IhlM/f6kOJX2R\nDKd+/lIdSvoiGS4R/fzV+yd7qPeOSD1Qm37+6v2TXVTTF8ly6v2TXZT0RbKcev9kFyV9kSyn3j/Z\nRUlfJMup9092UdIXyXLq/ZNd1HtHRNT7J4uopi8itaLeP5lFSV9EakW9fzKLkr6I1Ip6/2QWJX0R\nqRX1/sksSvoiUiua4zezqPeOiNSa5vjNHHHV9M1smJmtMrMCM5tUzvZrzWy5mS0xs5fNrHO0vreZ\n/dPMlkXbvpfoNyAiIvGrMumbWUNgBnAWkAuMMbPcMsXeAfLcvRfwFDAtWr8XuMjdewDDgDvMrHWi\ngheR+kEXdyVPPDX9/kCBu69x9y+A2cCI2ALuPt/dS3rqvgl0jNb/y91XR483AluB9okKXkQyX8nF\nXevWgfv+i7uU+OtGPEm/A/BhzHJhtK4ilwFzy640s/5AY+D9crZNMLN8M8vftm1bHCGJSH2RiIu7\n9Eshfgk9kWtm44A8YFCZ9UcCjwIXu3tx2f3cfSYwEyAvL88TGZOIpLfaXtylYSCqJ56a/gagU8xy\nx2jdAcxsKDAZGO7un8esPwR4AZjs7m/WLlwRqW9qe3GXhoGonniS/gKgq5l1MbPGwGhgTmwBM+sD\n3EtI+Ftj1jcGngEecfenEhe2iNQXtb24S8NAVE+VSd/di4CJwDxgBfCkuy8zsylmNjwqdivQAvij\nmS02s5IvhfOBbwDjo/WLzax34t+GiGSq2l7cpWEgqsfc06sJPS8vz/Pz81MdhohkiLJt+hB+KWTb\nVcFmttDd86oqp2EYRCSjaRiI6tEwDCKS8TQMRPxU0xeRrJdN/fxV0xeRrJZt/fxV0xeRrJZt/fyV\n9EUkq2VbP38lfRHJatnWz19JX0SyWrZN96ikLyJZLRH9/DOp949674hI1qtNP/9M6/2jmr6ISC1k\nWu8fJX0RkVrItN4/SvoiIrWQab1/lPRFRGohEb1/knkiWElfRKQWatv7J9kTw2s8fRGRFMrJCYm+\nrM6dYe3a+J9H4+mLiGSAZJ8IVtIXEUmhZJ8IVtIXEUmhZA8DoaQvIpJCyZ7uUcMwiIikWDKne1RN\nX0Qkiyjpi4hkESV9EZEsoqQvIpJFlPRFRLJI2g3DYGbbgHIuSo5bO2B7gsKpC4qvdhRf7Si+2knn\n+Dq7e/uqCqVd0q8tM8uPZ/yJVFF8taP4akfx1U66xxcPNe+IiGQRJX0RkSxSH5P+zFQHUAXFVzuK\nr3YUX+2ke3xVqndt+iIiUrH6WNMXEZEKKOmLiGSRjEz6ZjbMzFaZWYGZTSpnexMz+0O0/S0zy0li\nbJ3MbL6ZLTezZWb2X+WUOd3MdpnZ4uh2Y7Lii4lhrZktjV7/K/NTWnBXdAyXmFnfJMZ2fMyxWWxm\nu83sR2XKJPUYmtmDZrbVzN6LWXeomf3VzFZH920q2PfiqMxqM7s4ifHdamYro8/vGTNrXcG+lf4t\n1GF8N5nZhpjP8OwK9q30/70O4/tDTGxrzWxxBfvW+fFLKHfPqBvQEHgfOAZoDLwL5JYp833gd9Hj\n0cAfkhjfkUDf6HFL4F/lxHc68OcUH8e1QLtKtp8NzAUMOAV4K4Wf92bChScpO4bAN4C+wHsx66YB\nk6LHk4BbytnvUGBNdN8metwmSfGdCRwUPb6lvPji+Vuow/huAq6L4/Ov9P+9ruIrs/3XwI2pOn6J\nvGViTb8/UODua9z9C2A2MKJMmRHAw9Hjp4AzzMySEZy7b3L3RdHjj4EVQIdkvHaCjQAe8eBNoLWZ\nHZmCOM4A3nf32lylXWvu/irw7zKrY//OHgb+o5xdvwX81d3/7e4fAX8FhiUjPnf/i7sXRYtvAh0T\n/brxquD4xSOe//daqyy+KHecDzyR6NdNhUxM+h2AD2OWC/lqUi0tE/3R7wLaJiW6GFGzUh/grXI2\nn2pm75rZXDPrkdTAAgf+YmYLzWxCOdvjOc7JMJqK/9lSfQwPd/dN0ePNwOHllEmX43gp4Zdbear6\nW6hLE6PmpwcraB5Lh+M3ENji7qsr2J7K41dtmZj0M4KZtQCeBn7k7rvLbF5EaK44EbgbeDbZ8QGn\nuXtf4CzgB2b2jRTEUCkzawwMB/5YzuZ0OIalPPzOT8v+z2Y2GSgCZlVQJFV/C/cAxwK9gU2EJpR0\nNIbKa/lp/78UKxOT/gagU8xyx2hduWXM7CCgFbAjKdGF12xESPiz3P1PZbe7+2533xM9fhFoZGbt\nkhVf9LobovutwDOEn9Gx4jnOde0sYJG7bym7IR2OIbClpMkrut9aTpmUHkczGw98GxgbfTF9RRx/\nC3XC3be4+z53Lwbuq+B1U338DgLOA/5QUZlUHb+aysSkvwDoamZdoprgaGBOmTJzgJJeEqOAVyr6\ng0+0qP3vAWCFu99WQZkjSs4xmFl/wueQzC+l5mbWsuQx4YTfe2WKzQEuinrxnALsimnKSJYKa1ip\nPoaR2L+zi4HnyikzDzjTzNpEzRdnRuvqnJkNA/4bGO7ueysoE8/fQl3FF3uOaGQFrxvP/3tdGgqs\ndPfC8jam8vjVWKrPJNfkRuhZ8i/CWf3J0bophD9ugKaEJoEC4G3gmCTGdhrhZ/4SYHF0Oxu4Ergy\nKjMRWEboifAm8PUkH79jotd+N4qj5BjGxmjAjOgYLwXykhxjc0ISbxWzLmXHkPDlswn4ktCufBnh\nPNHLwGrgb8ChUdk84P6YfS+N/hYLgEuSGF8BoT285O+wpEfbUcCLlf0tJCm+R6O/rSWERH5k2fii\n5a/8vycjvmj970v+5mLKJv34JfKmYRhERLJIJjbviIhIDSnpi4hkESV9EZEsoqQvIpJFlPRFRLKI\nkr6ISBZR0hcRySL/H5V5hnuyqMOlAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3316a8b358>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "loss = history.history['loss']\n",
    "val_loss = history.history['val_loss']\n",
    "\n",
    "epochs = range(len(loss))\n",
    "\n",
    "plt.figure()\n",
    "\n",
    "plt.plot(epochs, loss, 'bo', label='Training loss')\n",
    "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
    "plt.title('Training and validation loss')\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Much better! We are able to significantly beat the common sense baseline, such demonstrating the value of machine learning here, as well as \n",
    "the superiority of recurrent networks compared to sequence-flattening dense networks on this type of task.\n",
    "\n",
    "Our new validation MAE of ~0.265 (before we start significantly overfitting) translates to a mean absolute error of 2.35˚C after \n",
    "de-normalization. That's a solid gain on our initial error of 2.57˚C, but we probably still have a bit of margin for improvement."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using recurrent dropout to fight overfitting\n",
    "\n",
    "\n",
    "It is evident from our training and validation curves that our model is overfitting: the training and validation losses start diverging \n",
    "considerably after a few epochs. You are already familiar with a classic technique for fighting this phenomenon: dropout, consisting in \n",
    "randomly zeroing-out input units of a layer in order to break happenstance correlations in the training data that the layer is exposed to. \n",
    "How to correctly apply dropout in recurrent networks, however, is not a trivial question. It has long been known that applying dropout \n",
    "before a recurrent layer hinders learning rather than helping with regularization. In 2015, Yarin Gal, as part of his Ph.D. thesis on \n",
    "Bayesian deep learning, determined the proper way to use dropout with a recurrent network: the same dropout mask (the same pattern of \n",
    "dropped units) should be applied at every timestep, instead of a dropout mask that would vary randomly from timestep to timestep. What's \n",
    "more: in order to regularize the representations formed by the recurrent gates of layers such as GRU and LSTM, a temporally constant \n",
    "dropout mask should be applied to the inner recurrent activations of the layer (a \"recurrent\" dropout mask). Using the same dropout mask at \n",
    "every timestep allows the network to properly propagate its learning error through time; a temporally random dropout mask would instead \n",
    "disrupt this error signal and be harmful to the learning process.\n",
    "\n",
    "Yarin Gal did his research using Keras and helped build this mechanism directly into Keras recurrent layers. Every recurrent layer in Keras \n",
    "has two dropout-related arguments: `dropout`, a float specifying the dropout rate for input units of the layer, and `recurrent_dropout`, \n",
    "specifying the dropout rate of the recurrent units. Let's add dropout and recurrent dropout to our GRU layer and see how it impacts \n",
    "overfitting. Because networks being regularized with dropout always take longer to fully converge, we train our network for twice as many \n",
    "epochs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/40\n",
      "500/500 [==============================] - 171s - loss: 0.3526 - val_loss: 0.2740\n",
      "Epoch 2/40\n",
      "500/500 [==============================] - 170s - loss: 0.3138 - val_loss: 0.2742\n",
      "Epoch 3/40\n",
      "500/500 [==============================] - 170s - loss: 0.3065 - val_loss: 0.2692\n",
      "Epoch 4/40\n",
      "500/500 [==============================] - 170s - loss: 0.3033 - val_loss: 0.2694\n",
      "Epoch 5/40\n",
      "500/500 [==============================] - 170s - loss: 0.3006 - val_loss: 0.2695\n",
      "Epoch 6/40\n",
      "500/500 [==============================] - 170s - loss: 0.2990 - val_loss: 0.2709\n",
      "Epoch 7/40\n",
      "500/500 [==============================] - 170s - loss: 0.2955 - val_loss: 0.2667\n",
      "Epoch 8/40\n",
      "500/500 [==============================] - 170s - loss: 0.2942 - val_loss: 0.2671\n",
      "Epoch 9/40\n",
      "500/500 [==============================] - 171s - loss: 0.2940 - val_loss: 0.2649\n",
      "Epoch 10/40\n",
      "500/500 [==============================] - 170s - loss: 0.2923 - val_loss: 0.2673\n",
      "Epoch 11/40\n",
      "500/500 [==============================] - 170s - loss: 0.2894 - val_loss: 0.2695\n",
      "Epoch 12/40\n",
      "500/500 [==============================] - 170s - loss: 0.2899 - val_loss: 0.2648\n",
      "Epoch 13/40\n",
      "500/500 [==============================] - 170s - loss: 0.2879 - val_loss: 0.2634\n",
      "Epoch 14/40\n",
      "500/500 [==============================] - 170s - loss: 0.2884 - val_loss: 0.2666\n",
      "Epoch 15/40\n",
      "500/500 [==============================] - 170s - loss: 0.2863 - val_loss: 0.2695\n",
      "Epoch 16/40\n",
      "500/500 [==============================] - 170s - loss: 0.2852 - val_loss: 0.2705\n",
      "Epoch 17/40\n",
      "500/500 [==============================] - 170s - loss: 0.2843 - val_loss: 0.2739\n",
      "Epoch 18/40\n",
      "500/500 [==============================] - 170s - loss: 0.2844 - val_loss: 0.2646\n",
      "Epoch 19/40\n",
      "500/500 [==============================] - 170s - loss: 0.2827 - val_loss: 0.2661\n",
      "Epoch 20/40\n",
      "500/500 [==============================] - 170s - loss: 0.2813 - val_loss: 0.2637\n",
      "Epoch 21/40\n",
      "500/500 [==============================] - 170s - loss: 0.2805 - val_loss: 0.2663\n",
      "Epoch 22/40\n",
      "500/500 [==============================] - 170s - loss: 0.2786 - val_loss: 0.2662\n",
      "Epoch 23/40\n",
      "500/500 [==============================] - 170s - loss: 0.2795 - val_loss: 0.2637\n",
      "Epoch 24/40\n",
      "500/500 [==============================] - 170s - loss: 0.2801 - val_loss: 0.2649\n",
      "Epoch 25/40\n",
      "500/500 [==============================] - 170s - loss: 0.2774 - val_loss: 0.2723\n",
      "Epoch 26/40\n",
      "500/500 [==============================] - 170s - loss: 0.2788 - val_loss: 0.2682\n",
      "Epoch 27/40\n",
      "500/500 [==============================] - 171s - loss: 0.2780 - val_loss: 0.2655\n",
      "Epoch 28/40\n",
      "500/500 [==============================] - 170s - loss: 0.2782 - val_loss: 0.2645\n",
      "Epoch 29/40\n",
      "500/500 [==============================] - 170s - loss: 0.2770 - val_loss: 0.2647\n",
      "Epoch 30/40\n",
      "500/500 [==============================] - 170s - loss: 0.2756 - val_loss: 0.2746\n",
      "Epoch 31/40\n",
      "500/500 [==============================] - 171s - loss: 0.2763 - val_loss: 0.2641\n",
      "Epoch 32/40\n",
      "500/500 [==============================] - 170s - loss: 0.2752 - val_loss: 0.2733\n",
      "Epoch 33/40\n",
      "500/500 [==============================] - 170s - loss: 0.2742 - val_loss: 0.2619\n",
      "Epoch 34/40\n",
      "500/500 [==============================] - 170s - loss: 0.2753 - val_loss: 0.2711\n",
      "Epoch 35/40\n",
      "500/500 [==============================] - 170s - loss: 0.2727 - val_loss: 0.2658\n",
      "Epoch 36/40\n",
      "500/500 [==============================] - 170s - loss: 0.2724 - val_loss: 0.2664\n",
      "Epoch 37/40\n",
      "500/500 [==============================] - 170s - loss: 0.2725 - val_loss: 0.2661\n",
      "Epoch 38/40\n",
      "500/500 [==============================] - 171s - loss: 0.2725 - val_loss: 0.2633\n",
      "Epoch 39/40\n",
      "500/500 [==============================] - 170s - loss: 0.2726 - val_loss: 0.2695\n",
      "Epoch 40/40\n",
      "500/500 [==============================] - 170s - loss: 0.2727 - val_loss: 0.2719\n"
     ]
    }
   ],
   "source": [
    "from keras.models import Sequential\n",
    "from keras import layers\n",
    "from keras.optimizers import RMSprop\n",
    "\n",
    "model = Sequential()\n",
    "model.add(layers.GRU(32,\n",
    "                     dropout=0.2,\n",
    "                     recurrent_dropout=0.2,\n",
    "                     input_shape=(None, float_data.shape[-1])))\n",
    "model.add(layers.Dense(1))\n",
    "\n",
    "model.compile(optimizer=RMSprop(), loss='mae')\n",
    "history = model.fit_generator(train_gen,\n",
    "                              steps_per_epoch=500,\n",
    "                              epochs=40,\n",
    "                              validation_data=val_gen,\n",
    "                              validation_steps=val_steps)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3317e879e8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n6RuT5nJzc2nQoAGZmZm4wU1NslJVdu3aRW5uLm3bto28QRlSpnpn1izIzISMDPd7Vrke921M+jp4\n8CDNmjWzhF8FiAjNmjWL6qosJUr6s2bBqFGwf7+b3rTJTQMMj3psQWNSnyX8qiPav1VKlPTvuqs4\n4Qfs3+/mG2OMKZYSSf/bb8s33xiTPHbt2kWXLl3o0qULxx57LC1btiyaPnzY37D7v/zlL1m7dm3Y\ndaZNm8asGNX7nnPOOaxYsSIm+6psKVG907q1q9Ipa74xJrZmzXJX0d9+675jEydGV43arFmzogR6\n3333Ub9+fW677bYS66gqqkpGRtnl1Keeeiri+9x0000VDzKFpERJf+JEqFu35Ly6dd18Y0zsBNrP\nNm0C1eL2s3h0nFi/fj1ZWVkMHz6cjh07snXrVkaNGkV2djYdO3ZkwoQJResGSt75+fk0btyYcePG\ncfrpp3P22Wfz/fffAzB+/HimTJlStP64cePo3r07p556Kh999BEAP/74I5dffjlZWVkMHjyY7Ozs\niCX6mTNn0qlTJ0477TTuvPNOAPLz87nqqquK5k+dOhWARx55hKysLDp37syIESNifsz8SImSfqCU\nEcvShzHmaOHaz+Lxffvqq6949tlnyc7OBuCBBx6gadOm5Ofn06dPHwYPHkxWVlaJbfbs2UOvXr14\n4IEHGDt2LE8++STjxo07at+qyieffMLcuXOZMGECb731Fo899hjHHnssL730Ep9//jndunULG19u\nbi7jx49n6dKlNGrUiH79+vHGG2/QokULdu7cyapVqwDYvXs3AJMmTWLTpk3UrFmzaF5lS4mSPrh/\nuJwcKCx0vy3hGxN7ld1+dtJJJxUlfIAXXniBbt260a1bN9asWcOXX3551DZ16tThwgsvBOCMM84g\nJyenzH1fdtllR63zwQcfMGTIEABOP/10OnbsGDa+JUuW0LdvX5o3b06NGjUYNmwYixcv5uSTT2bt\n2rXccsstLFiwgEaNGgHQsWNHRowYwaxZsyp8c1W0UibpG2PiL1Q7Wbzaz+rVq1f0et26dTz66KMs\nXLiQlStX0r9//zL7q9esWbPodbVq1cjPzy9z37Vq1Yq4TkU1a9aMlStX0rNnT6ZNm8aNN94IwIIF\nCxg9ejSffvop3bt3p6CgIKbv64clfWOMb4lsP9u7dy8NGjSgYcOGbN26lQULFsT8PXr06MGcOXMA\n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\n8xuoXz/R0RqTeiZOhBtucN+3gOCkHvzksrIeTtO6tUvmpbVuHX74iuHDw29rSvFzOVCZPxWt3vn+\n+7Iv7wI/NWq43yNHVmj3Jgm99ZZqp06qK1cmOhITMH588XfuuOPK3xAbz+ErkrmhNxaxkW51+keO\nqL77ruonn6h+8YXqhg2q27ap7t3rlqmq3nOP+8TPP1+htzBJ5KWXik/kN9yQ6GhMwA03uGRbrZrq\nuHHl3/6pp1QbNSquj49Vz59YnBQi7T+abWPRCJ12Sd+PI0dUe/RQbdhQ9Ztv4vY2Js6efdYllbPP\nVr38ctUGDVTz8hIdlTlwwCXsq65SveAC1bZtVQsLy7ePmTNdVrr33qPnx3MgOj/3L4RaHs22fmLz\ny5J+CDk57h/zzDNVDx+O61uZOJg2zf3X9u2rum+f6vvvu+mnn050ZJXrgw9UlyxJdBQlvfii+1ss\nWOBK7FD+GHv3dtt17nz0smiqQOLZsyjaXkl+bnrzw5J+GHPmuE9+551xfysTQw8+6P5uAwa4UqWq\nK0m2a6d67rmJja0y7d6t2rixau3aqh9/nOhoig0c6Orx8/NVf/hBtWZN1Vtv9b/911+7v2/btu53\nLK/Go0284ZZHs62f2Pzym/TTssvmFVfAddfBn/8MCxcmOhoTiSqMHw933AFDhsBLL0Ht2m6ZCFx7\nLSxeDOvWJTbOyvJ//we7d0OTJjBgAGzYkOiIYNcumDcPhg2DatWgcWPo3x/mzHHdO/148kn38Jbn\nnnPTr74au/iifRpauOXRbAtw++3umIWKLeb8nBkq86eybs7Ky1M99VTV449X3bEjvu+1davqX/+q\n+t138X2fVFRQoHrLLa7kc/31rhRZ2nffqWZkpMeVW16eavPmqv37q371lWqTJu7/eNeuxMYVqHZb\nsaJ43vPPu3mLF0fe/sgR1WOPdVdxqqqnn67as2f543jzTdVRo8r+P4mmMTUedfrPPefap5o2dZ0S\nGjcuLuFb7504+ewzdwk6YED5G5wiOXJEde5cd8lbrZo70p06qe7ZE9v3SVWHD6u+957qL37hjt3Y\nseH/Rpdc4k7gZX3ZU8kjj7jj8cEHbvq999z/cK9eqgcPJi6us89WPe20kn+jfftU69RRvemmyNu/\n9pr7XK+95qbvvdcl5+3byxdH165uPw8+WL7tVCu3986jj6peeKGL9X/+R3XNmvLHW5olfZ+mTHFH\n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\n+f9aLqARS41G2QAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3315076e48>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "loss = history.history['loss']\n",
    "val_loss = history.history['val_loss']\n",
    "\n",
    "epochs = range(len(loss))\n",
    "\n",
    "plt.figure()\n",
    "\n",
    "plt.plot(epochs, loss, 'bo', label='Training loss')\n",
    "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
    "plt.title('Training and validation loss')\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great success; we are no longer overfitting during the first 30 epochs. However, while we have more stable evaluation scores, our best \n",
    "scores are not much lower than they were previously."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Stacking recurrent layers\n",
    "\n",
    "Since we are no longer overfitting yet we seem to have hit a performance bottleneck, we should start considering increasing the capacity of \n",
    "our network. If you remember our description of the \"universal machine learning workflow\": it is a generally a good idea to increase the \n",
    "capacity of your network until overfitting becomes your primary obstacle (assuming that you are already taking basic steps to mitigate \n",
    "overfitting, such as using dropout). As long as you are not overfitting too badly, then you are likely under-capacity.\n",
    "\n",
    "Increasing network capacity is typically done by increasing the number of units in the layers, or adding more layers. Recurrent layer \n",
    "stacking is a classic way to build more powerful recurrent networks: for instance, what currently powers the Google translate algorithm is \n",
    "a stack of seven large LSTM layers -- that's huge.\n",
    "\n",
    "To stack recurrent layers on top of each other in Keras, all intermediate layers should return their full sequence of outputs (a 3D tensor) \n",
    "rather than their output at the last timestep. This is done by specifying `return_sequences=True`: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/40\n",
      "500/500 [==============================] - 346s - loss: 0.3341 - val_loss: 0.2780\n",
      "Epoch 2/40\n",
      "500/500 [==============================] - 344s - loss: 0.3125 - val_loss: 0.2754\n",
      "Epoch 3/40\n",
      "500/500 [==============================] - 344s - loss: 0.3045 - val_loss: 0.2696\n",
      "Epoch 4/40\n",
      "500/500 [==============================] - 344s - loss: 0.3018 - val_loss: 0.2747\n",
      "Epoch 5/40\n",
      "500/500 [==============================] - 344s - loss: 0.2957 - val_loss: 0.2690\n",
      "Epoch 6/40\n",
      "500/500 [==============================] - 344s - loss: 0.2923 - val_loss: 0.2692\n",
      "Epoch 7/40\n",
      "500/500 [==============================] - 344s - loss: 0.2907 - val_loss: 0.2673\n",
      "Epoch 8/40\n",
      "500/500 [==============================] - 343s - loss: 0.2879 - val_loss: 0.2690\n",
      "Epoch 9/40\n",
      "500/500 [==============================] - 343s - loss: 0.2866 - val_loss: 0.2743\n",
      "Epoch 10/40\n",
      "500/500 [==============================] - 344s - loss: 0.2833 - val_loss: 0.2669\n",
      "Epoch 11/40\n",
      "500/500 [==============================] - 344s - loss: 0.2825 - val_loss: 0.2669\n",
      "Epoch 12/40\n",
      "500/500 [==============================] - 344s - loss: 0.2822 - val_loss: 0.2700\n",
      "Epoch 13/40\n",
      "500/500 [==============================] - 345s - loss: 0.2785 - val_loss: 0.2698\n",
      "Epoch 14/40\n",
      "500/500 [==============================] - 345s - loss: 0.2775 - val_loss: 0.2634\n",
      "Epoch 15/40\n",
      "500/500 [==============================] - 344s - loss: 0.2778 - val_loss: 0.2653\n",
      "Epoch 16/40\n",
      "500/500 [==============================] - 344s - loss: 0.2740 - val_loss: 0.2633\n",
      "Epoch 17/40\n",
      "500/500 [==============================] - 344s - loss: 0.2746 - val_loss: 0.2680\n",
      "Epoch 18/40\n",
      "500/500 [==============================] - 344s - loss: 0.2731 - val_loss: 0.2649\n",
      "Epoch 19/40\n",
      "500/500 [==============================] - 345s - loss: 0.2709 - val_loss: 0.2699\n",
      "Epoch 20/40\n",
      "500/500 [==============================] - 344s - loss: 0.2693 - val_loss: 0.2655\n",
      "Epoch 21/40\n",
      "500/500 [==============================] - 345s - loss: 0.2679 - val_loss: 0.2654\n",
      "Epoch 22/40\n",
      "500/500 [==============================] - 344s - loss: 0.2677 - val_loss: 0.2731\n",
      "Epoch 23/40\n",
      "500/500 [==============================] - 345s - loss: 0.2672 - val_loss: 0.2680\n",
      "Epoch 24/40\n",
      "500/500 [==============================] - 345s - loss: 0.2648 - val_loss: 0.2669\n",
      "Epoch 25/40\n",
      "500/500 [==============================] - 345s - loss: 0.2645 - val_loss: 0.2655\n",
      "Epoch 26/40\n",
      "500/500 [==============================] - 344s - loss: 0.2648 - val_loss: 0.2673\n",
      "Epoch 27/40\n",
      "500/500 [==============================] - 344s - loss: 0.2624 - val_loss: 0.2694\n",
      "Epoch 28/40\n",
      "500/500 [==============================] - 344s - loss: 0.2624 - val_loss: 0.2698\n",
      "Epoch 29/40\n",
      "500/500 [==============================] - 344s - loss: 0.2602 - val_loss: 0.2765\n",
      "Epoch 30/40\n",
      "500/500 [==============================] - 344s - loss: 0.2596 - val_loss: 0.2795\n",
      "Epoch 31/40\n",
      "500/500 [==============================] - 344s - loss: 0.2598 - val_loss: 0.2688\n",
      "Epoch 32/40\n",
      "500/500 [==============================] - 344s - loss: 0.2590 - val_loss: 0.2724\n",
      "Epoch 33/40\n",
      "500/500 [==============================] - 344s - loss: 0.2581 - val_loss: 0.2754\n",
      "Epoch 34/40\n",
      "500/500 [==============================] - 344s - loss: 0.2570 - val_loss: 0.2688\n",
      "Epoch 35/40\n",
      "500/500 [==============================] - 344s - loss: 0.2559 - val_loss: 0.2753\n",
      "Epoch 36/40\n",
      "500/500 [==============================] - 345s - loss: 0.2552 - val_loss: 0.2719\n",
      "Epoch 37/40\n",
      "500/500 [==============================] - 344s - loss: 0.2552 - val_loss: 0.2745\n",
      "Epoch 38/40\n",
      "500/500 [==============================] - 344s - loss: 0.2537 - val_loss: 0.2761\n",
      "Epoch 39/40\n",
      "500/500 [==============================] - 344s - loss: 0.2546 - val_loss: 0.2793\n",
      "Epoch 40/40\n",
      "500/500 [==============================] - 345s - loss: 0.2532 - val_loss: 0.2782\n"
     ]
    }
   ],
   "source": [
    "from keras.models import Sequential\n",
    "from keras import layers\n",
    "from keras.optimizers import RMSprop\n",
    "\n",
    "model = Sequential()\n",
    "model.add(layers.GRU(32,\n",
    "                     dropout=0.1,\n",
    "                     recurrent_dropout=0.5,\n",
    "                     return_sequences=True,\n",
    "                     input_shape=(None, float_data.shape[-1])))\n",
    "model.add(layers.GRU(64, activation='relu',\n",
    "                     dropout=0.1, \n",
    "                     recurrent_dropout=0.5))\n",
    "model.add(layers.Dense(1))\n",
    "\n",
    "model.compile(optimizer=RMSprop(), loss='mae')\n",
    "history = model.fit_generator(train_gen,\n",
    "                              steps_per_epoch=500,\n",
    "                              epochs=40,\n",
    "                              validation_data=val_gen,\n",
    "                              validation_steps=val_steps)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's take a look at our results:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f33151ee630>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\nAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3315184390>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "loss = history.history['loss']\n",
    "val_loss = history.history['val_loss']\n",
    "\n",
    "epochs = range(len(loss))\n",
    "\n",
    "plt.figure()\n",
    "\n",
    "plt.plot(epochs, loss, 'bo', label='Training loss')\n",
    "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
    "plt.title('Training and validation loss')\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that the added layers does improve ours results by a bit, albeit not very significantly. We can draw two conclusions:\n",
    "\n",
    "* Since we are still not overfitting too badly, we could safely increase the size of our layers, in quest for a bit of validation loss \n",
    "improvement. This does have a non-negligible computational cost, though. \n",
    "* Since adding a layer did not help us by a significant factor, we may be seeing diminishing returns to increasing network capacity at this \n",
    "point."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using bidirectional RNNs\n",
    "\n",
    "\n",
    "The last technique that we will introduce in this section is called \"bidirectional RNNs\". A bidirectional RNN is common RNN variant which \n",
    "can offer higher performance than a regular RNN on certain tasks. It is frequently used in natural language processing -- you could call it \n",
    "the Swiss army knife of deep learning for NLP.\n",
    "\n",
    "RNNs are notably order-dependent, or time-dependent: they process the timesteps of their input sequences in order, and shuffling or \n",
    "reversing the timesteps can completely change the representations that the RNN will extract from the sequence. This is precisely the reason \n",
    "why they perform well on problems where order is meaningful, such as our temperature forecasting problem. A bidirectional RNN exploits \n",
    "the order-sensitivity of RNNs: it simply consists of two regular RNNs, such as the GRU or LSTM layers that you are already familiar with, \n",
    "each processing input sequence in one direction (chronologically and antichronologically), then merging their representations. By \n",
    "processing a sequence both way, a bidirectional RNN is able to catch patterns that may have been overlooked by a one-direction RNN.\n",
    "\n",
    "Remarkably, the fact that the RNN layers in this section have so far processed sequences in chronological order (older timesteps first) may \n",
    "have been an arbitrary decision. At least, it's a decision we made no attempt at questioning so far. Could it be that our RNNs could have \n",
    "performed well enough if it were processing input sequences in antichronological order, for instance (newer timesteps first)? Let's try \n",
    "this in practice and see what we get. All we need to do is write a variant of our data generator, where the input sequences get reverted \n",
    "along the time dimension (replace the last line with `yield samples[:, ::-1, :], targets`). Training the same one-GRU-layer network as we \n",
    "used in the first experiment in this section, we get the following results:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def reverse_order_generator(data, lookback, delay, min_index, max_index,\n",
    "                            shuffle=False, batch_size=128, step=6):\n",
    "    if max_index is None:\n",
    "        max_index = len(data) - delay - 1\n",
    "    i = min_index + lookback\n",
    "    while 1:\n",
    "        if shuffle:\n",
    "            rows = np.random.randint(\n",
    "                min_index + lookback, max_index, size=batch_size)\n",
    "        else:\n",
    "            if i + batch_size >= max_index:\n",
    "                i = min_index + lookback\n",
    "            rows = np.arange(i, min(i + batch_size, max_index))\n",
    "            i += len(rows)\n",
    "\n",
    "        samples = np.zeros((len(rows),\n",
    "                           lookback // step,\n",
    "                           data.shape[-1]))\n",
    "        targets = np.zeros((len(rows),))\n",
    "        for j, row in enumerate(rows):\n",
    "            indices = range(rows[j] - lookback, rows[j], step)\n",
    "            samples[j] = data[indices]\n",
    "            targets[j] = data[rows[j] + delay][1]\n",
    "        yield samples[:, ::-1, :], targets\n",
    "        \n",
    "train_gen_reverse = reverse_order_generator(\n",
    "    float_data,\n",
    "    lookback=lookback,\n",
    "    delay=delay,\n",
    "    min_index=0,\n",
    "    max_index=200000,\n",
    "    shuffle=True,\n",
    "    step=step, \n",
    "    batch_size=batch_size)\n",
    "val_gen_reverse = reverse_order_generator(\n",
    "    float_data,\n",
    "    lookback=lookback,\n",
    "    delay=delay,\n",
    "    min_index=200001,\n",
    "    max_index=300000,\n",
    "    step=step,\n",
    "    batch_size=batch_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/20\n",
      "500/500 [==============================] - 172s - loss: 0.4781 - val_loss: 0.4797\n",
      "Epoch 2/20\n",
      "500/500 [==============================] - 171s - loss: 0.4529 - val_loss: 0.4679\n",
      "Epoch 3/20\n",
      "500/500 [==============================] - 170s - loss: 0.4071 - val_loss: 0.4536\n",
      "Epoch 4/20\n",
      "500/500 [==============================] - 171s - loss: 0.3670 - val_loss: 0.4398\n",
      "Epoch 5/20\n",
      "500/500 [==============================] - 170s - loss: 0.3343 - val_loss: 0.4320\n",
      "Epoch 6/20\n",
      "500/500 [==============================] - 170s - loss: 0.3191 - val_loss: 0.4388\n",
      "Epoch 7/20\n",
      "500/500 [==============================] - 170s - loss: 0.3065 - val_loss: 0.4186\n",
      "Epoch 8/20\n",
      "500/500 [==============================] - 170s - loss: 0.2938 - val_loss: 0.4014\n",
      "Epoch 9/20\n",
      "500/500 [==============================] - 170s - loss: 0.2824 - val_loss: 0.4077\n",
      "Epoch 10/20\n",
      "500/500 [==============================] - 170s - loss: 0.2724 - val_loss: 0.4090\n",
      "Epoch 11/20\n",
      "500/500 [==============================] - 170s - loss: 0.2670 - val_loss: 0.3990\n",
      "Epoch 12/20\n",
      "500/500 [==============================] - 170s - loss: 0.2613 - val_loss: 0.4146\n",
      "Epoch 13/20\n",
      "500/500 [==============================] - 170s - loss: 0.2548 - val_loss: 0.4013\n",
      "Epoch 14/20\n",
      "500/500 [==============================] - 170s - loss: 0.2521 - val_loss: 0.4086\n",
      "Epoch 15/20\n",
      "500/500 [==============================] - 170s - loss: 0.2458 - val_loss: 0.4178\n",
      "Epoch 16/20\n",
      "500/500 [==============================] - 170s - loss: 0.2437 - val_loss: 0.4097\n",
      "Epoch 17/20\n",
      "500/500 [==============================] - 170s - loss: 0.2416 - val_loss: 0.4163\n",
      "Epoch 18/20\n",
      "500/500 [==============================] - 170s - loss: 0.2373 - val_loss: 0.4174\n",
      "Epoch 19/20\n",
      "500/500 [==============================] - 170s - loss: 0.2355 - val_loss: 0.4064\n",
      "Epoch 20/20\n",
      "500/500 [==============================] - 170s - loss: 0.2313 - val_loss: 0.4261\n"
     ]
    }
   ],
   "source": [
    "model = Sequential()\n",
    "model.add(layers.GRU(32, input_shape=(None, float_data.shape[-1])))\n",
    "model.add(layers.Dense(1))\n",
    "\n",
    "model.compile(optimizer=RMSprop(), loss='mae')\n",
    "history = model.fit_generator(train_gen_reverse,\n",
    "                              steps_per_epoch=500,\n",
    "                              epochs=20,\n",
    "                              validation_data=val_gen_reverse,\n",
    "                              validation_steps=val_steps)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3314e81860>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n6KE7p2XOy8ujc+fOXHzxxXTt2pXjjz9+t+OUZOHChRx55JF0796doUOH8vnnn+88ftFUy0UTvf37\n3//eeROZnj17smXLlkqf25JonH4F1a0Lv/gFHH98uHr3qKPCJek33wxpmjRPJGl+/vPwjTaZevSA\nKF+WaO+996Z37968+OKLDBkyhKlTp3LmmWdiZjRs2JDp06ez5557smHDBo488kgGDx5c6n1iH374\nYRo1asSyZctYtGgRvXr12vna7bffzt57782OHTs49thjWbRoEVdeeSX33Xcfs2fPpmXLlrvta/78\n+Tz++OPMnTsXd+eII46gf//+NG/enBUrVvD000/z+9//njPPPJO//OUvZc6Pf8455/Dggw/Sv39/\nbrnlFm699VYeeOAB7rzzTj744AMaNGiws0np3nvvZeLEifTt25etW7fSsGHDCpzt8qmmH6nojdX7\n9An/HD/9Kdx2G/TrBytXpiJSkdontokntmnH3bnxxhvp3r07xx13HB9//DFr164tdT9z5szZmXy7\nd+9O9+7dd742bdo0evXqRc+ePVmyZEm5k6m9/vrrDB06lMaNG9OkSRNOO+00XnvtNQA6dOhAjx49\ngLKnb4Ywv/+mTZvo378/AOeeey5z5szZGeOIESOYPHnyzit/+/bty9VXX82ECRPYtGlT0q8IVk2f\nXXcDKmrWi/fG6nvuGTp4TzwxXMhVVKO58MLQDyBS05RVI69KQ4YMYfTo0SxYsIBt27Zx+OGHAzBl\nyhTWr1/P/PnzqVevHtnZ2SVOp1yeDz74gHvvvZd58+bRvHlzzjvvvErtp0jRtMwQpmYur3mnNC+8\n8AJz5szh73//O7fffjuLFy9mzJgxnHTSScycOZO+ffsya9YsDjnkkErHWlxcNX0zG2hmy81spZmN\nKaPc6WbmZpYTLWeb2XYzWxg9fpeswJMp0bsBnXlmGNrZuzdcfDGccorm7xGpiCZNmjBgwAAuuOCC\n3TpwN2/ezD777EO9evWYPXs2q1evLnM/Rx11FE899RQA7777LosWLQLCtMyNGzdmr732Yu3atbwY\nc0ONpk2blthu3q9fP/72t7+xbds2vvzyS6ZPn06/fv0q/LvttddeNG/efOe3hCeffJL+/ftTWFjI\nRx99xIABA7jrrrvYvHkzW7du5f3336dbt25cf/31fP/73+e9996r8DHLUm5N38zqABOBHwH5wDwz\n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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f330f25bcc0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "loss = history.history['loss']\n",
    "val_loss = history.history['val_loss']\n",
    "\n",
    "epochs = range(len(loss))\n",
    "\n",
    "plt.figure()\n",
    "\n",
    "plt.plot(epochs, loss, 'bo', label='Training loss')\n",
    "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
    "plt.title('Training and validation loss')\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "So the reversed-order GRU strongly underperforms even the common-sense baseline, indicating that the in our case chronological processing is very \n",
    "important to the success of our approach. This makes perfect sense: the underlying GRU layer will typically be better at remembering the \n",
    "recent past than the distant past, and naturally the more recent weather data points are more predictive than older data points in our \n",
    "problem (that's precisely what makes the common-sense baseline a fairly strong baseline). Thus the chronological version of the layer is \n",
    "bound to outperform the reversed-order version. Importantly, this is generally not true for many other problems, including natural \n",
    "language: intuitively, the importance of a word in understanding a sentence is not usually dependent on its position in the sentence. Let's \n",
    "try the same trick on the LSTM IMDB example from the previous section:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 20000 samples, validate on 5000 samples\n",
      "Epoch 1/10\n",
      "20000/20000 [==============================] - 111s - loss: 0.4965 - acc: 0.7648 - val_loss: 0.3593 - val_acc: 0.8570\n",
      "Epoch 2/10\n",
      "20000/20000 [==============================] - 107s - loss: 0.3105 - acc: 0.8810 - val_loss: 0.3329 - val_acc: 0.8648\n",
      "Epoch 3/10\n",
      "20000/20000 [==============================] - 105s - loss: 0.2566 - acc: 0.9057 - val_loss: 0.3863 - val_acc: 0.8770\n",
      "Epoch 4/10\n",
      "20000/20000 [==============================] - 106s - loss: 0.2231 - acc: 0.9195 - val_loss: 0.3471 - val_acc: 0.8556\n",
      "Epoch 5/10\n",
      "20000/20000 [==============================] - 105s - loss: 0.1912 - acc: 0.9314 - val_loss: 0.3346 - val_acc: 0.8694\n",
      "Epoch 6/10\n",
      "20000/20000 [==============================] - 105s - loss: 0.1721 - acc: 0.9379 - val_loss: 0.3621 - val_acc: 0.8520\n",
      "Epoch 7/10\n",
      "20000/20000 [==============================] - 105s - loss: 0.1613 - acc: 0.9427 - val_loss: 0.3438 - val_acc: 0.8694\n",
      "Epoch 8/10\n",
      "20000/20000 [==============================] - 105s - loss: 0.1502 - acc: 0.9503 - val_loss: 0.3890 - val_acc: 0.8588\n",
      "Epoch 9/10\n",
      "20000/20000 [==============================] - 105s - loss: 0.1369 - acc: 0.9520 - val_loss: 0.3626 - val_acc: 0.8768\n",
      "Epoch 10/10\n",
      "20000/20000 [==============================] - 105s - loss: 0.1249 - acc: 0.9579 - val_loss: 0.4639 - val_acc: 0.8566\n"
     ]
    }
   ],
   "source": [
    "from keras.datasets import imdb\n",
    "from keras.preprocessing import sequence\n",
    "from keras import layers\n",
    "from keras.models import Sequential\n",
    "\n",
    "# Number of words to consider as features\n",
    "max_features = 10000\n",
    "# Cut texts after this number of words (among top max_features most common words)\n",
    "maxlen = 500\n",
    "\n",
    "# Load data\n",
    "(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)\n",
    "\n",
    "# Reverse sequences\n",
    "x_train = [x[::-1] for x in x_train]\n",
    "x_test = [x[::-1] for x in x_test]\n",
    "\n",
    "# Pad sequences\n",
    "x_train = sequence.pad_sequences(x_train, maxlen=maxlen)\n",
    "x_test = sequence.pad_sequences(x_test, maxlen=maxlen)\n",
    "\n",
    "model = Sequential()\n",
    "model.add(layers.Embedding(max_features, 128))\n",
    "model.add(layers.LSTM(32))\n",
    "model.add(layers.Dense(1, activation='sigmoid'))\n",
    "\n",
    "model.compile(optimizer='rmsprop',\n",
    "              loss='binary_crossentropy',\n",
    "              metrics=['acc'])\n",
    "history = model.fit(x_train, y_train,\n",
    "                    epochs=10,\n",
    "                    batch_size=128,\n",
    "                    validation_split=0.2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "We get near-identical performance as the chronological-order LSTM we tried in the previous section.\n",
    "\n",
    "Thus, remarkably, on such a text dataset, reversed-order processing works just as well as chronological processing, confirming our \n",
    "hypothesis that, albeit word order *does* matter in understanding language, *which* order you use isn't crucial. Importantly, a RNN trained \n",
    "on reversed sequences will learn different representations than one trained on the original sequences, in much the same way that you would \n",
    "have quite different mental models if time flowed backwards in the real world -- if you lived a life where you died on your first day and \n",
    "you were born on your last day. In machine learning, representations that are *different* yet *useful* are always worth exploiting, and the \n",
    "more they differ the better: they offer a new angle from which to look at your data, capturing aspects of the data that were missed by other \n",
    "approaches, and thus they can allow to boost performance on a task. This is the intuition behind \"ensembling\", a concept that we will \n",
    "introduce in the next chapter.\n",
    "\n",
    "A bidirectional RNN exploits this idea to improve upon the performance of chronological-order RNNs: it looks at its inputs sequence both \n",
    "ways, obtaining potentially richer representations and capturing patterns that may have been missed by the chronological-order version alone."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![bidirectional rnn](https://s3.amazonaws.com/book.keras.io/img/ch6/bidirectional_rnn.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To instantiate a bidirectional RNN in Keras, one would use the `Bidirectional` layer, which takes as first argument a recurrent layer \n",
    "instance. `Bidirectional` will create a second, separate instance of this recurrent layer, and will use one instance for processing the \n",
    "input sequences in chronological order and the other instance for processing the input sequences in reversed order. Let's try it on the \n",
    "IMDB sentiment analysis task:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from keras import backend as K\n",
    "K.clear_session()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 20000 samples, validate on 5000 samples\n",
      "Epoch 1/10\n",
      "20000/20000 [==============================] - 214s - loss: 0.5994 - acc: 0.6865 - val_loss: 0.4722 - val_acc: 0.8090\n",
      "Epoch 2/10\n",
      "20000/20000 [==============================] - 213s - loss: 0.3673 - acc: 0.8543 - val_loss: 0.3769 - val_acc: 0.8448\n",
      "Epoch 3/10\n",
      "20000/20000 [==============================] - 213s - loss: 0.2743 - acc: 0.8972 - val_loss: 0.3196 - val_acc: 0.8688\n",
      "Epoch 4/10\n",
      "20000/20000 [==============================] - 211s - loss: 0.2310 - acc: 0.9150 - val_loss: 0.2972 - val_acc: 0.8856\n",
      "Epoch 5/10\n",
      "20000/20000 [==============================] - 211s - loss: 0.2009 - acc: 0.9261 - val_loss: 0.4461 - val_acc: 0.8514\n",
      "Epoch 6/10\n",
      "20000/20000 [==============================] - 210s - loss: 0.1912 - acc: 0.9339 - val_loss: 0.3636 - val_acc: 0.8640\n",
      "Epoch 7/10\n",
      "20000/20000 [==============================] - 209s - loss: 0.1670 - acc: 0.9423 - val_loss: 0.3476 - val_acc: 0.8580\n",
      "Epoch 8/10\n",
      "20000/20000 [==============================] - 210s - loss: 0.1523 - acc: 0.9469 - val_loss: 0.3887 - val_acc: 0.8830\n",
      "Epoch 9/10\n",
      "20000/20000 [==============================] - 209s - loss: 0.1431 - acc: 0.9506 - val_loss: 0.3781 - val_acc: 0.8810\n",
      "Epoch 10/10\n",
      "20000/20000 [==============================] - 209s - loss: 0.1366 - acc: 0.9521 - val_loss: 0.3713 - val_acc: 0.8792\n"
     ]
    }
   ],
   "source": [
    "model = Sequential()\n",
    "model.add(layers.Embedding(max_features, 32))\n",
    "model.add(layers.Bidirectional(layers.LSTM(32)))\n",
    "model.add(layers.Dense(1, activation='sigmoid'))\n",
    "\n",
    "model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])\n",
    "history = model.fit(x_train, y_train, epochs=10, batch_size=128, validation_split=0.2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It performs slightly better than the regular LSTM we tried in the previous section, going above 88% validation accuracy. It also seems to \n",
    "overfit faster, which is unsurprising since a bidirectional layer has twice more parameters than a chronological LSTM. With some \n",
    "regularization, the bidirectional approach would likely be a strong performer on this task.\n",
    "\n",
    "Now let's try the same approach on the weather prediction task:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/40\n",
      "500/500 [==============================] - 325s - loss: 0.3029 - val_loss: 0.2660\n",
      "Epoch 2/40\n",
      "500/500 [==============================] - 324s - loss: 0.2751 - val_loss: 0.2660\n",
      "Epoch 3/40\n",
      "500/500 [==============================] - 326s - loss: 0.2668 - val_loss: 0.2628\n",
      "Epoch 4/40\n",
      "500/500 [==============================] - 326s - loss: 0.2594 - val_loss: 0.2615\n",
      "Epoch 5/40\n",
      "500/500 [==============================] - 324s - loss: 0.2532 - val_loss: 0.2684\n",
      "Epoch 6/40\n",
      "500/500 [==============================] - 324s - loss: 0.2442 - val_loss: 0.2674\n",
      "Epoch 7/40\n",
      "500/500 [==============================] - 324s - loss: 0.2405 - val_loss: 0.2700\n",
      "Epoch 8/40\n",
      "500/500 [==============================] - 324s - loss: 0.2343 - val_loss: 0.2782\n",
      "Epoch 9/40\n",
      "500/500 [==============================] - 324s - loss: 0.2293 - val_loss: 0.2778\n",
      "Epoch 10/40\n",
      "500/500 [==============================] - 324s - loss: 0.2233 - val_loss: 0.2813\n",
      "Epoch 11/40\n",
      "500/500 [==============================] - 324s - loss: 0.2167 - val_loss: 0.2978\n",
      "Epoch 12/40\n",
      "500/500 [==============================] - 324s - loss: 0.2116 - val_loss: 0.2984\n",
      "Epoch 13/40\n",
      "500/500 [==============================] - 324s - loss: 0.2061 - val_loss: 0.2920\n",
      "Epoch 14/40\n",
      "500/500 [==============================] - 323s - loss: 0.2008 - val_loss: 0.3016\n",
      "Epoch 15/40\n",
      "500/500 [==============================] - 324s - loss: 0.1952 - val_loss: 0.2985\n",
      "Epoch 16/40\n",
      "500/500 [==============================] - 324s - loss: 0.1915 - val_loss: 0.3029\n",
      "Epoch 17/40\n",
      "500/500 [==============================] - 323s - loss: 0.1862 - val_loss: 0.3127\n",
      "Epoch 18/40\n",
      "500/500 [==============================] - 324s - loss: 0.1821 - val_loss: 0.3079\n",
      "Epoch 19/40\n",
      "500/500 [==============================] - 324s - loss: 0.1772 - val_loss: 0.3116\n",
      "Epoch 20/40\n",
      "500/500 [==============================] - 323s - loss: 0.1735 - val_loss: 0.3151\n",
      "Epoch 21/40\n",
      "500/500 [==============================] - 323s - loss: 0.1705 - val_loss: 0.3208\n",
      "Epoch 22/40\n",
      "500/500 [==============================] - 324s - loss: 0.1664 - val_loss: 0.3345\n",
      "Epoch 23/40\n",
      "500/500 [==============================] - 323s - loss: 0.1631 - val_loss: 0.3162\n",
      "Epoch 24/40\n",
      "500/500 [==============================] - 324s - loss: 0.1604 - val_loss: 0.3141\n",
      "Epoch 25/40\n",
      "500/500 [==============================] - 324s - loss: 0.1572 - val_loss: 0.3173\n",
      "Epoch 26/40\n",
      "500/500 [==============================] - 325s - loss: 0.1559 - val_loss: 0.3156\n",
      "Epoch 27/40\n",
      "500/500 [==============================] - 324s - loss: 0.1530 - val_loss: 0.3227\n",
      "Epoch 28/40\n",
      "500/500 [==============================] - 324s - loss: 0.1521 - val_loss: 0.3288\n",
      "Epoch 29/40\n",
      "500/500 [==============================] - 325s - loss: 0.1496 - val_loss: 0.3264\n",
      "Epoch 30/40\n",
      "500/500 [==============================] - 324s - loss: 0.1481 - val_loss: 0.3266\n",
      "Epoch 31/40\n",
      "500/500 [==============================] - 323s - loss: 0.1456 - val_loss: 0.3241\n",
      "Epoch 32/40\n",
      "500/500 [==============================] - 323s - loss: 0.1436 - val_loss: 0.3293\n",
      "Epoch 33/40\n",
      "500/500 [==============================] - 324s - loss: 0.1426 - val_loss: 0.3301\n",
      "Epoch 34/40\n",
      "500/500 [==============================] - 324s - loss: 0.1409 - val_loss: 0.3298\n",
      "Epoch 35/40\n",
      "500/500 [==============================] - 324s - loss: 0.1399 - val_loss: 0.3372\n",
      "Epoch 36/40\n",
      "500/500 [==============================] - 323s - loss: 0.1387 - val_loss: 0.3304\n",
      "Epoch 37/40\n",
      "500/500 [==============================] - 324s - loss: 0.1388 - val_loss: 0.3324\n",
      "Epoch 38/40\n",
      "500/500 [==============================] - 324s - loss: 0.1362 - val_loss: 0.3317\n",
      "Epoch 39/40\n",
      "500/500 [==============================] - 323s - loss: 0.1342 - val_loss: 0.3319\n",
      "Epoch 40/40\n",
      "500/500 [==============================] - 324s - loss: 0.1350 - val_loss: 0.3289\n"
     ]
    }
   ],
   "source": [
    "from keras.models import Sequential\n",
    "from keras import layers\n",
    "from keras.optimizers import RMSprop\n",
    "\n",
    "model = Sequential()\n",
    "model.add(layers.Bidirectional(\n",
    "    layers.GRU(32), input_shape=(None, float_data.shape[-1])))\n",
    "model.add(layers.Dense(1))\n",
    "\n",
    "model.compile(optimizer=RMSprop(), loss='mae')\n",
    "history = model.fit_generator(train_gen,\n",
    "                              steps_per_epoch=500,\n",
    "                              epochs=40,\n",
    "                              validation_data=val_gen,\n",
    "                              validation_steps=val_steps)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "It performs about as well as the regular GRU layer. It's easy to understand why: all of the predictive capacity must be coming from the \n",
    "chronological half of the network, since the anti-chronological half is known to be severely underperforming on this task (again, because \n",
    "the recent past matters much more than the distant past in this case)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Going even further\n",
    "\n",
    "At this stage, there are still many other things you could try in order to improve performance on our weather forecasting problem:\n",
    "\n",
    "* Adjust the number of units in each recurrent layer in the stacked setup. Our current choices are largely arbitrary and thus likely \n",
    "suboptimal.\n",
    "* Adjust the learning rate used by our `RMSprop` optimizer.\n",
    "* Try using `LSTM` layers instead of `GRU` layers.\n",
    "* Try using a bigger densely-connected regressor on top of the recurrent layers, i.e. a bigger `Dense` layer or even a stack of `Dense` \n",
    "layers.\n",
    "* Don't forget to eventually run the best performing models (in terms of validation MAE) on the test set! Least you start developing \n",
    "architectures that are overfitting to the validation set.   \n",
    "\n",
    "As usual: deep learning is more an art than a science, and while we can provide guidelines as to what is likely to work or not work on a \n",
    "given problem, ultimately every problem is unique and you will have to try and evaluate different strategies empirically. There is \n",
    "currently no theory that will tell you in advance precisely what you should do to optimally solve a problem. You must try and iterate.\n",
    "\n",
    "\n",
    "## Wrapping up\n",
    "\n",
    "Here's what you should take away from this section:\n",
    "\n",
    "* As you first learned in Chapter 4, when approaching a new problem, \n",
    "it is good to first establish common sense baselines for your metric of choice. If you don't have a \n",
    "baseline to beat, you can't tell if you are making any real progress.\n",
    "* Try simple models before expensive ones, to justify the additional expense. Sometimes a simple model will turn out to be your best option.\n",
    "* On data where temporal ordering matters, recurrent networks are a great fit and easily outperform models that first flatten the temporal \n",
    "data.\n",
    "* To use dropout with recurrent networks, one should use a time-constant dropout mask and recurrent dropout mask. This is built into Keras \n",
    "recurrent layers, so all you have to do is use the `dropout` and `recurrent_dropout` arguments of recurrent layers.\n",
    "* Stacked RNNs provide more representational power than a single RNN layer. They are also much more expensive, and thus not always worth it. \n",
    "While they offer clear gains on complex problems (e.g. machine translation), they might not always be relevant to smaller, simpler problems.\n",
    "* Bidirectional RNNs, which look at a sequence both ways, are very useful on natural language processing problems. However, they will not \n",
    "be strong performers on sequence data where the recent past is much more informative than the beginning of the sequence.\n",
    "\n",
    "Note there are two important concepts that we will not cover in detail here: recurrent \"attention\", and sequence masking. Both tend to be \n",
    "especially relevant for natural language processing, and are not particularly applicable to our temperature forecasting problem. We will \n",
    "leave them for future study outside of this book."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
