mirror of
https://github.com/fchollet/deep-learning-with-python-notebooks.git
synced 2021-07-27 01:28:40 +03:00
1677 lines
199 KiB
Plaintext
1677 lines
199 KiB
Plaintext
{
|
|
"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": "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\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": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAEICAYAAACzliQjAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XmYFNW5+PHvyy6L7G4Mm8oVZgABR9CLiCAqioAYoiC4\nRYMScQl6r0SIMRjuT9HgFmIkiZrICKJGJW64oWgUZFAEARHEQQYQAWUTBIZ5f3+c6pmeYbq7prun\nu6f7/TxPP9NVdarqdPX0W6fOOXVKVBVjjDGZoUayM2CMMSZxLOgbY0wGsaBvjDEZxIK+McZkEAv6\nxhiTQSzoG2NMBrGgbypFRGqKyB4RaRPPtMkkIieKSNz7LovIABEpCJpeLSJ9/KSNYl9/E5E7ol0/\nzHb/ICJPxnu7JnlqJTsDpmqJyJ6gyfrAfuCQN32dquZVZnuqeghoGO+0mUBVT4rHdkTkWmC0qp4V\ntO1r47Ftk/4s6Kc5VS0Jul5J8lpVfStUehGppapFicibMSbxrHonw3mX78+IyCwR2Q2MFpHTRWSh\niOwQkc0i8rCI1PbS1xIRFZF23vRMb/lrIrJbRD4SkfaVTestP19EvhSRnSLyiIj8R0SuCpFvP3m8\nTkTWisgPIvJw0Lo1ReQBEdkuIuuAgWGOz0QRmV1u3nQRmea9v1ZEVnmf5yuvFB5qW4Uicpb3vr6I\nPOXlbQVwSrm0k0RknbfdFSIyxJvfBfgT0MerOtsWdGzvClr/eu+zbxeRF0XkWD/HJhIRGeblZ4eI\nvCMiJwUtu0NENonILhH5IuizniYin3jzt4jIfX73Z6qAqtorQ15AATCg3Lw/AAeAwbhCwBHAqUAv\n3JXg8cCXwDgvfS1AgXbe9ExgG5AL1AaeAWZGkfYoYDcw1Fs2HjgIXBXis/jJ40tAY6Ad8H3gswPj\ngBVAFtAcWOB+ChXu53hgD9AgaNvfAbne9GAvjQD9gX1AV2/ZAKAgaFuFwFne+/uBd4GmQFtgZbm0\nlwDHet/JZV4ejvaWXQu8Wy6fM4G7vPfnennsBtQD/gy84+fYVPD5/wA86b3v5OWjv/cd3QGs9t7n\nAOuBY7y07YHjvfeLgZHe+0ZAr2T/FjL5ZSV9A/CBqv5bVYtVdZ+qLlbVRapapKrrgBlA3zDrP6eq\n+ap6EMjDBZvKpr0QWKqqL3nLHsCdICrkM4//T1V3qmoBLsAG9nUJ8ICqFqrqduCeMPtZB3yOOxkB\nnAP8oKr53vJ/q+o6dd4B3gYqbKwt5xLgD6r6g6qux5Xeg/c7R1U3e9/J07gTdq6P7QKMAv6mqktV\n9SdgAtBXRLKC0oQ6NuGMAOaq6jved3QP7sTRCyjCnWByvCrCr71jB+7k3UFEmqvqblVd5PNzmCpg\nQd8AbAieEJGOIvKKiHwrIruAyUCLMOt/G/R+L+Ebb0OlPS44H6qquJJxhXzm0de+cCXUcJ4GRnrv\nL/OmA/m4UEQWicj3IrIDV8oOd6wCjg2XBxG5SkQ+86pRdgAdfW4X3Ocr2Z6q7gJ+AFoFpanMdxZq\nu8W476iVqq4GbsV9D9951YXHeEmvBrKB1SLysYhc4PNzmCpgQd+Au9wP9hiudHuiqh4J3ImrvqhK\nm3HVLQCIiFA2SJUXSx43A62DpiN1KZ0DDBCRVrgS/9NeHo8AngP+H67qpQnwhs98fBsqDyJyPPAo\nMBZo7m33i6DtRupeuglXZRTYXiNcNdJGH/mqzHZr4L6zjQCqOlNVe+OqdmrijguqulpVR+Cq8P4I\nPC8i9WLMi4mSBX1TkUbATuBHEekEXJeAfb4M9BCRwSJSC7gZaFlFeZwD3CIirUSkOXB7uMSq+i3w\nAfAksFpV13iL6gJ1gK3AIRG5EDi7Enm4Q0SaiLuPYVzQsoa4wL4Vd/77Ja6kH7AFyAo0XFdgFnCN\niHQVkbq44Pu+qoa8cqpEnoeIyFnevv8H1w6zSEQ6iUg/b3/7vFcx7gNcLiItvCuDnd5nK44xLyZK\nFvRNRW4FrsT9oB/DNbhWKVXdAlwKTAO2AycAn+LuK4h3Hh/F1b0vxzUyPudjnadxDbMlVTuqugP4\nNfACrjF0OO7k5cfvcFccBcBrwD+DtrsMeAT42EtzEhBcD/4msAbYIiLB1TSB9V/HVbO84K3fBlfP\nHxNVXYE75o/iTkgDgSFe/X5dYCquHeZb3JXFRG/VC4BV4nqH3Q9cqqoHYs2PiY64qlNjUouI1MRV\nJwxX1feTnR9j0oWV9E3KEJGBXnVHXeC3uF4fHyc5W8akFQv6JpWcAazDVR2cBwxT1VDVO8aYKFj1\njjHGZBAr6RtjTAZJuQHXWrRooe3atUt2NowxplpZsmTJNlUN180ZSMGg365dO/Lz85OdDWOMqVZE\nJNKd5YBV7xhjTEaxoG+MMRnEgr4xxmSQlKvTN8Yk1sGDByksLOSnn35KdlaMD/Xq1SMrK4vatUMN\nvRSeBX1jMlxhYSGNGjWiXbt2uMFNTapSVbZv305hYSHt27ePvEIF0qZ6Jy8P2rWDGjXc37xKPe7b\nmMz1008/0bx5cwv41YCI0Lx585iuytKipJ+XB2PGwN69bnr9ejcNMCrmsQWNSX8W8KuPWL+rtCjp\nT5xYGvAD9u51840xxpRKi6D/zTeVm2+MSR3bt2+nW7dudOvWjWOOOYZWrVqVTB844G/Y/auvvprV\nq1eHTTN9+nTy4lTve8YZZ7B06dK4bCvR0qJ6p00bV6VT0XxjTHzl5bmr6G++cb+xKVNiq0Zt3rx5\nSQC96667aNiwIbfddluZNKqKqlKjRsXl1CeeeCLifm644YboM5lG0qKkP2UK1K9fdl79+m6+MSZ+\nAu1n69eDamn7WVV0nFi7di3Z2dmMGjWKnJwcNm/ezJgxY8jNzSUnJ4fJkyeXpA2UvIuKimjSpAkT\nJkzg5JNP5vTTT+e7774DYNKkSTz44IMl6SdMmEDPnj056aST+PDDDwH48ccf+dnPfkZ2djbDhw8n\nNzc3Yol+5syZdOnShc6dO3PHHXcAUFRUxOWXX14y/+GHHwbggQceIDs7m65duzJ69Oi4HzM/0qKk\nHyhlxLP0YYw5XLj2s6r4vX3xxRf885//JDc3F4B77rmHZs2aUVRURL9+/Rg+fDjZ2dll1tm5cyd9\n+/blnnvuYfz48Tz++ONMmDDhsG2rKh9//DFz585l8uTJvP766zzyyCMcc8wxPP/883z22Wf06NEj\nbP4KCwuZNGkS+fn5NG7cmAEDBvDyyy/TsmVLtm3bxvLlywHYsWMHAFOnTmX9+vXUqVOnZF6ipUVJ\nH9w/XEEBFBe7vxbwjYm/RLefnXDCCSUBH2DWrFn06NGDHj16sGrVKlauXHnYOkcccQTnn38+AKec\ncgoFBQUVbvviiy8+LM0HH3zAiBEjADj55JPJyckJm79FixbRv39/WrRoQe3atbnssstYsGABJ554\nIqtXr+amm25i3rx5NG7cGICcnBxGjx5NXl5e1DdXxSptgr4xpuqFaierqvazBg0alLxfs2YNDz30\nEO+88w7Lli1j4MCBFfZXr1OnTsn7mjVrUlRUVOG269atGzFNtJo3b86yZcvo06cP06dP57rrrgNg\n3rx5XH/99SxevJiePXty6NChuO7XDwv6xhjfktl+tmvXLho1asSRRx7J5s2bmTdvXtz30bt3b+bM\nmQPA8uXLK7ySCNarVy/mz5/P9u3bKSoqYvbs2fTt25etW7eiqvz85z9n8uTJfPLJJxw6dIjCwkL6\n9+/P1KlT2bZtG3vL15UlgK86fREZCDwE1AT+pqr3lFt+PXADcAjYA4xR1ZUi0hOYEUgG3KWqL8Qr\n88aYxEpm+1mPHj3Izs6mY8eOtG3blt69e8d9HzfeeCNXXHEF2dnZJa9A1UxFsrKyuPvuuznrrLNQ\nVQYPHsygQYP45JNPuOaaa1BVRIR7772XoqIiLrvsMnbv3k1xcTG33XYbjRo1ivtniCTiM3JFpCbw\nJXAOUAgsBkaq6sqgNEeq6i7v/RDgV6o6UETqAwdUtUhEjgU+A45T1ZDXUrm5uWoPUTEmcVatWkWn\nTp2SnY2UUFRURFFREfXq1WPNmjWce+65rFmzhlq1UqvPS0XfmYgsUdXcEKuU8PNJegJrVXWdt+HZ\nwFCgJOgHAr6nAaDe/OBrl3qB+cYYk4r27NnD2WefTVFREarKY489lnIBP1Z+Pk0rYEPQdCHQq3wi\nEbkBGA/UAfoHze8FPA60BS6vqJQvImOAMQBt7I4qY0ySNGnShCVLliQ7G1Uqbg25qjpdVU8Abgcm\nBc1fpKo5wKnAb0SkXgXrzlDVXFXNbdky4nN9jTHGRMlP0N8ItA6azvLmhTIbuKj8TFVdhWvk7VyZ\nDBpjjIkfP0F/MdBBRNqLSB1gBDA3OIGIdAiaHASs8ea3F5Fa3vu2QEegIA75NsYYE4WIdfpez5tx\nwDxcl83HVXWFiEwG8lV1LjBORAYAB4EfgCu91c8AJojIQaAY16tnW1V8EGOMMZH5qtNX1VdV9b9U\n9QRVneLNu9ML+Kjqzaqao6rdVLWfqq7w5j8VNL+Hqr5YdR/FGFMd9evX77AbrR588EHGjh0bdr2G\nDRsCsGnTJoYPH15hmrPOOotIXcAffPDBMjdJXXDBBXEZF+euu+7i/vvvj3k78WZ35BpjkmrkyJHM\nnj27zLzZs2czcuRIX+sfd9xxPPfcc1Hvv3zQf/XVV2nSpEnU20t1FvSNMUk1fPhwXnnllZIHphQU\nFLBp0yb69OlT0m++R48edOnShZdeeumw9QsKCujc2fUP2bdvHyNGjKBTp04MGzaMffv2laQbO3Zs\nybDMv/vd7wB4+OGH2bRpE/369aNfv34AtGvXjm3bXC30tGnT6Ny5M507dy4ZlrmgoIBOnTrxy1/+\nkpycHM4999wy+6nI0qVLOe200+jatSvDhg3jhx9+KNl/YKjlwEBv7733XslDZLp3787u3bujPrYV\nSa+7DowxMbnlFoj3A6G6dQMvXlaoWbNm9OzZk9dee42hQ4cye/ZsLrnkEkSEevXq8cILL3DkkUey\nbds2TjvtNIYMGRLyObGPPvoo9evXZ9WqVSxbtqzM0MhTpkyhWbNmHDp0iLPPPptly5Zx0003MW3a\nNObPn0+LFi3KbGvJkiU88cQTLFq0CFWlV69e9O3bl6ZNm7JmzRpmzZrFX//6Vy655BKef/75sOPj\nX3HFFTzyyCP07duXO++8k9///vc8+OCD3HPPPXz99dfUrVu3pErp/vvvZ/r06fTu3Zs9e/ZQr95h\nvdxjYiV9Y0zSBVfxBFftqCp33HEHXbt2ZcCAAWzcuJEtW7aE3M6CBQtKgm/Xrl3p2rVrybI5c+bQ\no0cPunfvzooVKyIOpvbBBx8wbNgwGjRoQMOGDbn44ot5//33AWjfvj3dunUDwg/fDG58/x07dtC3\nb18ArrzyShYsWFCSx1GjRjFz5sySO3979+7N+PHjefjhh9mxY0fc7wi2kr4xpkS4EnlVGjp0KL/+\n9a/55JNP2Lt3L6eccgoAeXl5bN26lSVLllC7dm3atWtX4XDKkXz99dfcf//9LF68mKZNm3LVVVdF\ntZ2AwLDM4IZmjlS9E8orr7zCggUL+Pe//82UKVNYvnw5EyZMYNCgQbz66qv07t2befPm0bFjx6jz\nWp6V9I0xSdewYUP69evHL37xizINuDt37uSoo46idu3azJ8/n/UVPQw7yJlnnsnTTz8NwOeff86y\nZcsANyxzgwYNaNy4MVu2bOG1114rWadRo0YV1pv36dOHF198kb179/Ljjz/ywgsv0KdPn0p/tsaN\nG9O0adOSq4SnnnqKvn37UlxczIYNG+jXrx/33nsvO3fuZM+ePXz11Vd06dKF22+/nVNPPZUvvvii\n0vsMx0r6xpiUMHLkSIYNG1amJ8+oUaMYPHgwXbp0ITc3N2KJd+zYsVx99dV06tSJTp06lVwxnHzy\nyXTv3p2OHTvSunXrMsMyjxkzhoEDB3Lccccxf/78kvk9evTgqquuomfPngBce+21dO/ePWxVTij/\n+Mc/uP7669m7dy/HH388TzzxBIcOHWL06NHs3LkTVeWmm26iSZMm/Pa3v2X+/PnUqFGDnJyckqeA\nxUvEoZUTzYZWNiaxbGjl6ieWoZWtescYYzKIBX1jjMkgFvSNMaRaNa8JLdbvyoK+MRmuXr16bN++\n3QJ/NaCqbN++PaYbtqz3jjEZLisri8LCQrZu3ZrsrBgf6tWrR1ZWVtTrW9A3JsPVrl2b9u3bJzsb\nJkGsescYYzKIBX1jjMkgvoK+iAwUkdUislZEJlSw/HoRWS4iS0XkAxHJ9uafIyJLvGVLRKR/vD+A\nMcYY/yIGfRGpCUwHzgeygZGBoB7kaVXtoqrdgKnANG/+NmCwqnbBPULxqbjl3BhjTKX5Ken3BNaq\n6jpVPQDMBoYGJ1DVXUGTDQD15n+qqpu8+SuAI0SkLsYYY5LCT++dVsCGoOlCoFf5RCJyAzAeqANU\nVI3zM+ATVd1fwbpjgDEAbdq08ZElY4wx0YhbQ66qTlfVE4DbgUnBy0QkB7gXuC7EujNUNVdVc1u2\nbBmvLBljjCnHT9DfCLQOms7y5oUyG7goMCEiWcALwBWq+lU0mTTGGBMffoL+YqCDiLQXkTrACGBu\ncAIR6RA0OQhY481vArwCTFDV/8Qny8YYY6IVMeirahEwDpgHrALmqOoKEZksIkO8ZONEZIWILMXV\n618ZmA+cCNzpdedcKiJHxf9jGGOM8cMeomKMMWnAHqJijDHmMBb0jTEmg1jQN8aYDGJB3xhjMogF\nfWOMySAW9I0xJoNY0DfGmAxiQd8YYzKIBX1jjMkgGRH08/KgXTuoUcP9zctLdo6MMSY5/IynX63l\n5cGYMbB3r5tev95NA4walbx8GWNMMqR9SX/ixNKAH7B3r5tvjDGZJu2D/jffVG6+Mcaks7QP+qGe\nvmhPZTTGZKK0D/pTpkD9+mXn1a/v5htjTKbxFfRFZKCIrBaRtSIyoYLl14vIcu8hKR+ISLY3v7mI\nzBeRPSLyp3hn3o9Ro2DGDGjbFkTc3xkzrBHXGJOZIj5ERURqAl8C5wCFuMcnjlTVlUFpjlTVXd77\nIcCvVHWgiDQAugOdgc6qOi5ShuwhKsYYU3nxfIhKT2Ctqq5T1QO4B58PDU4QCPieBoB6839U1Q+A\nn3zn3BhjTJXx00+/FbAhaLoQ6FU+kYjcgHs+bh2gf2UyISJjgDEAbayF1RhjqkzcGnJVdbqqngDc\nDkyq5LozVDVXVXNbtmwZrywZY4wpx0/Q3wi0DprO8uaFMhu4KJZMGWOMqRp+gv5ioIOItBeROsAI\nYG5wAhHpEDQ5CFgTvywaY4yJl4h1+qpaJCLjgHlATeBxVV0hIpOBfFWdC4wTkQHAQeAH4MrA+iJS\nABwJ1BGRi4Bzg3v+GGOMSZyIXTYTzbpsGmNM5cWzy6Yxxpg0YUHfGGMyiAV9Y4zJIBb0jTEmg1jQ\nN8aYDGJBH3uGrjEmc6T9M3IjsWfoGmMyScaX9O0ZusaYTJLxQd+eoWuMySQZH/TtGbrGmEyS8UHf\nnqFrjMkkGR/0/TxD13r3GGPSRcb33gEX4EP11LHePcaYdJLxJf1IrHePMSadWNCPwHr3GGPSia+g\nLyIDRWS1iKwVkQkVLL9eRJaLyFIR+UBEsoOW/cZbb7WInBfPzCeC9e4xxqSTiEFfRGoC04HzgWxg\nZHBQ9zytql1UtRswFZjmrZuNe7xiDjAQ+LO3vWrDevcYY9KJn5J+T2Ctqq5T1QO4B58PDU6gqruC\nJhsAgcdxDQVmq+p+Vf0aWOttr9rw07vHGGOqCz+9d1oBG4KmC4Fe5ROJyA3AeKAO0D9o3YXl1m0V\nVU6TKFzvHmOMqU7i1pCrqtNV9QTgdmBSZdYVkTEiki8i+Vu3bo1XlowxxpTjJ+hvBFoHTWd580KZ\nDVxUmXVVdYaq5qpqbsuWLX1kyRhjTDT8BP3FQAcRaS8idXANs3ODE4hIh6DJQcAa7/1cYISI1BWR\n9kAH4OPYs22MMSYaEev0VbVIRMYB84CawOOqukJEJgP5qjoXGCciA4CDwA/Ald66K0RkDrASKAJu\nUNVDVfRZjDHGRCCqGjlVAuXm5mp+fn6ys2GMMdWKiCxR1dxI6eyOXGOMySAW9I0xJoNY0I8DG3rZ\nGFNd2NDKMbKhl40x1YmV9GNkQy8bY6oTC/oxsqGXjTHViQX9GNnQy8aY6sSCfoxs6GVjTHViQT9G\nNvSyMaY6sd47cWBDLxtjqgsr6SeA9eM3xqQKK+lXMevHb4xJJVbSr2LWj98Yk0os6Fcx68dvjEkl\nFvSrWKR+/Fbfb4xJJAv6VSxcP/5Aff/69aBaWt9vgd8YU1V8BX0RGSgiq0VkrYhMqGD5eBFZKSLL\nRORtEWkbtOxeEfnce10az8xXB+H68Vt9vzEm0SI+OUtEagJfAucAhbhn5o5U1ZVBafoBi1R1r4iM\nBc5S1UtFZBBwC3A+UBd4FzhbVXeF2l8mPTmrRg1Xwi9PBIqLE58fY0z1Fc8nZ/UE1qrqOlU9AMwG\nhgYnUNX5qhoosy4Esrz32cACVS1S1R+BZcBAvx8i3dm4PcaYRPMT9FsBG4KmC715oVwDvOa9/wwY\nKCL1RaQF0A9oXX4FERkjIvkikr9161Z/OU8DNm6PMSbR4tqQKyKjgVzgPgBVfQN4FfgQmAV8BBwq\nv56qzlDVXFXNbdmyZTyzlNJs3B5jTKL5CfobKVs6z/LmlSEiA4CJwBBV3R+Yr6pTVLWbqp4DCK59\nwHhGjYKCAleHX1BweMC3Lp3GmHjyMwzDYqCDiLTHBfsRwGXBCUSkO/AYMFBVvwuaXxNooqrbRaQr\n0BV4I16ZT3c2hIMxJt4ilvRVtQgYB8wDVgFzVHWFiEwWkSFesvuAhsCzIrJUROZ682sD74vISmAG\nMNrbnvHBunQaY+ItYpfNRMukLpuR+OnSmZfnTgLffON6/UyZYlcBxmSieHbZNEniZwgHu6PXGFMZ\nFvRTWKQunVb9Y4ypLAv6KSxSl04bwdMYU1n2EJUUF+5RjG3auCqdiuYbY0xFrKRfjdkdvcaYyrKg\nX43ZHb3GmMqy6p1qLlz1jzHGlGcl/TRnwzgYY4JZST+N2TAOxpjyrKSfxvz047crAWMyiwX9NBap\nH7+fO3rtpGBMerGgn8YiDeMQ6UrAhnkwJv1Y0E9jkfrxR7oSsGEejEk/FvTTWKR+/JGuBGyYB2PS\njwX9NBfuyVyRrgTswe3GpB9fQV9EBorIahFZKyITKlg+XkRWisgyEXlbRNoGLZsqIitEZJWIPCwi\nEs8PYKIX6UrAhnkwJv1EDPreIw+nA+cD2cBIEckul+xTIFdVuwLPAVO9df8b6I17TGJn4FSgb9xy\nb2IW7krAhnkwJv34uTmrJ7BWVdcBiMhsYCiwMpBAVecHpV8IjA4sAuoBdXAPRa8NbIk92yZRbJgH\nY9KLn+qdVsCGoOlCb14o1wCvAajqR8B8YLP3mqeqq8qvICJjRCRfRPK3bt3qN+/GmBRUXAwHDiQ7\nFyaUuDbkishoIBf3oHRE5ESgE5CFO1H0F5E+5ddT1RmqmququS1btoxnlkwVshu3THnr10PHjjBi\nRLJzknrefBOuuw5efRUOHkxePvxU72wEWgdNZ3nzyhCRAcBEoK+q7vdmDwMWquoeL81rwOnA+7Fk\n2iSfjetjyvvySzj7bCgshK+/hp07oXHjZOcqNbz2Glx0kQv2M2ZA8+YwfDiMHAl9+riCU6L42dVi\noIOItBeROsAIYG5wAhHpDjwGDFHV74IWfQP0FZFaIlIb14h7WPWOqX7iceOWXSmkj+XL4cwzYf9+\n+NOfoKgI3ngj2blKDfPmwbBhkJMDmzbBSy/BOefAU0/BWWe5LtC33gqLF7s736ucqkZ8ARcAXwJf\nARO9eZNxQR7gLVwD7VLvNdebXxN3MliFa/idFmlfp5xyikbj0CHV3/xGdf36qFY3lSSi6v5Fy75E\nStPMnKnatq2b17atmw5eVr9+2XXr1y+bxlQPH3+s2rSpaqtWqqtWqRYVqTZrpnr55cnOWfK9+aZq\nvXqqJ5+sum1b2WV79qjOmqU6ZIhq7druN3DGGdHvC8hXP/HcT6JEvqIN+l98oXrkkaotW6q+915U\nmzCV0LZtxUG/bVu3PFJQj7S+qR7ee0+1USPV9u1V160rnT96tGrz5u4EkKneftsF/C5dVLduDZ/2\n++9V//Y31enTo99fxgV9VRf4TzpJtVYt1T/9SbW4OOpNmQhiDep+rhRManv9ddUjjlDt2FG1sLDs\nsmeecd/nBx8kJ2/JNn++OzadO6t+911i9uk36KfVMAwnnQSLFsHAgTBuHFx7ratjNPEX6catSOP2\n2BAP1dsLL8Dgwe4399570KpcJ+7zzoNateDll5OTv2RasAAGDYL27eHttyHlOiT6OTMk8hVLST/g\n0CHVSZNcSeO001Q3box5k6aSYq3+ManrpZdUa9Z0v60ffgidrn9/1ZycxOUrFbz/vmqDBu7q59tv\nE7tvMrGkH1CjBtx9Nzz3nOtVkJsLCxcmO1eZJdK4PTbEQ/VUVATjx7ueKG++CU2ahE574YWwYoXr\nvpnu9u+HP/8Zzj/fXfW88w4cfXSycxWCnzNDIl/xKOkHW7ZM9fjjVevUcQ0lJnHC9d4x1dPTT7ur\nsn/9K3LaL790aR9+OH77Ly6O3CiaSPv2ufbDVq20pPdNsmoWyMSG3FC2b1cdMMB92pdfjvvmTZLY\nSSWxDh1yDZPZ2e69HyedpHruufHZf1GR6tVXu44aixdHt42bb1YdOVJ1//7Y8rJvn+ojj6ged1xp\nsH/rreR2HrGgX86BA6r/9V+qnTqpHjxY+fVXrHD1dSZxrJ9/annpJXecn3rK/zq33uqusnftim3f\nBw6oXnqp23/t2qoXXVT5bXz+een/yqWXRteddN8+d+USCPZ9+riumanQU9CCfgX+9S/3iR97rHLr\n7diheuyxrgvWhg1Vk7dYrF6t+uGHyc5FfFk//9RSXKzas6frj1+ZQtO777rv5fnno9/3vn2qgwe7\n7Uydqno5qYUZAAAXEklEQVTnne798uWV287IkaoNG6pOnOjWv/76ygXr//xHNSvLrXvmmarvvJMa\nwT7Agn4FiotVe/dWPfpo1d27/a/3q1+p1qjhSixXXFFl2YvKvn2qJ5zgbpCJtTSVSmLt529VP/H1\n5pvu+P7lL5Vb78AB1SZNVK+6Krr97tlTWjUbuHFp2zbXQ+ayy/xvZ/Vq9xv+3/9107ff7rY5caK/\n9f/+d3eFceKJLtinIgv6IXz0kfvUv/ud//Qiri4w8I+Sn1+lWayU3/++NOA98kiycxM/kYJ6uJOC\nVf3EX79+7mr3p58qv+7Ike5Oeb/tAAE7drhCWo0aqk8+WXbZbbe5+WvX+tvWVVe5K/UtW9x0cbHq\nL3/p/jemTQu93sGD7rcPquec4+6cTVUW9MP4+c9dENi0KXy6AwfcLdRZWa4UvWOHaosWqn37psZl\n3Vdfudu8L7lEtVcv12ZR2R9Wqoqln38qVP0cPOhKh5W5okxVH37ojt8f/xjd+nl5bv2PPvK/zrZt\nqrm5rtF2zpzDl2/apFq3rgvckaxb5+4ruPnmsvOLilSHD3d5K39SUS3bAeTXv46uLTCRLOiHsXat\nu1SL9A9zzz3uCL34Yum8P//ZzXvhharNYyTFxaqDBrk6ysLC0h/Wa68lN1/x4qe0HqoKJxWGeHjq\nKbfPsWMTt8+qcuGFbhydaE9g27e7oOu3KmXzZtdLqG7d8L3txo51v+NI7Wxjxriq2fJDRai6K5dz\nznH5C/6dr1zpqnLq1FF9/HF/+U42C/oR3HKLuzz8/POKl3/1lbscHDas7PyDB10PoA4dYu/2FYsX\nX3Tf3v33u+n9+1WPOUb1/POTl6d4i7ZePhVK+qefXnqiqUwJN9UsXeo+x+TJsW3nzDNVu3aNnG7z\nZvfbatDA9YoJ5+uvKy7BB9uwwZ0Ywp18d+92V8p167oxc/79b9dGdvTRrvG2urCgH8G2baqNG6te\ncMHhy4qLVc87z33xFZUiXnnFHbmHHqr6fFbkxx9dAMvJcVVQAYH6/dWrk5OvVJHsOv1PPnH7vPtu\nd9NO165lv6fq5NJL3e8g1rrs++5zxyTc0Oe7dqn26OG+K78DtV15pSuchRrU7MYbXRVRQUH47Wzb\n5u4/OOIId6I+5RTVb77xl4dUYUHfh6lT3REoX6KYNUvD3klYXOzq+po1S07Dzh13uPyVH0L6229d\nqebGGxOfp1QT6SqhKnv3XHONC1w//OCqAQNdDaub1avd8bn99ti3tWqVlumBU97+/aXVLK++Wrnt\nirjfRHmbN7s2r1/8wt+2CgtdQWr0aFewqm4s6Puwb5/7wXfvXtoA+v33qkcdpXrqqeFv3li61P2z\njR+fkKyW+OILF9hDPaDi8stdyWznzsTmqzqpyiuB7793pcXg9qIhQ9z2v/469u0n0i9+4YJmPAYO\nKy52deQVVT8WF7tAC6pPPFH5bQ8f7p6lUX7wt0APnzVrospytRPXoA8MBFYDa4EJFSwfj3sy1jLg\nbaCtN78fpU/TWgr8BFwUbl+JDPqq7ocefJfhmDGutPHpp5HXveYaF4D9dhuLVeAKo3Hj0D/Ejz8O\nf5ViqrbOf9o0t63g/5/1610d9aBBqdHry4/16121yLhx8dvmLbe4evM9e8rOD3SF/sMfottuoDpt\nypTSeVu3umM+alT0+a1u4hb0cY88/Ao4HqgDfAZkl0vTD6jvvR8LPFPBdpoB3wfShXolOugfOuTq\n79q0Kb0B5dZb/a27aZP7x/rZz6o2jwFz5qiv/vinn+4aw9Kl+2a8VVXvnkOHXGn2v//78GWBk8Fz\nz8W2j0QJ1IXH8/Gjb72lh/WGe/hhLenlFMsJ8YILXHfqwAnljjvc97liRWx5rk7iGfRPB+YFTf8G\n+E2Y9N2B/1QwfwyQF2l/iQ76qq7FHlwppE2bw0si4Uye7Nat6nF5du1yjYLdu0ceMyTQJlGZutFQ\n3n3XdZ/LyXE3ygwa5EpPN9zguuDdd5/qvHmx7yeR/JT0o6nzf/11t528vMOXHTyo2q2bu8Fpx474\nfI5427vXdVV88UVXrXP11fHd/v79rhrm2mvd9LPPuuN70UWxP1bxP/9xx/6BB1wVW6NGrtonk8Qz\n6A8H/hY0fTnwpzDp/wRMqmD+O8CFIdYZA+QD+W3atKnqY1OhCy90R6Oyo3D++KMLxqeeGr5kHWup\n+7bb1PcNLgcOuAGhBg6MbZ+vv+5+/CecoHrxxe6hGD16uKGqmzVz9aWBgFmdHos3c6ardw9Vpx9t\nnf+QIa49KNRdqx9/7IJcPKtMonHwoAu4d93lhhU544zSAcQCr0aNqqYX2M9/7roWv/uuK2T17u1O\nNvHQt6/7HIGODkuXxme71UVSgj4wGlgI1C03/1hgK1A70v6SUdJXdV22XnklunWffNIdyYsvVh0x\nwgXb005z/fkDA7WJuJJHNJfL777rLrUDJSQ/7r7b5emLLyq/P1VX2qtTx5VOQ3WHC4xtftRRrudF\nddKvX2mAq1GjbPfbaOr8CwrcdirqRRLsxhvd/8LHH8fjU1Tep5+66sxAdVZWlutDf9VV7n8mL88V\nLKqqV9o//1l6Vd2xo7txK17eeKP0uxoyJH7brS4SXr0DDABWAUdVsOxmYIafDCUr6Mfi0CEX9Fq2\ndHXpp57qGlyHD3eB+rbbVG+6yQX/+vVdg5OfMUxWrXI3h4H7cVbm4RFbtrigHU2pctYs15jdq5e/\nH3+gD3Z1uZHl7bddfv/nf9yDPho2dKXdwG32fur8y1f/DB7sgn7gpB6qemjnTlca7dYtsbf179vn\nTkg1a7qT9OzZbl6ibd3qjtNxx0XuO19ZxcXutwfJO6kmUzyDfi1gHdA+qCE3p1ya7l5jb4cQ21gI\n9POToeoY9P0qKCgN4h06hB4yYcMG1zOoRg0XkH7/++hG0LzySrd+ZeqQ//53F6jOPNP/PvfscSe8\neD0sozIqWzWwZ48bHrhDh9J1Az24Jk1y09GM+wOuBB1qeXD10HPPuXnRjmVTWe+/7x5mAq5EH8/S\ndTRef93d8V4Vli5VffTRqtl2qot3l80LgC+9wD7RmzcZGOK9fwvYEtQ1c27Quu2AjUANP/tK56Af\n8PrrLuiAa8QK9N/evt2VPuvVc6X0m28OXbXiR36+28eDD/pL/8gjLv2551b+5pRAaT+R4/q/8orr\nMluZIQJuucXls/yNbVdf7U52b70V/Vj+Rx0VfnngpPHUU6VtCg0auMG84lWvHWznTjcsOKi2a1f9\nGtxN5cQ16CfylQlBX9VV7/zf/7lgUq+eK4E1buwCzxVXxO9Gnt69XUNspIbke+/VkrrQaIbPDZT2\nzzsvunxW1vffl7aXgKu6iNTl78MP3fGtaByWPXtcHfMxx7iqsXC9d0JV/0D45SKhrxLq1nVDHjz7\nbOV6j4Xy8suqrVuXDgueDqN9mvAs6FcT69eXDu86eLB7kHs8PfOMllQlvPyyGxZgzhzXYPePf7iH\nxY8b59JcemlsY8QEhrVIRGl/9GjXuJ2fXzou+vjxoQP/Tz+5hvXWrUPfrfzZZy74nnde+JNkpJJ8\nuOWhljVs6E6a4E5kF1/sTgCVrff/7DN3pQZuLJl0e6KaCc2CfjVTFZf3qi6It25dcaAJfl1zTex9\npffscTfIVHVpPzCeTeBBOMXFrlcMuOqMigL2pElueaShpx991KW7997QaSoqrR9xhL8un+GuAoqK\n3D0jN9zgrmLAfXf33hu5QX3jRjdsgohq06buZrBorthM9WVB35QoLHT96BctcresL1vmegatXeuu\nNAJPE4qHQDVRVQ0nHOgi2q1b2aGti4tde0hFJ7ClS91VgZ9HXRYXuyuvWrXCf4aZM0ufl9qwof8B\n3fx2Bz10yA3x279/6UnjV786vAvu7t3umbH167v2jfHjk99Qa5LDgr5Jit27XWk/1hvDQrn0Uhfc\nPvvs8GXFxaq//a37rx41ylWNHDzobig76ih3L4YfP/zgGj7btg1fwv7jH92+/IzTFBDNjV9Ll7qG\n5jp1XPpBg1yf9BkzXBsEuKenBXrE2POBM5MFfZM0gdL+woXh0xUXu3YGv/XOgbGHIg3MNWWKSzd8\neOkwGc8+628fAQsXutJ+3bruwd5HH+2G6DjxRDckRY8eruG9onF2Iol22Odvv3V30R55ZOkJo25d\nNy94XXs+cGbyG/TFpU0dubm5mp+fn+xsmBjs2QPt28Opp8Krr1acZvVquPFGePNNN33ttTB1KjRt\nWnH6776DnBxo1w4++ghq1Qqfh2nT4NZb3fuLL4bnn6/853j9dXjrLdi/Hw4ccH+DX0VFcMcd0Ldv\n5bcdSl4ejBkDe/eWzqtfH2bMgFGj3PJf/hL27at4ebt2sH794dtt2xYKCuKXT5N6RGSJquZGTOjn\nzJDIl5X000Pg+cKLFpWd/+OPrntl7dqupPzQQ64uPnCn6KxZh/fAKS52vVnq1KncqIl/+Yu7Q3Pz\n5tg/T6LE0jNINTWeD2ySA6veMcm0e7d7mHbgcZTFxa7XTZs27r/u8svLPhPg009Vc3PdsvPPL3uf\nwtNPa8QeNekiUtCOtDwVng9sksNv0K9R5dccJiM1bAi33eaqd555Bi68EIYNgyOPhPfeg3/+E44+\nujR9t26wcCE89BAsWOCqcu6/HzZsgBtugNNOK62uSWdt2oSfH2n5lCmuuidY/fpuvjGAlfRN1dm1\ny5X2A90a//hHfzd/rV/vblQL9H+vVy/60UKrm0gNsX4aamN5PrD1/Km+sOodkwpmz1a97jp3r0Bl\nFBe7gck6dHB185mkKh/qHu6kYT1/qje/Qd967xiTQcL17gHr+VOd+e29E6HjmzEmnXzzTeXmR1pm\nqh9ryDUmg4RrCI7USGzSgwV9YzJIuN491vMnM/gK+iIyUERWi8haEZlQwfLxIrJSRJaJyNsi0jZo\nWRsReUNEVnlp2sUv+8aYyhg1yt2927YtiLi/gbt5wy0LyMtz7QI1ari/eXnJ+iQmapFaeoGauCdm\nHU/p4xKzy6XpB9T33o8Fngla9i5wjve+YSBdqJf13jEmNVV1d1ETG+J4c1ZPYK2qrlPVA8BsYGi5\nE8d8VQ2MFrIQyAIQkWyglqq+6aXbE5TOGFONTJxYdkwgcNMTJ7r3gXGD1q93p4T169104Gog0nKT\nGH6CfitgQ9B0oTcvlGuA17z3/wXsEJF/icinInKfiNQsv4KIjBGRfBHJ37p1q9+8G2MSKFLPn0gn\nhUjLwaqPEiGuDbkiMhrIBe7zZtUC+gC3AafiqoiuKr+eqs5Q1VxVzW3ZsmU8s2SMiZNIvXsinRQi\nLbcrgcTwE/Q3Aq2DprO8eWWIyABgIjBEVfd7swuBpV7VUBHwItAjtiwbY5IhUu+eWMcN8lN9ZFcB\nsfMT9BcDHUSkvYjUAUYAc4MTiEh34DFcwP+u3LpNRCRQfO8PrIw928aYRIvUuyfSSSHS8nBXAnYV\nEEd+WnuBC4Avcb14JnrzJuOCPMBbwBZgqfeaG7TuOcAyYDnwJFAn3L6s944x1VcsvXfCDQttQ0ZH\nho29Y4ypTsI9Nezyy12YL08EiotL15840V0ZtGnjriCC7zFId37H3rE7co0xKSFc9VGk9gCr/vHP\ngr4xJmWMGuVG9Cwudn/9thdYd1D/LOgbY1JepEZk6w7qnwV9Y0y1EOoqAGLvDgqRrwTS5UrBgr4x\nptqLpTsoZNYQEhb0jTHVXqTqn1ivBPxcKYSTSlcJ1mXTGJP2wnUHHTXKBeNwXUIjLY9l3/FiXTaN\nMcYT65WAny6joUrysV4lxJsFfWNMRgjXEBzLEBKR6vv9PJc4odU/fm7bTeTLhmEwxiRDtENIRBoi\nItJyPw+n8QMbhsEYY6pepPr+SHX67dq5q4Py2rZ1VyR+WZ2+McYkQKT6/lhvLIs3C/rGGBODSO0B\nENuNZfFmQd8YY2IQqSQfiZ+TRjzVqprNGmNM5hg1Kvo+94H1EjUstAV9Y4xJslhOGpXlq3pHRAaK\nyGoRWSsiEypYPl5EVorIMhF5W0TaBi07JCJLvdfc8usaY4xJnIglfRGpCUzHPfawEFgsInNVNfhZ\nt58Cuaq6V0TGAlOBS71l+1S1W5zzbYwxJgp+Svo9gbWquk5VDwCzgaHBCVR1vqoGeqEuBLLim01j\njDHx4CfotwI2BE0XevNCuQZ4LWi6nojki8hCEbmoohVEZIyXJn/r1q0+smSMMSYacW3IFZHRQC7Q\nN2h2W1XdKCLHA++IyHJV/Sp4PVWdAcwAd0duPPNkjDGmlJ+gvxFoHTSd5c0rQ0QGABOBvqq6PzBf\nVTd6f9eJyLtAd+Cr8usHLFmyZJuIVHBTsm8tgG0xrF+VLG/RsbxFx/IWneqat7Yh5pcRcewdEakF\nfAmcjQv2i4HLVHVFUJruwHPAQFVdEzS/KbBXVfeLSAvgI2BouUbguBKRfD/jTySD5S06lrfoWN6i\nk+55i1jSV9UiERkHzANqAo+r6goRmYwb1W0ucB/QEHhWRAC+UdUhQCfgMREpxrUf3FOVAd8YY0x4\nvur0VfVV4NVy8+4Mej8gxHofAl1iyaAxxpj4Scexd2YkOwNhWN6iY3mLjuUtOmmdt5QbT98YY0zV\nSceSvjHGmBAs6BtjTAZJm6AfaVC4ZBKRAhFZ7g06l/RnQYrI4yLynYh8HjSvmYi8KSJrvL9NUyRf\nd4nIxqBB+y5IdL68fLQWkfnewIIrRORmb34qHLdQeUv6sROReiLysYh85uXt99789iKyyPu9PiMi\ndVIob0+KyNdBxy1pY4eJSE0R+VREXvamYz9ufh6km+ovXFfSr4DjgTrAZ0B2svMVlL8CoEWy8xGU\nnzOBHsDnQfOmAhO89xOAe1MkX3cBt6XAMTsW6OG9b4S7dyU7RY5bqLwl/dgBAjT03tcGFgGnAXOA\nEd78vwBjUyhvTwLDk/0/5+VrPPA08LI3HfNxS5eSfsRB4UwpVV0AfF9u9lDgH977fwAVjpNUlULk\nKyWo6mZV/cR7vxtYhRuDKhWOW6i8JZ06e7zJ2t5Lgf64GzohecctVN5SgohkAYOAv3nTQhyOW7oE\n/coOCpdoCrwhIktEZEyyMxPC0aq62Xv/LXB0MjNTzjjvWQ2PJ6P6pDwRaYcbTmQRKXbcyuUNUuDY\neVUUS4HvgDdxV+U7VLXIS5K032v5vKlq4LhN8Y7bAyJSNxl5Ax4E/hco9qabE4fjli5BP9Wdoao9\ngPOBG0TkzGRnKBx1146pUuJ5FDgB6AZsBv6YzMyISEPgeeAWVd0VvCzZx62CvKXEsVPVQ+qeqZGF\nuyrvmIx8VKR83kSkM/AbXB5PBZoBtyc6XyJyIfCdqi6J97bTJej7GhQuWbR00LnvgBdw//ipZouI\nHAvg/f0uyfkBQFW3eD/MYuCvJPHYiUhtXFDNU9V/ebNT4rhVlLdUOnZefnYA84HTgSbeuF6QAr/X\noLwN9KrLVN3AkU+QnOPWGxgiIgW46ur+wEPE4bilS9BfDHTwWrbrACOAlHg0o4g0EJFGgffAucDn\n4ddKirnAld77K4GXkpiXEoGA6hlGko6dV5/6d2CVqk4LWpT04xYqb6lw7ESkpYg08d4fgXsC3ypc\ngB3uJUvWcasob18EncQFV2ee8OOmqr9R1SxVbYeLZ++o6ijicdyS3Todx1buC3C9Fr4CJiY7P0H5\nOh7Xm+gzYEUq5A2YhbvcP4irF7wGV1/4NrAGeAtoliL5egpYDizDBdhjk3TMzsBV3SwDlnqvC1Lk\nuIXKW9KPHdAV9zjVZbjgeac3/3jgY2At8CxQN4Xy9o533D4HZuL18EnWCziL0t47MR83G4bBGGMy\nSLpU7xhjjPHBgr4xxmQQC/rGGJNBLOgbY0wGsaBvjDEZxIK+McZkEAv6xhiTQf4/IzaWGVAhoW4A\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": [
|
|
""
|
|
]
|
|
},
|
|
{
|
|
"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
|
|
}
|