{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "name": "S+P Week 3 Exercise Answer.ipynb",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "metadata": {
        "id": "zX4Kg8DUTKWO"
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "D1J15Vh_1Jih"
      },
      "source": [
        "!pip install tf-nightly-2.0-preview\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BOjujz601HcS"
      },
      "source": [
        "import tensorflow as tf\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "print(tf.__version__)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Zswl7jRtGzkk"
      },
      "source": [
        "def plot_series(time, series, format=\"-\", start=0, end=None):\n",
        "    plt.plot(time[start:end], series[start:end], format)\n",
        "    plt.xlabel(\"Time\")\n",
        "    plt.ylabel(\"Value\")\n",
        "    plt.grid(False)\n",
        "\n",
        "def trend(time, slope=0):\n",
        "    return slope * time\n",
        "\n",
        "def seasonal_pattern(season_time):\n",
        "    \"\"\"Just an arbitrary pattern, you can change it if you wish\"\"\"\n",
        "    return np.where(season_time < 0.1,\n",
        "                    np.cos(season_time * 6 * np.pi),\n",
        "                    2 / np.exp(9 * season_time))\n",
        "\n",
        "def seasonality(time, period, amplitude=1, phase=0):\n",
        "    \"\"\"Repeats the same pattern at each period\"\"\"\n",
        "    season_time = ((time + phase) % period) / period\n",
        "    return amplitude * seasonal_pattern(season_time)\n",
        "\n",
        "def noise(time, noise_level=1, seed=None):\n",
        "    rnd = np.random.RandomState(seed)\n",
        "    return rnd.randn(len(time)) * noise_level\n",
        "\n",
        "time = np.arange(10 * 365 + 1, dtype=\"float32\")\n",
        "baseline = 10\n",
        "series = trend(time, 0.1)  \n",
        "baseline = 10\n",
        "amplitude = 40\n",
        "slope = 0.005\n",
        "noise_level = 3\n",
        "\n",
        "# Create the series\n",
        "series = baseline + trend(time, slope) + seasonality(time, period=365, amplitude=amplitude)\n",
        "# Update with noise\n",
        "series += noise(time, noise_level, seed=51)\n",
        "\n",
        "split_time = 3000\n",
        "time_train = time[:split_time]\n",
        "x_train = series[:split_time]\n",
        "time_valid = time[split_time:]\n",
        "x_valid = series[split_time:]\n",
        "\n",
        "window_size = 20\n",
        "batch_size = 32\n",
        "shuffle_buffer_size = 1000\n",
        "\n",
        "plot_series(time, series)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "4sTTIOCbyShY"
      },
      "source": [
        "def windowed_dataset(series, window_size, batch_size, shuffle_buffer):\n",
        "  dataset = tf.data.Dataset.from_tensor_slices(series)\n",
        "  dataset = dataset.window(window_size + 1, shift=1, drop_remainder=True)\n",
        "  dataset = dataset.flat_map(lambda window: window.batch(window_size + 1))\n",
        "  dataset = dataset.shuffle(shuffle_buffer).map(lambda window: (window[:-1], window[-1]))\n",
        "  dataset = dataset.batch(batch_size).prefetch(1)\n",
        "  return dataset"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "A1Hl39rklkLm"
      },
      "source": [
        "tf.keras.backend.clear_session()\n",
        "tf.random.set_seed(51)\n",
        "np.random.seed(51)\n",
        "\n",
        "tf.keras.backend.clear_session()\n",
        "dataset = windowed_dataset(x_train, window_size, batch_size, shuffle_buffer_size)\n",
        "\n",
        "model = tf.keras.models.Sequential([\n",
        "  tf.keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=-1),\n",
        "                      input_shape=[None]),\n",
        "  tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32, return_sequences=True)),\n",
        "  tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),\n",
        "  tf.keras.layers.Dense(1),\n",
        "  tf.keras.layers.Lambda(lambda x: x * 10.0)\n",
        "])\n",
        "\n",
        "lr_schedule = tf.keras.callbacks.LearningRateScheduler(\n",
        "    lambda epoch: 1e-8 * 10**(epoch / 20))\n",
        "optimizer = tf.keras.optimizers.SGD(lr=1e-8, momentum=0.9)\n",
        "model.compile(loss=tf.keras.losses.Huber(),\n",
        "              optimizer=optimizer,\n",
        "              metrics=[\"mae\"])\n",
        "history = model.fit(dataset, epochs=100, callbacks=[lr_schedule])"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "AkBsrsXMzoWR"
      },
      "source": [
        "plt.semilogx(history.history[\"lr\"], history.history[\"loss\"])\n",
        "plt.axis([1e-8, 1e-4, 0, 30])"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "4uh-97bpLZCA"
      },
      "source": [
        "tf.keras.backend.clear_session()\n",
        "tf.random.set_seed(51)\n",
        "np.random.seed(51)\n",
        "\n",
        "tf.keras.backend.clear_session()\n",
        "dataset = windowed_dataset(x_train, window_size, batch_size, shuffle_buffer_size)\n",
        "\n",
        "model = tf.keras.models.Sequential([\n",
        "  tf.keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=-1),\n",
        "                      input_shape=[None]),\n",
        "   tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32, return_sequences=True)),\n",
        "  tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),\n",
        "  tf.keras.layers.Dense(1),\n",
        "  tf.keras.layers.Lambda(lambda x: x * 100.0)\n",
        "])\n",
        "\n",
        "\n",
        "model.compile(loss=\"mse\", optimizer=tf.keras.optimizers.SGD(lr=1e-5, momentum=0.9),metrics=[\"mae\"])\n",
        "history = model.fit(dataset,epochs=500,verbose=1)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "icGDaND7z0ne"
      },
      "source": [
        "forecast = []\n",
        "results = []\n",
        "for time in range(len(series) - window_size):\n",
        "  forecast.append(model.predict(series[time:time + window_size][np.newaxis]))\n",
        "\n",
        "forecast = forecast[split_time-window_size:]\n",
        "results = np.array(forecast)[:, 0, 0]\n",
        "\n",
        "\n",
        "plt.figure(figsize=(10, 6))\n",
        "\n",
        "plot_series(time_valid, x_valid)\n",
        "plot_series(time_valid, results)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "KfPeqI7rz4LD"
      },
      "source": [
        "tf.keras.metrics.mean_absolute_error(x_valid, results).numpy()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "JUsdZB_tzDLe"
      },
      "source": [
        "import matplotlib.image  as mpimg\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "#-----------------------------------------------------------\n",
        "# Retrieve a list of list results on training and test data\n",
        "# sets for each training epoch\n",
        "#-----------------------------------------------------------\n",
        "mae=history.history['mae']\n",
        "loss=history.history['loss']\n",
        "\n",
        "epochs=range(len(loss)) # Get number of epochs\n",
        "\n",
        "#------------------------------------------------\n",
        "# Plot MAE and Loss\n",
        "#------------------------------------------------\n",
        "plt.plot(epochs, mae, 'r')\n",
        "plt.plot(epochs, loss, 'b')\n",
        "plt.title('MAE and Loss')\n",
        "plt.xlabel(\"Epochs\")\n",
        "plt.ylabel(\"Accuracy\")\n",
        "plt.legend([\"MAE\", \"Loss\"])\n",
        "\n",
        "plt.figure()\n",
        "\n",
        "epochs_zoom = epochs[200:]\n",
        "mae_zoom = mae[200:]\n",
        "loss_zoom = loss[200:]\n",
        "\n",
        "#------------------------------------------------\n",
        "# Plot Zoomed MAE and Loss\n",
        "#------------------------------------------------\n",
        "plt.plot(epochs_zoom, mae_zoom, 'r')\n",
        "plt.plot(epochs_zoom, loss_zoom, 'b')\n",
        "plt.title('MAE and Loss')\n",
        "plt.xlabel(\"Epochs\")\n",
        "plt.ylabel(\"Accuracy\")\n",
        "plt.legend([\"MAE\", \"Loss\"])\n",
        "\n",
        "plt.figure()"
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}