{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Exercise 4.2 - Solution\n", "## Linear regression\n", "In this task we will design and train a linear model using [Keras](https://keras.io/).\n", "\n", "### Tasks\n", "1. Complete the implemetation of the `LinearLayer`\n", "2. Define a meaningful objective\n", "3. Implement gradient descent and train the linear model for 80 epochs." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import tensorflow as tf\n", "from tensorflow import keras\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "layers = keras.layers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simulation of data\n", "Let's first simulate some noisy data" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x.shape: (100, 1)\n", "y.shape: (100,)\n" ] } ], "source": [ "np.random.seed(1904)\n", "x = np.float32(np.linspace(-1, 1, 100)[:,np.newaxis])\n", "y = np.float32(2 * x[:,0] + 0.3 * np.random.randn(100))\n", "print(\"x.shape:\", x.shape)\n", "print(\"y.shape:\", y.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Implement linear model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we have to design a linear layer that maps from the input $x$ to the output $y$ using a single adaptive weight $w$:\n", " \n", "$$y = w \\cdot x$$\n", "\n", "### Task 1\n", "Complete the implementation of the `LinearLayer` by adding the linear transformation in the `call` function." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "class LinearLayer(layers.Layer):\n", "\n", " def __init__(self, units=1, input_dim=1): # when intializing the layer the weights have to be initialized\n", " super(LinearLayer, self).__init__()\n", " w_init = tf.random_normal_initializer()\n", " self.w = tf.Variable(initial_value=w_init(shape=(input_dim, units), dtype=\"float32\"),\n", " trainable=True)\n", "\n", " def call(self, inputs): # when calling the layer the linear transformation has to be performed\n", " return tf.matmul(inputs, self.w)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Build a model using the implemented layer." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "model = keras.models.Sequential()\n", "model.add(LinearLayer(units=1, input_dim=1))" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential\"\n", "_________________________________________________________________\n", "Layer (type) Output Shape Param # \n", "=================================================================\n", "linear_layer (LinearLayer) (None, 1) 1 \n", "=================================================================\n", "Total params: 1\n", "Trainable params: 1\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "None\n" ] } ], "source": [ "model.build((None, 1))\n", "print(model.summary())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Performance before the training\n", "Plot data and model before the training" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "y_pred = model(x)\n", "\n", "fig, ax = plt.subplots(1)\n", "ax.plot(x, y, 'bo', label='data')\n", "ax.plot(x, y_pred, 'r-', label='model')\n", "ax.set(xlabel='$x$', ylabel='$y$')\n", "ax.grid()\n", "ax.legend(loc='lower right')\n", "plt.tight_layout()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Task 2: Define the objective function\n", "Define a meaningful objective here (regression task). \n", "Note that you can use `tf.reduce_mean()` to average your loss estimate over the full data set (100 points)." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def loss(x, y):\n", " return tf.reduce_mean((tf.squeeze(x)-tf.squeeze(y))**2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Task 3 - Train the model using gradient descent\n", "'Train' the linear model for 80 epochs (or iterations) with a meaningful learning rate and implement gradient descent. \n", "Hint: you can access the adaptive parameters using `model.trainable_weights` and perform $w' \\rightarrow w-z$ using `w.assign_sub(z)`" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Current loss at epoch 0: 1.5236\n", "Current loss at epoch 1: 1.3338\n", "Current loss at epoch 2: 1.1689\n", "Current loss at epoch 3: 1.0257\n", "Current loss at epoch 4: 0.9014\n", "Current loss at epoch 5: 0.7933\n", "Current loss at epoch 6: 0.6995\n", "Current loss at epoch 7: 0.6180\n", "Current loss at epoch 8: 0.5472\n", "Current loss at epoch 9: 0.4857\n", "Current loss at epoch 10: 0.4323\n", "Current loss at epoch 11: 0.3859\n", "Current loss at epoch 12: 0.3456\n", "Current loss at epoch 13: 0.3106\n", "Current loss at epoch 14: 0.2802\n", "Current loss at epoch 15: 0.2538\n", "Current loss at epoch 16: 0.2308\n", "Current loss at epoch 17: 0.2109\n", "Current loss at epoch 18: 0.1936\n", "Current loss at epoch 19: 0.1786\n", "Current loss at epoch 20: 0.1655\n", "Current loss at epoch 21: 0.1542\n", "Current loss at epoch 22: 0.1443\n", "Current loss at epoch 23: 0.1357\n", "Current loss at epoch 24: 0.1283\n", "Current loss at epoch 25: 0.1219\n", "Current loss at epoch 26: 0.1163\n", "Current loss at epoch 27: 0.1114\n", "Current loss at epoch 28: 0.1072\n", "Current loss at epoch 29: 0.1035\n", "Current loss at epoch 30: 0.1003\n", "Current loss at epoch 31: 0.0975\n", "Current loss at epoch 32: 0.0951\n", "Current loss at epoch 33: 0.0930\n", "Current loss at epoch 34: 0.0912\n", "Current loss at epoch 35: 0.0896\n", "Current loss at epoch 36: 0.0882\n", "Current loss at epoch 37: 0.0871\n", "Current loss at epoch 38: 0.0860\n", "Current loss at epoch 39: 0.0851\n", "Current loss at epoch 40: 0.0843\n", "Current loss at epoch 41: 0.0837\n", "Current loss at epoch 42: 0.0831\n", "Current loss at epoch 43: 0.0826\n", "Current loss at epoch 44: 0.0821\n", "Current loss at epoch 45: 0.0817\n", "Current loss at epoch 46: 0.0814\n", "Current loss at epoch 47: 0.0811\n", "Current loss at epoch 48: 0.0809\n", "Current loss at epoch 49: 0.0806\n", "Current loss at epoch 50: 0.0804\n", "Current loss at epoch 51: 0.0803\n", "Current loss at epoch 52: 0.0801\n", "Current loss at epoch 53: 0.0800\n", "Current loss at epoch 54: 0.0799\n", "Current loss at epoch 55: 0.0798\n", "Current loss at epoch 56: 0.0797\n", "Current loss at epoch 57: 0.0797\n", "Current loss at epoch 58: 0.0796\n", "Current loss at epoch 59: 0.0795\n", "Current loss at epoch 60: 0.0795\n", "Current loss at epoch 61: 0.0795\n", "Current loss at epoch 62: 0.0794\n", "Current loss at epoch 63: 0.0794\n", "Current loss at epoch 64: 0.0794\n", "Current loss at epoch 65: 0.0793\n", "Current loss at epoch 66: 0.0793\n", "Current loss at epoch 67: 0.0793\n", "Current loss at epoch 68: 0.0793\n", "Current loss at epoch 69: 0.0793\n", "Current loss at epoch 70: 0.0793\n", "Current loss at epoch 71: 0.0792\n", "Current loss at epoch 72: 0.0792\n", "Current loss at epoch 73: 0.0792\n", "Current loss at epoch 74: 0.0792\n", "Current loss at epoch 75: 0.0792\n", "Current loss at epoch 76: 0.0792\n", "Current loss at epoch 77: 0.0792\n", "Current loss at epoch 78: 0.0792\n", "Current loss at epoch 79: 0.0792\n" ] } ], "source": [ "epochs = 80 # number of epochs\n", "lr = 0.1 # learning rate\n", "\n", "for epoch in range(epochs):\n", "\n", " with tf.GradientTape() as tape:\n", " output = model(x, training=True)\n", " # Compute loss value\n", " loss_value = loss(tf.convert_to_tensor(y), output)\n", " grads = tape.gradient(loss_value, model.trainable_weights)\n", " \n", " for weight, grad in zip(model.trainable_weights, grads):\n", " weight.assign_sub(lr * grad)\n", "\n", " print(\"Current loss at epoch %d: %.4f\" % (epoch, float(loss_value)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Performance of the fitted model\n", "Plot data and model after the training" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(1)\n", "\n", "y_pred = model(x)\n", "\n", "ax.plot(x, y, 'bo', label='data')\n", "ax.plot(x, y_pred, 'r-', label='model')\n", "ax.set(xlabel='$x$', ylabel='$y$')\n", "ax.grid()\n", "ax.legend(loc='lower right')\n", "plt.tight_layout()" ] } ], "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.6.9" } }, "nbformat": 4, "nbformat_minor": 4 }