{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "spread-happiness", "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "%load_ext autoreload\n", "%autoreload 2\n", "\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "import matplotlib.ticker as ticker\n", "from IPython.display import Markdown, display, HTML\n", "\n", "import torch\n", "import torch.nn as nn\n", "import torch.optim as optim\n", "\n", "# Fix the dying kernel problem (only a problem in some installations - you can remove it, if it works without it)\n", "import os\n", "os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'" ] }, { "cell_type": "markdown", "id": "approximate-classic", "metadata": {}, "source": [ "# PyTorch\n", "\n", "Here's your best friend when working with PyTorch: https://pytorch.org/docs/stable/index.html.\n", "\n", "The beginning of this notebook shows that PyTorch tensors can be used exactly like numpy arrays. Later in the notebook additional features of tensors will be presented." ] }, { "cell_type": "markdown", "id": "renewable-chase", "metadata": {}, "source": [ "## Creating PyTorch tensors" ] }, { "cell_type": "markdown", "id": "afraid-consortium", "metadata": {}, "source": [ "### Directly" ] }, { "cell_type": "code", "execution_count": 2, "id": "textile-mainland", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1. 2. 3.]\n", " [4. 5. 6.]\n", " [7. 8. 9.]]\n", "\n", "tensor([[1., 2., 3.],\n", " [4., 5., 6.],\n", " [7., 8., 9.]])\n" ] } ], "source": [ "a = np.array(\n", " [[1.0, 2.0, 3.0], \n", " [4.0, 5.0, 6.0], \n", " [7.0, 8.0, 9.0]]\n", ")\n", "\n", "print(a)\n", "print()\n", "\n", "t = torch.tensor(\n", " [[1.0, 2.0, 3.0], \n", " [4.0, 5.0, 6.0], \n", " [7.0, 8.0, 9.0]]\n", ")\n", "\n", "print(t)" ] }, { "cell_type": "markdown", "id": "floating-junior", "metadata": {}, "source": [ "### From a list" ] }, { "cell_type": "code", "execution_count": 3, "id": "reasonable-mistress", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]\n", "\n", "[[1. 2. 3.]\n", " [4. 5. 6.]\n", " [7. 8. 9.]]\n", "\n", "tensor([[1., 2., 3.],\n", " [4., 5., 6.],\n", " [7., 8., 9.]])\n" ] } ], "source": [ "l = [[1.0, 2.0, 3.0], \n", " [4.0, 5.0, 6.0], \n", " [7.0, 8.0, 9.0]]\n", "\n", "print(l)\n", "print()\n", "\n", "a = np.array(l)\n", "print(a)\n", "print()\n", "\n", "t = torch.tensor(l)\n", "print(t)" ] }, { "cell_type": "markdown", "id": "incorrect-practitioner", "metadata": {}, "source": [ "### From a list comprehension" ] }, { "cell_type": "code", "execution_count": 4, "id": "straight-cooling", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n", "\n", "[ 0 1 4 9 16 25 36 49 64 81]\n", "\n", "tensor([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])\n" ] } ], "source": [ "a = [i**2 for i in range(10)]\n", "\n", "print(a)\n", "print()\n", "print(np.array(a))\n", "print()\n", "print(torch.tensor(a))" ] }, { "cell_type": "markdown", "id": "enormous-drink", "metadata": {}, "source": [ "### From a numpy array" ] }, { "cell_type": "code", "execution_count": 5, "id": "parental-judges", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([[1., 2., 3.],\n", " [4., 5., 6.],\n", " [7., 8., 9.]], dtype=torch.float64)\n" ] } ], "source": [ "a = np.array(\n", " [[1.0, 2.0, 3.0], \n", " [4.0, 5.0, 6.0], \n", " [7.0, 8.0, 9.0]]\n", ")\n", "\n", "t = torch.tensor(a)\n", "\n", "print(t)" ] }, { "cell_type": "markdown", "id": "suffering-myanmar", "metadata": {}, "source": [ "### Ready-made functions in PyTorch" ] }, { "cell_type": "code", "execution_count": 6, "id": "expensive-bowling", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "All zeros\n", "tensor([[0., 0., 0., 0.],\n", " [0., 0., 0., 0.],\n", " [0., 0., 0., 0.]])\n", "\n", "All chosen value (variant 1)\n", "tensor([[7., 7., 7., 7.],\n", " [7., 7., 7., 7.],\n", " [7., 7., 7., 7.]])\n", "\n", "All chosen value (variant 2)\n", "tensor([[7., 7., 7., 7.],\n", " [7., 7., 7., 7.],\n", " [7., 7., 7., 7.]])\n", "\n", "Random integers\n", "[[6 6]\n", " [8 9]\n", " [1 0]]\n", "\n", "tensor([[9, 5],\n", " [9, 3],\n", " [3, 8]])\n", "\n", "Random values from the normal distribution\n", "[[ -5.34346728 0.97207777]\n", " [ -7.26648922 -12.2890286 ]\n", " [ -2.68082928 10.95819034]]\n", "\n", "tensor([[ 1.1231, -5.9980],\n", " [20.4600, -6.4359],\n", " [-6.6826, -0.4491]])\n" ] } ], "source": [ "# All zeros\n", "a = torch.zeros((3, 4))\n", "print(\"All zeros\")\n", "print(a)\n", "print()\n", "\n", "# All a chosen value\n", "a = torch.full((3, 4), 7.0)\n", "print(\"All chosen value (variant 1)\")\n", "print(a)\n", "print()\n", "\n", "# or\n", "\n", "a = torch.zeros((3, 4))\n", "a[:] = 7.0\n", "print(\"All chosen value (variant 2)\")\n", "print(a)\n", "print()\n", "\n", "# Random integers\n", "\n", "print(\"Random integers\")\n", "a = np.random.randint(low=0, high=10, size=(3, 2))\n", "print(a)\n", "print()\n", "a = torch.randint(low=0, high=10, size=(3, 2))\n", "print(a)\n", "print()\n", "\n", "# Random values from the normal distribution (Gaussian)\n", "\n", "print(\"Random values from the normal distribution\")\n", "a = np.random.normal(loc=0, scale=10, size=(3, 2))\n", "print(a)\n", "print()\n", "a = torch.normal(mean=0, std=10, size=(3, 2))\n", "print(a)" ] }, { "cell_type": "markdown", "id": "aggressive-titanium", "metadata": {}, "source": [ "## Slicing PyTorch tensors" ] }, { "cell_type": "markdown", "id": "former-richardson", "metadata": {}, "source": [ "### Slicing in 1D\n", "\n", "To obtain only specific values from a PyTorch tensor one can use so called slicing. It has the form\n", "\n", "**arr[low:high:step]**\n", "\n", "where low is the lowest index to be retrieved, high is the lowest index not to be retrieved and step indicates that every step element will be taken." ] }, { "cell_type": "code", "execution_count": 7, "id": "desirable-documentary", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original: tensor([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])\n", "First 5 elements: tensor([ 0, 1, 4, 9, 16])\n", "Elements from index 3 to index 5: tensor([ 9, 16, 25])\n", "Last 3 elements (negative indexing): tensor([49, 64, 81])\n", "Every second element: tensor([ 0, 4, 16, 36, 64])\n", "Negative step a[::-1] to obtain reverse order does not work for tensors\n" ] } ], "source": [ "a = torch.tensor([i**2 for i in range(10)])\n", "\n", "print(\"Original: \", a)\n", "print(\"First 5 elements:\", a[:5])\n", "print(\"Elements from index 3 to index 5:\", a[3:6])\n", "print(\"Last 3 elements (negative indexing):\", a[-3:])\n", "print(\"Every second element:\", a[::2])\n", "\n", "print(\"Negative step a[::-1] to obtain reverse order does not work for tensors\")" ] }, { "cell_type": "markdown", "id": "micro-explosion", "metadata": {}, "source": [ "### Slicing in 2D\n", "\n", "In two dimensions it works similarly, just the slicing is separate for every dimension." ] }, { "cell_type": "code", "execution_count": 8, "id": "disciplinary-think", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original: \n", "tensor([[ 0, 1, 2, 3, 4],\n", " [ 5, 6, 7, 8, 9],\n", " [10, 11, 12, 13, 14],\n", " [15, 16, 17, 18, 19],\n", " [20, 21, 22, 23, 24]])\n", "\n", "First 2 elements of the first 3 row:\n", "tensor([[ 0, 1],\n", " [ 5, 6],\n", " [10, 11]])\n", "\n", "Middle 3 elements from the middle 3 rows:\n", "tensor([[ 6, 7, 8],\n", " [11, 12, 13],\n", " [16, 17, 18]])\n", "\n", "Bottom-right 3 by 3 submatrix (negative indexing):\n", "tensor([[12, 13, 14],\n", " [17, 18, 19],\n", " [22, 23, 24]])\n" ] } ], "source": [ "a = torch.tensor([i for i in range(25)]).reshape(5, 5)\n", "\n", "print(\"Original: \")\n", "print(a)\n", "print()\n", "print(\"First 2 elements of the first 3 row:\")\n", "print(a[:3, :2])\n", "print()\n", "print(\"Middle 3 elements from the middle 3 rows:\")\n", "print(a[1:4, 1:4])\n", "print()\n", "print(\"Bottom-right 3 by 3 submatrix (negative indexing):\")\n", "print(a[-3:, -3:])" ] }, { "cell_type": "markdown", "id": "removable-canyon", "metadata": {}, "source": [ "### Setting PyTorch tensor field values" ] }, { "cell_type": "code", "execution_count": 9, "id": "senior-serbia", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original: \n", "tensor([[ 0, 1, 2, 3, 4],\n", " [ 5, 6, 7, 8, 9],\n", " [10, 11, 12, 13, 14],\n", " [15, 16, 17, 18, 19],\n", " [20, 21, 22, 23, 24]])\n", "\n", "Middle values changed to 5\n", "tensor([[ 0, 1, 2, 3, 4],\n", " [ 5, 5, 5, 5, 9],\n", " [10, 5, 5, 5, 14],\n", " [15, 5, 5, 5, 19],\n", " [20, 21, 22, 23, 24]])\n", "\n", "Second matrix\n", "tensor([[ 0, 0, 2],\n", " [ 6, 12, 20],\n", " [30, 42, 56]])\n", "\n", "Second matrix substituted into the middle of the first matrix\n", "tensor([[ 0, 1, 2, 3, 4],\n", " [ 5, 0, 0, 2, 9],\n", " [10, 6, 12, 20, 14],\n", " [15, 30, 42, 56, 19],\n", " [20, 21, 22, 23, 24]])\n" ] } ], "source": [ "a = torch.tensor([i for i in range(25)]).reshape(5, 5)\n", "\n", "print(\"Original: \")\n", "print(a)\n", "print()\n", "\n", "a[1:4, 1:4] = 5.0\n", "\n", "print(\"Middle values changed to 5\")\n", "print(a)\n", "print()\n", "\n", "b = torch.tensor([i**2 - i for i in range(9)]).reshape(3, 3)\n", "\n", "print(\"Second matrix\")\n", "print(b)\n", "print()\n", "\n", "a[1:4, 1:4] = b\n", "\n", "print(\"Second matrix substituted into the middle of the first matrix\")\n", "print(a)" ] }, { "cell_type": "markdown", "id": "federal-wayne", "metadata": {}, "source": [ "## Operations on PyTorch tensors\n", "\n", "It is important to remember that arithmetic operations on PyTorch tensors are always element-wise." ] }, { "cell_type": "code", "execution_count": 10, "id": "southwest-biotechnology", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([[ 0, 1, 4],\n", " [ 9, 16, 25],\n", " [36, 49, 64]])\n", "\n", "tensor([[0.0000, 1.0000, 1.4142],\n", " [1.7321, 2.0000, 2.2361],\n", " [2.4495, 2.6458, 2.8284]])\n", "\n" ] } ], "source": [ "a = torch.tensor([i**2 for i in range(9)]).reshape((3, 3))\n", "print(a)\n", "print()\n", "\n", "b = torch.tensor([i**0.5 for i in range(9)]).reshape((3, 3))\n", "print(b)\n", "print()" ] }, { "cell_type": "markdown", "id": "intensive-gates", "metadata": {}, "source": [ "### Element-wise sum" ] }, { "cell_type": "code", "execution_count": 11, "id": "behavioral-safety", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([[ 0.0000, 2.0000, 5.4142],\n", " [10.7321, 18.0000, 27.2361],\n", " [38.4495, 51.6458, 66.8284]])\n" ] } ], "source": [ "print(a + b)" ] }, { "cell_type": "markdown", "id": "occupied-trial", "metadata": {}, "source": [ "### Element-wise multiplication" ] }, { "cell_type": "code", "execution_count": 12, "id": "charming-pleasure", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([[ 0.0000, 1.0000, 5.6569],\n", " [ 15.5885, 32.0000, 55.9017],\n", " [ 88.1816, 129.6418, 181.0193]])\n" ] } ], "source": [ "print(a * b)" ] }, { "cell_type": "markdown", "id": "efficient-league", "metadata": {}, "source": [ "### Matrix multiplication" ] }, { "cell_type": "code", "execution_count": 13, "id": "changing-community", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([[ 11.5300, 12.5830, 13.5498],\n", " [ 88.9501, 107.1438, 119.2157],\n", " [241.6378, 303.3281, 341.4984]], dtype=torch.float64)\n", "\n", "tensor([[ 0., 1., 4.],\n", " [ 9., 16., 25.],\n", " [36., 49., 64.]])\n" ] } ], "source": [ "print(np.matmul(a, b))\n", "print()\n", "\n", "# Multiplication by the identity matrix (to check it works as expected)\n", "id_matrix = torch.tensor(\n", " [[1.0, 0.0, 0.0], \n", " [0.0, 1.0, 0.0], \n", " [0.0, 0.0, 1.0]]\n", ")\n", "\n", "# Tensor a contained integers (type Long by default) and must be changed to the float type\n", "a = a.type(torch.FloatTensor)\n", "\n", "print(torch.matmul(id_matrix, a))" ] }, { "cell_type": "markdown", "id": "assisted-communications", "metadata": {}, "source": [ "### Calculating the mean" ] }, { "cell_type": "code", "execution_count": 14, "id": "defensive-wrong", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([3, 8, 7, 2, 6])\n", "\n", "Mean: tensor(5.2000)\n", "\n", "Mean: 5.199999809265137\n" ] } ], "source": [ "a = torch.randint(low=0, high=10, size=(5,))\n", "\n", "print(a)\n", "print()\n", "\n", "print(\"Mean: \", torch.sum(a) / len(a))\n", "print()\n", "\n", "# To get a single value use tensor.item()\n", "\n", "print(\"Mean: \", (torch.sum(a) / len(a)).item())" ] }, { "cell_type": "markdown", "id": "complex-karma", "metadata": {}, "source": [ "### Calculating the mean of every row" ] }, { "cell_type": "code", "execution_count": 15, "id": "correct-dietary", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([[1, 6, 8],\n", " [6, 4, 8],\n", " [1, 5, 8],\n", " [2, 5, 7],\n", " [1, 0, 4]])\n", "\n", "Mean: tensor([5.0000, 6.0000, 4.6667, 4.6667, 1.6667])\n", "Mean in the original matrix form:\n", "tensor([[5.0000],\n", " [6.0000],\n", " [4.6667],\n", " [4.6667],\n", " [1.6667]])\n" ] } ], "source": [ "a = torch.randint(low=0, high=10, size=(5, 3))\n", "\n", "print(a)\n", "print()\n", "\n", "print(\"Mean:\", torch.sum(a, axis=1) / a.shape[1])\n", "\n", "print(\"Mean in the original matrix form:\")\n", "print((torch.sum(a, axis=1) / a.shape[1]).reshape(-1, 1)) # -1 calculates the right size to use all elements" ] }, { "cell_type": "markdown", "id": "indian-orlando", "metadata": {}, "source": [ "### More complex operations\n", "\n", "Note that more complex tensor operations can only be performed on tensors. Numpy operations can be performed on numpy arrays but also directly on lists." ] }, { "cell_type": "code", "execution_count": 16, "id": "presidential-cologne", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector to power 2 (element-wise)\n", "tensor([1., 4., 9.])\n", "\n", "Euler number to the power a (element-wise)\n", "tensor([ 2.7183, 7.3891, 20.0855])\n", "\n", "An even more complex expression\n", "tensor([0.6197, 1.8982, 4.8476])\n" ] } ], "source": [ "a = torch.tensor([1.0, 2.0, 3.0])\n", "\n", "print(\"Vector to power 2 (element-wise)\")\n", "print(torch.pow(a, 2))\n", "print()\n", "print(\"Euler number to the power a (element-wise)\")\n", "print(torch.exp(a))\n", "print()\n", "print(\"An even more complex expression\")\n", "print((torch.pow(a, 2) + torch.exp(a)) / torch.sum(a))" ] }, { "cell_type": "markdown", "id": "hearing-street", "metadata": {}, "source": [ "## PyTorch basic operations tasks" ] }, { "cell_type": "markdown", "id": "regular-niger", "metadata": {}, "source": [ "**Task 1.** Calculate the sigmoid (logistic) function on every element of the following array [0.3, 1.2, -1.4, 0.2, -0.1, 0.1, 0.8, -0.25] and print the last 5 elements. Use only tensor operations." ] }, { "cell_type": "code", "execution_count": 17, "id": "agreed-single", "metadata": {}, "outputs": [], "source": [ "# Write your code here" ] }, { "cell_type": "markdown", "id": "another-catch", "metadata": {}, "source": [ "**Task 2.** Calculate the dot product of the following two vectors:
\n", "$x = [3, 1, 4, 2, 6, 1, 4, 8]$
\n", "$y = [5, 2, 3, 12, 2, 4, 17, 9]$
\n", "a) by using element-wise mutliplication and torch.sum,
\n", "b) by using torch.dot,
\n", "b) by using torch.matmul and transposition (x.T)." ] }, { "cell_type": "code", "execution_count": 18, "id": "forbidden-journalism", "metadata": {}, "outputs": [], "source": [ "# Write your code here" ] }, { "cell_type": "markdown", "id": "acute-amber", "metadata": {}, "source": [ "**Task 3.** Calculate the following expression
\n", "$$\\frac{1}{1 + e^{-x_0 \\theta_0 - \\ldots - x_9 \\theta_9 - \\theta_{10}}}$$\n", "for
\n", "$x = [1.2, 2.3, 3.4, -0.7, 4.2, 2.7, -0.5, 1.4, -3.3, 0.2]$
\n", "$\\theta = [1.7, 0.33, -2.12, -1.73, 2.9, -5.8, -0.9, 12.11, 3.43, -0.5, -1.65]$
\n", "and print the result. Use only tensor operations." ] }, { "cell_type": "code", "execution_count": 19, "id": "falling-holder", "metadata": {}, "outputs": [], "source": [ "# Write your code here" ] }, { "cell_type": "markdown", "id": "latter-vector", "metadata": {}, "source": [ "# Tensor gradients\n", "\n", "Tensors are designed to be used in neural networks. Their most important functionality is automatic gradient and backward propagation calculation." ] }, { "cell_type": "code", "execution_count": 20, "id": "guided-interface", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "out=35.0\n", "\n", "gradient\n", "tensor([[12., 3.],\n", " [27., 3.]])\n" ] } ], "source": [ "x = torch.tensor([[2., -1.], [3., 1.]], requires_grad=True)\n", "out = x.pow(3).sum() # the actual derivative is 3*x^2\n", "print(\"out={}\".format(out))\n", "print()\n", "\n", "out.backward()\n", "print(\"gradient\")\n", "print(x.grad)" ] }, { "cell_type": "code", "execution_count": 21, "id": "nuclear-gothic", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tensor([[ 4., 2., -1.]])\n", "tensor([[ 2., -1., 3.]])\n", "tensor([[ 0.1807, 0.0904, -0.0452]])\n", "tensor([[ 0.0904, -0.0452, 0.1355]])\n" ] } ], "source": [ "x = torch.tensor([[2., -1., 3.]], requires_grad=True)\n", "y = torch.tensor([[4., 2., -1.]], requires_grad=True)\n", "\n", "z = torch.sum(x * y)\n", "\n", "z.backward()\n", "print(x.grad)\n", "print(y.grad)\n", "\n", "x.grad.data.zero_()\n", "y.grad.data.zero_()\n", "\n", "z = torch.sigmoid(torch.sum(x * y))\n", "\n", "z.backward()\n", "print(x.grad)\n", "print(y.grad)" ] }, { "cell_type": "markdown", "id": "innovative-provider", "metadata": {}, "source": [ "# Backpropagation\n", "\n", "In this section we train weights $w$ of a simple model $y = \\text{sigmoid}(w * x)$ to obtain $y = 0.65$ on $x = [2.0, -1.0, 3.0]$." ] }, { "cell_type": "code", "execution_count": 22, "id": "supposed-sellers", "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x\n", "tensor([ 2., -1., 3.])\n", "x.grad\n", "None\n", "w\n", "tensor([ 4., 2., -1.], requires_grad=True)\n", "w.grad\n", "None\n", "\n", "\n", "w\n", "tensor([ 3.9945, 2.0027, -1.0082], requires_grad=True)\n", "w.grad\n", "tensor([ 0.0547, -0.0273, 0.0820])\n", "y\n", "tensor(0.9526, grad_fn=)\n", "loss\n", "tensor(0.0916, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.9889, 2.0055, -1.0166], requires_grad=True)\n", "w.grad\n", "tensor([ 0.0563, -0.0281, 0.0844])\n", "y\n", "tensor(0.9508, grad_fn=)\n", "loss\n", "tensor(0.0905, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.9831, 2.0084, -1.0253], requires_grad=True)\n", "w.grad\n", "tensor([ 0.0579, -0.0290, 0.0869])\n", "y\n", "tensor(0.9489, grad_fn=)\n", "loss\n", "tensor(0.0894, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.6599, 2.1701, -1.5102], requires_grad=True)\n", "w.grad\n", "tensor([ 6.1291e-06, -3.0645e-06, 9.1936e-06])\n", "y\n", "tensor(0.6500, grad_fn=)\n", "loss\n", "tensor(4.5365e-11, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.6599, 2.1701, -1.5102], requires_grad=True)\n", "w.grad\n", "tensor([ 5.0985e-06, -2.5493e-06, 7.6478e-06])\n", "y\n", "tensor(0.6500, grad_fn=)\n", "loss\n", "tensor(3.1392e-11, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.6599, 2.1701, -1.5102], requires_grad=True)\n", "w.grad\n", "tensor([ 4.4477e-06, -2.2238e-06, 6.6715e-06])\n", "y\n", "tensor(0.6500, grad_fn=)\n", "loss\n", "tensor(2.3888e-11, grad_fn=)\n", "\n", "\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "x = torch.tensor([2., -1., 3.], requires_grad=False)\n", "w = torch.tensor([4., 2., -1.], requires_grad=True)\n", "y_target = 0.65\n", "\n", "print(\"x\")\n", "print(x)\n", "print(\"x.grad\")\n", "print(x.grad)\n", "print(\"w\")\n", "print(w)\n", "print(\"w.grad\")\n", "print(w.grad)\n", "print()\n", "print()\n", "\n", "optimizer = optim.SGD([w], lr=0.1)\n", "\n", "losses = []\n", "n_epochs = 100\n", "for epoch in range(n_epochs):\n", "\n", " optimizer.zero_grad()\n", " y = torch.sigmoid(torch.sum(x * w))\n", " loss = torch.pow(y - y_target, 2)\n", " loss.backward()\n", " losses.append(loss.item())\n", " optimizer.step()\n", "\n", " if epoch < 3 or epoch > 96:\n", " print(\"w\")\n", " print(w)\n", " print(\"w.grad\")\n", " print(w.grad)\n", " print(\"y\")\n", " print(y)\n", " print(\"loss\")\n", " print(loss)\n", " print()\n", " print()\n", " \n", "sns.lineplot(x=np.arange(n_epochs), y=losses).set_title('Training loss')\n", "plt.xlabel(\"epoch\")\n", "plt.ylabel(\"loss\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "addressed-anxiety", "metadata": {}, "source": [ "# Proper PyTorch model with a fully-connected layer\n", "\n", "A fully-connected layer is represented by torch.nn.Linear. Its parameters are:\n", " - in_features - the number of input neurons,\n", " - out_features - the number of output neurons,\n", " - bias - boolean if bias should be included.\n", " \n", "Documentation: https://pytorch.org/docs/stable/generated/torch.nn.Linear.html" ] }, { "cell_type": "code", "execution_count": 23, "id": "lovely-wesley", "metadata": {}, "outputs": [], "source": [ "class FullyConnectedNetworkModel(nn.Module):\n", " def __init__(self, seed):\n", " super().__init__()\n", "\n", " self.seed = torch.manual_seed(seed)\n", "\n", " self.fc = nn.Linear(3, 1, bias=False)\n", "\n", " self.fc.weight.data = torch.tensor([4., 2., -1.], requires_grad=True)\n", "\n", " def forward(self, x):\n", " x = torch.sigmoid(self.fc(x))\n", "\n", " return x" ] }, { "cell_type": "code", "execution_count": 24, "id": "hourly-apollo", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "w\n", "tensor([ 3.9945, 2.0027, -1.0082])\n", "w.grad\n", "tensor([ 0.0547, -0.0273, 0.0820])\n", "y\n", "tensor(0.9526, grad_fn=)\n", "loss\n", "tensor(0.0916, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.9889, 2.0055, -1.0166])\n", "w.grad\n", "tensor([ 0.0563, -0.0281, 0.0844])\n", "y\n", "tensor(0.9508, grad_fn=)\n", "loss\n", "tensor(0.0905, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.9831, 2.0084, -1.0253])\n", "w.grad\n", "tensor([ 0.0579, -0.0290, 0.0869])\n", "y\n", "tensor(0.9489, grad_fn=)\n", "loss\n", "tensor(0.0894, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.6599, 2.1701, -1.5102])\n", "w.grad\n", "tensor([ 6.1291e-06, -3.0645e-06, 9.1936e-06])\n", "y\n", "tensor(0.6500, grad_fn=)\n", "loss\n", "tensor(4.5365e-11, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.6599, 2.1701, -1.5102])\n", "w.grad\n", "tensor([ 5.0985e-06, -2.5493e-06, 7.6478e-06])\n", "y\n", "tensor(0.6500, grad_fn=)\n", "loss\n", "tensor(3.1392e-11, grad_fn=)\n", "\n", "\n", "w\n", "tensor([ 3.6599, 2.1701, -1.5102])\n", "w.grad\n", "tensor([ 4.4477e-06, -2.2238e-06, 6.6715e-06])\n", "y\n", "tensor(0.6500, grad_fn=)\n", "loss\n", "tensor(2.3888e-11, grad_fn=)\n", "\n", "\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "x = torch.tensor([2., -1., 3.])\n", "y_target = 0.65\n", "\n", "fc_neural_net = FullyConnectedNetworkModel(seed=6789)\n", "\n", "optimizer = optim.SGD(fc_neural_net.parameters(), lr=0.1)\n", "\n", "losses = []\n", "n_epochs = 100\n", "for epoch in range(n_epochs):\n", "\n", " optimizer.zero_grad()\n", " y = fc_neural_net(x)\n", " loss = torch.pow(y - y_target, 2)\n", " loss.backward()\n", " losses.append(loss.item())\n", " optimizer.step()\n", " \n", " if epoch < 3 or epoch > 96:\n", " print(\"w\")\n", " print(fc_neural_net.fc.weight.data)\n", " print(\"w.grad\")\n", " print(next(fc_neural_net.parameters()).grad)\n", " print(\"y\")\n", " print(y)\n", " print(\"loss\")\n", " print(loss)\n", " print()\n", " print()\n", " \n", "sns.lineplot(x=np.arange(n_epochs), y=losses).set_title('Training loss')\n", "plt.xlabel(\"epoch\")\n", "plt.ylabel(\"loss\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "breeding-sailing", "metadata": {}, "source": [ "# Embedding layer\n", "\n", "An embedding layer is represented by torch.nn.Embedding. Its main parameters are:\n", " - num_embeddings - the number of ids to embed,\n", " - embedding_dim - the dimension of the embedding vector.\n", " \n", "Documentation: https://pytorch.org/docs/stable/generated/torch.nn.Embedding.html\n", "\n", "In the example below we will have 3 movies and 3 users. The movies have already trained representations:\n", " - $m0 = [0.6, 0.4, -0.2]$\n", " - $m1 = [-0.7, 0.8, -0.7]$\n", " - $m2 = [0.8, -0.75, 0.9]$\n", "where the three dimensions represent: level of violence, positive message, foul language.\n", "\n", "We want to find user embeddings so that:\n", " - user 0 likes movie 0 and dislikes movie 1 and 2,\n", " - user 1 likes movie 1 and dislikes movie 0 and 2,\n", " - user 2 likes movie 2 and dislikes movie 0 and 1." ] }, { "cell_type": "code", "execution_count": 25, "id": "posted-performer", "metadata": {}, "outputs": [], "source": [ "class EmbeddingNetworkModel(nn.Module):\n", " def __init__(self, seed):\n", " super().__init__()\n", "\n", " self.seed = torch.manual_seed(seed)\n", "\n", " self.embedding = nn.Embedding(3, 3)\n", "\n", " def forward(self, x):\n", " user_id = x[0]\n", " item_repr = x[1]\n", " \n", " y = self.embedding(user_id) * item_repr\n", " y = torch.sum(y)\n", " y = torch.sigmoid(y)\n", "\n", " return y" ] }, { "cell_type": "code", "execution_count": 26, "id": "pleased-distributor", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "user_ids = [torch.tensor(0), torch.tensor(1), torch.tensor(2)]\n", "items = [torch.tensor([0.6, 0.4, -0.2]), \n", " torch.tensor([-0.7, 0.8, -0.7]), \n", " torch.tensor([0.8, -0.75, 0.9])]\n", "responses = [1, 0, 0, 0, 1, 0, 0, 0, 1]\n", "data = [(user_ids[user_id], items[item_id]) for user_id in range(3) for item_id in range(3)]\n", "\n", "embedding_nn = EmbeddingNetworkModel(seed=6789)\n", "\n", "optimizer = optim.SGD(embedding_nn.parameters(), lr=0.1)\n", "\n", "losses = []\n", "n_epochs = 1000\n", "for epoch in range(n_epochs):\n", "\n", " optimizer.zero_grad()\n", " \n", " for i in range(len(data)):\n", " user_id = data[i][0]\n", " item_repr = data[i][1]\n", " \n", " y = embedding_nn((user_id, item_repr))\n", " if i == 0:\n", " loss = torch.pow(y - responses[i], 2)\n", " else:\n", " loss += torch.pow(y - responses[i], 2)\n", " \n", " for param in embedding_nn.parameters():\n", " loss += 1 / 5 * torch.norm(param)\n", " \n", " loss.backward()\n", " losses.append(loss.item())\n", " optimizer.step()\n", "\n", "sns.lineplot(x=np.arange(n_epochs), y=losses).set_title('Training loss')\n", "plt.xlabel(\"epoch\")\n", "plt.ylabel(\"loss\")\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 27, "id": "turkish-thinking", "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Embedding for user 0\n", "tensor([ 0.9887, 0.2676, -0.7881], grad_fn=)\n", "Representation for item 0\n", "tensor([ 0.6000, 0.4000, -0.2000])\n", "Score=0.7\n", "\n", "Embedding for user 0\n", "tensor([ 0.9887, 0.2676, -0.7881], grad_fn=)\n", "Representation for item 1\n", "tensor([-0.7000, 0.8000, -0.7000])\n", "Score=0.52\n", "\n", "Embedding for user 0\n", "tensor([ 0.9887, 0.2676, -0.7881], grad_fn=)\n", "Representation for item 2\n", "tensor([ 0.8000, -0.7500, 0.9000])\n", "Score=0.47\n", "\n", "Embedding for user 1\n", "tensor([-1.7678, 0.1267, -0.4628], grad_fn=)\n", "Representation for item 0\n", "tensor([ 0.6000, 0.4000, -0.2000])\n", "Score=0.29\n", "\n", "Embedding for user 1\n", "tensor([-1.7678, 0.1267, -0.4628], grad_fn=)\n", "Representation for item 1\n", "tensor([-0.7000, 0.8000, -0.7000])\n", "Score=0.84\n", "\n", "Embedding for user 1\n", "tensor([-1.7678, 0.1267, -0.4628], grad_fn=)\n", "Representation for item 2\n", "tensor([ 0.8000, -0.7500, 0.9000])\n", "Score=0.13\n", "\n", "Embedding for user 2\n", "tensor([-0.2462, -1.4256, 1.1095], grad_fn=)\n", "Representation for item 0\n", "tensor([ 0.6000, 0.4000, -0.2000])\n", "Score=0.28\n", "\n", "Embedding for user 2\n", "tensor([-0.2462, -1.4256, 1.1095], grad_fn=)\n", "Representation for item 1\n", "tensor([-0.7000, 0.8000, -0.7000])\n", "Score=0.15\n", "\n", "Embedding for user 2\n", "tensor([-0.2462, -1.4256, 1.1095], grad_fn=)\n", "Representation for item 2\n", "tensor([ 0.8000, -0.7500, 0.9000])\n", "Score=0.87\n", "\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYoAAAEGCAYAAAB7DNKzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAhhklEQVR4nO3df3hV1Z3v8ff3EExuAYFg+CGIIUgHwcSISbRaR0EhWL1QW7G2SvVWRudeR9p6hzZzGbm2d5gbexlRM63CVAtWHQS0yqBXUSvqPLZCxPDDogIa+VEVjBJJpolJznf+ODtpwOTkhOT8SPJ5Pc95ztn77Oz1Xc9Jzjd7rbXXMndHRESkPaFkByAiIqlNiUJERKJSohARkaiUKEREJColChERiSot2QHEw0knneTZ2dnJDkNEpMd4/fXXP3b3rLbe65WJIjs7m/Ly8mSHISLSY5jZ++29p6YnERGJSolCRESiUqIQEZGolChERCQqJQoREYmqV456EmkWDjuVVbV89FkdI07MIHvYAEIhS3ZYIj2KEoX0WuGw88ybH3Lr6grqGsJk9A9x51X5zJw8UslCpBPU9CS9VmVVbUuSAKhrCHPr6goqq2qTHJlIz6JEIb3WR5/VtSSJZnUNYQ4eqUtSRCI9kxKF9FojTswgo//Rv+IZ/UMMH5SRpIhEeiYlCum1socN4M6r8luSRXMfRfawAUmOTKRnUWe29FqhkDFz8kgmzr+Ag0fqGD5Io55EjocShfRqoZCRkzWQnKyByQ5FpMdS05OIiESlRCEiIlEpUUifcd555wFQWVnJI488EteyXn75ZaZMmUJaWhpr166Na1ki8aZEIX3Gq6++CiQmUYwdO5YVK1bwne98J67liCSCEoX0GQMHRjq0S0pKeOWVV8jPz2fp0qU0NTWxYMECCgsLycvLY9myZQBs3LiRCy+8kNmzZ5OTk0NJSQkPP/wwRUVF5ObmsmfPnnbLys7OJi8vj1BIf2LS82nUk/Q5paWlLFmyhPXr1wOwfPlyBg8ezObNm6mvr+f8889nxowZAGzdupWdO3eSmZlJTk4O8+bNY9OmTdx9992UlZVx1113JbEmIomhRCF93oYNG9i2bVtLX0J1dTW7du3ihBNOoLCwkFGjRgEwfvz4lgSSm5vLiy++mLSYRRJJiUL6PHenrKyM4uLio/Zv3LiR9PT0lu1QKNSyHQqFaGxsTGicIsmiBlTpcwYNGsSRI0datouLi7n33ntpaGgA4J133qG2VjPMijRTopA+Jy8vj379+nHmmWeydOlS5s2bx6RJk5gyZQpnnHEGN910U5evFjZv3syYMWNYs2YNN910E5MnT+6m6EUSz9w92TF0u4KCAi8vL092GCIiPYaZve7uBW29pysKERGJSp3ZIl2wePFi1qxZc9S+OXPmsHDhwiRFJNL91PQkIiJqehIRkeOnRCEiIlEpUYiISFRKFCIiEpUShYiIRJXURGFmM83sbTPbbWYlbbx/vZkdMrOK4DEvGXGKiPRlSbuPwsz6AT8HpgP7gc1mts7d/3DMoY+6+98kPEAREQGSe0VRBOx293fd/XNgFTA7ifGIiEgbkpkoRgP7Wm3vD/Yd65tmts3M1prZKe2dzMxuNLNyMys/dOhQd8cqItJnpXpn9r8B2e6eBzwHrGzvQHdf7u4F7l6QlZWVsABFRHq7ZCaKA0DrK4Qxwb4W7l7l7vXB5i+BsxMUm4iIBJKZKDYDE8xsnJmdAFwNrGt9gJmNarU5C9iZwPhERIQkjnpy90Yz+xvgWaAf8IC7v2lmPwXK3X0dMN/MZgGNwCfA9cmKV0Skr9LssSIiEnX2WK1HISLShnDYqayq5aPP6hhxYgbZwwYQClmyw0oKJQoRkWOEw84zb37IrasrqGsIk9E/xJ1X5TNz8sg+mSxSfXisiEjCVVbVtiQJgLqGMLeurqCyqjbJkSWHEoWIyDE++qyuJUk0q2sIc/BIXZIiSi4lChGRY4w4MYOM/kd/PWb0DzF8UEaSIkouJQoRkWNkDxvAnVfltySL5j6K7GEDkhxZcqgzW0TkGKGQMXPySCbOv4CDR+oYPkijnkRE5BihkJGTNZCcrIHJDiXp1PQkIiJRKVGIiEhUShQi0mucd955AFRWVvLII4/Etaz6+nq+9a1vcdppp3HOOedQWVkZ1/KSSYlCRHqNV199FUhMorj//vsZOnQou3fv5oc//CE//vGP41peMilRiEivMXBgpOO5pKSEV155hfz8fJYuXUpTUxMLFiygsLCQvLw8li1bBsDGjRu58MILmT17Njk5OZSUlPDwww9TVFREbm4ue/bsabesJ598kuuuuw6AK6+8khdeeIFkTbIaDjvvHqrhd3s+5t1DNYTD3RuHRj2JSK9TWlrKkiVLWL9+PQDLly9n8ODBbN68mfr6es4//3xmzJgBwNatW9m5cyeZmZnk5OQwb948Nm3axN13301ZWRl33XVXm2UcOHCAU06JrL2WlpbG4MGDqaqq4qSTTkpIHZslYl4qXVGISK+3YcMGHnzwQfLz8znnnHOoqqpi165dABQWFjJq1CjS09MZP358SwLJzc3tEf0OiZiXSlcUItLruTtlZWUUFxcftX/jxo2kp6e3bIdCoZbtUChEY2Nju+ccPXo0+/btY8yYMTQ2NlJdXc2wYcPiU4Eoos1L1V33gOiKQkR6nUGDBnHkyJGW7eLiYu69914aGhoAeOedd6it7dp/3LNmzWLlypUArF27lmnTpmGW+Du3EzEvla4oRKTXycvLo1+/fpx55plcf/31fP/736eyspIpU6bg7mRlZfHEE090qYwbbriBuXPnctppp5GZmcmqVau6J/hOap6X6tg+iu6cl0pLoYqI9HDNq/F1ZV4qLYUqItKLxXteKiUKEZEoFi9ezJo1a47aN2fOHBYuXJikiBJPTU8iIhK16UmjnkREermVK1cyYcIEJkyY0DJSqzPU9CQi0gs0NjaSlvbFr/RPPvmEn/zkJ5SXl2NmnH322cyaNYuhQ4fGfO4Orygs4lozWxRsjzWzos5UoCeI91wpIiKtVVZWcsYZZ7RsL1myhNtvv5177rmHSZMmkZeXx9VXXw1AbW0t3/ve9ygqKuKss87iySefBGDFihXMmjWLadOmcfHFF7dZzrPPPsv06dPJzMxk6NChTJ8+nWeeeaZTscZyRfELIAxMA34KHAEeAwo7VVIKS8RcKSIisSgtLeW9994jPT2dw4cPA5EO9WnTpvHAAw9w+PBhioqKuOSSSwDYsmUL27ZtIzMzs83ztZ6TCmDMmDEcOHCgUzHF0kdxjrvfDNQBuPunwAmdKiXFJWKuFBGRWOTl5XHNNdfw0EMPtTQlbdiwgdLSUvLz87nooouoq6tj7969AC1XC/EUS6JoMLN+gAOYWRaRK4xeI9pcKSIi8ZCWlkY4/Ofvnbq6yPfNU089xc0338yWLVsoLCyksbERd+exxx6joqKCiooK9u7dy+mnnw7AgAHR78BunpOq2f79+xk9enSnYo0lUdwD/AYYbmaLgX8H/rFTpaS4RMyVIiLS2ogRIzh48CBVVVXU19ezfv16wuEw+/btY+rUqdxxxx1UV1dTU1NDcXExZWVlLetdvPHGGzGXU1xczIYNG/j000/59NNP2bBhwxcmR+xIh30U7v6wmb0OXAwY8HV339mpUlJcIuZKERFprX///ixatIiioiJGjx7NxIkTaWpq4tprr6W6uhp3Z/78+QwZMoTbbruNH/zgB+Tl5REOhxk3blzLWhsdyczM5LbbbqOwMNKtvGjRok43VXV4w52ZtXXGI+7e0KmSEuh4brjrjrlSRER6qq7O9bQFOAX4lMgVxRDgQzP7CPgrd3+9uwJNpnjPlSIi0lPFkiieA9a6+7MAZjYD+CbwKyJDZ8+JX3giIhKL7du3M3fu3KP2paen89prr3X53LE0PW1399xj9m1z9zwzq3D3/C5H0c0015OISOd0da6nD8zsx2Z2avD4EfBRMGS2Vw2TTYaZM2cyZMgQLr/88mSHIiLSplgSxXeAMcATwWNssK8fcFVXCjezmWb2tpntNrOSNt5PN7NHg/dfM7PsrpSXLNHW3V2wYAG//vWvExiNiEjnxDI89mPglnbe3n28BQdXJD8HpgP7gc1mts7d/9DqsBuAT939NDO7GrgD+NbxlhmryspKLr/8cnbs2AFE5mCpqakhMzOT++67j7S0NCZNmsSqVauora3llltuYceOHTQ0NHD77bcze/ZsVqxYweOPP05NTQ1NTU289NJLbZZ18cUXs3HjxnhXSUTkuHWYKII7sX8ETAZa7kBz92ldLLsI2O3u7wblrAJmA60TxWzg9uD1WuCfzcw8SYtodPccLCIiPUEsTU8PA28B44CfAJXA5m4oezSwr9X2/mBfm8e4eyNQDQxr62RmdqOZlZtZ+aFDh7ohvC9KxTlYRETiLZZEMczd7wca3P0ld/8ekZlkU4q7L3f3AncvyMrK6tK5EjUHi4hITxDTpIDB8wdmdpmZnQV0x7/JB4jcyNdsTLCvzWPMLA0YDFR1Q9lRJWoOFhGRniCWG+7+wcwGA/8TKANOBH7YDWVvBiaY2TgiCeFqIqOpWlsHXAf8DrgS+G0i+icSNQcLwAUXXMBbb71FTU0NY8aM4f777+/0hF0iIvHU4Q13cS3c7GvAXUSG2j7g7ovN7KdAubuvM7MM4NfAWcAnwNXNnd/R6IY7EZHO6dJcT2b2M+AfgD8BzwB5wA/d/aGuBubuTwNPH7NvUavXdcCcrpYjIiLHL5ampxnu/iMzu4LIiKdvAC8DXU4UfUU852AREYm3WBJF8zGXAWvcvdpM0293Rm5uLhUVFckOQ0TkuMSSKNab2VtEmp7+e3ADntYIFRHpIzocHuvuJcB5QEGwWFEtkTumRUSkD+gwUZjZHCI32zWZ2d8T6Zs4Oe6RiYhISojlhrvb3P2ImX0VuAS4H7g3vmGJiEiqiCVRNAXPlwHL3f0p4IT4hSQiIqkklkRxwMyWEZne+2kzS4/x50REpBeI5Qv/KuBZoNjdDxOZ52lBPIMSEZHUEcuop/8ADgJfDXY1ArviGZSIiKSOWEY9/W/gx8DfBbv6o7uyRUT6jFianq4AZhG5fwJ3/yMwKJ5BiYhI6oglUXweTO3tAGam1XhERPqQWBLF6mDU0xAz+yvgeeBf4huWiIikig7nenL3JWY2HfgM+Atgkbs/F/fIREQkJcQyKSDu/pyZvdZ8vJlluvsncY1MRERSQiwLF90E/ITIjLFhwIj0V+TENzQREUkFsVxR/C1whrt/HO9gREQk9cTSmb0H+I94ByIiIqkpliuKvwNeDfoo6pt3uvv8uEUlIiIpI5ZEsQz4LbCdSB+FiIj0IbEkiv7ufmvcIxERkZQUSx/F/zezG81slJllNj/iHpmIiKSEWK4ovh08/12rfRoeKyLSR8RyZ/a4RAQiIiKpSSvViYhIVEoUIiISlRKFiIhEFcsKd2Zm15rZomB7rJkVxT80ERFJBbFcUfwC+Ap/Hv10BPh53CISEZGUEsvw2HPcfYqZvQHg7p+a2QlxjktERFJELFcUDWbWjz8vhZqFpvIQEekzYkkU9wC/AYab2WLg34F/jGtUIiKSMmK54e5hM3sduJjIokVfd/edcY9MRERSQiwr3N0DrHJ3dWCLiPRBsTQ9vQ78vZntMbMlZlYQ76BERCR1dJgo3H2lu38NKATeBu4ws11dKTSYgfY5M9sVPA9t57gmM6sIHuu6UqaIiByfztyZfRowETgVeKuL5ZYAL7j7BOCFYLstf3L3/OAxq4tliojIcYjlzuyfBVcQPwV2AAXu/l+7WO5sYGXweiXw9S6eT0RE4iSWG+72AF9x94+7sdwR7v5B8PpDYEQ7x2WYWTnQCJS6+xPtndDMbgRuBBg7dmw3hioi0re1myjMbKK7vwVsBsaa2VHfvu6+JdqJzex5YGQbby085jxuZt7OaU519wNmlgP81sy2u/uetg509+XAcoCCgoL2ziciIp0U7YriViL/of9TG+85MC3aid39kvbeM7OPzGyUu39gZqOAg+2c40Dw/K6ZbQTOInKFIyIiCdJuonD3G4OXl7p7Xev3zCyji+WuA64DSoPnJ489IBgJ9R/uXm9mJwHnAz/rYrkiItJJsYx6ejXGfZ1RCkwPOskvCbYxswIz+2VwzOlAuZltBV4k0kfxhy6WKyIinRStj2IkMBr4L2Z2FpHpOwBOBL7UlULdvYrIlCDH7i8H5gWvXwVyu1KOiIh0XbQrimJgCTAGuJNIX8U/Eem7+F/xD01EJDWcd955AFRWVvLII4/Etaw777yTSZMmkZeXx8UXX8z7778f1/Ji0W6iCO7Ingpc7+5TWz1mufvjCYxRRCSpXn010tqeiERx1llnUV5ezrZt27jyyiv50Y9+FNfyYtFuojCza4OX2WZ267GPBMUnIpJ0AwcOBKCkpIRXXnmF/Px8li5dSlNTEwsWLKCwsJC8vDyWLVsGwMaNG7nwwguZPXs2OTk5lJSU8PDDD1NUVERubi579rQ/eHPq1Kl86UuR1v1zzz2X/fv3x7+CHYg2PHZA8DwwEYGIiKS60tJSlixZwvr16wFYvnw5gwcPZvPmzdTX13P++eczY8YMALZu3crOnTvJzMwkJyeHefPmsWnTJu6++27Kysq46667Oizv/vvv59JLL41nlWISbXjssuD5J4kLR0Sk59iwYQPbtm1j7dq1AFRXV7Nr1y5OOOEECgsLGTVqFADjx49vSSC5ubm8+OKLHZ77oYceory8nJdeeil+FYhRrHM9nWhm/c3sBTM71KpZSkSkz3J3ysrKqKiooKKigvfee68lIaSnp7ccFwqFWrZDoRCNjY1Rz/v888+zePFi1q1bd9R5kiWW+yhmuPtnwOVAJZFZZBfEMygRkVQ0aNAgjhw50rJdXFzMvffeS0NDAwDvvPMOtbW1XSrjjTfe4KabbmLdunUMHz68S+fqLrFMCth8zGXAGnevNrNox4uI9Ep5eXn069ePM888k+uvv57vf//7VFZWMmXKFNydrKwsnnjiiS6VsWDBAmpqapgzZw4QmeR03brkLsdj7tHnzzOzUiLTgP8JKAKGAOvd/Zx4B3e8CgoKvLy8PNlhiIj0GGb2uru3uYJpLCvclQDnEVmHogGoJbKehIiI9AEdNj2ZWX/gWuAvgyanl4D74hyXiEivtnjxYtasWXPUvjlz5rBw4cJ2fiJ5Yml6+iXQnz+vSDcXaHL3eXGO7bip6UlEpHOiNT3F0pld6O5nttr+bTCjq4iI9AGxDI9tMrPxzRvBanNN8QtJRKT3Coeddw/V8Ls9H/PuoRrC4dRfkDOWK4oFwItm9i6RqcZPBf5bXKMSEemFwmHnmTc/5NbVFdQ1hMnoH+LOq/KZOXkkoVDq3nbQYaJw9xfMbALwF8Gut929Pr5hiYj0PpVVtS1JAqCuIcytqyuYOP8CcrJSd1q9WEY9ZQD/A/gqkbWyXzGz+45dHlVERKL76LO6liTRrK4hzMEjdSmdKGLpo3gQmAyUAf8cvP51PIMSEemNRpyYQUb/o792M/qHGD4oI0kRxSaWRHGGu9/g7i8Gj78ikixERKQTsocN4M6r8luSRXMfRfawAR38ZHLF0pm9xczOdfffA5jZOYBuUhAR6aRQyJg5eSQT51/AwSN1DB+UQfawASndkQ2xJYqzgVfNbG+wPRZ428y2A+7ueXGLTkSklwmFjJysgSndJ3GsWBLFzLhHISIiKSuW4bHvJyIQERFJTbF0ZouISB+mRCEiIlEpUYiISFRKFCIiEpUShYiIRKVEISIiUSlRiIhIVEoUIiISlRKFiIhEpUQhIiJRKVGIiEhUShQiIhJVUhKFmc0xszfNLGxmBVGOm2lmb5vZbjMrSWSMIiISkawrih3AN4CX2zvAzPoBPwcuBSYB3zazSYkJT0REmsWyHkW3c/edAGZRV3UqAna7+7vBsauA2cAf4h6giIi0SOU+itHAvlbb+4N9bTKzG82s3MzKDx06FPfgRET6irhdUZjZ88DINt5a6O5Pdnd57r4cWA5QUFDg3X1+EZG+Km6Jwt0v6eIpDgCntNoeE+wTEZEESuWmp83ABDMbZ2YnAFcD65Ick4hIn5Os4bFXmNl+4CvAU2b2bLD/ZDN7GsDdG4G/AZ4FdgKr3f3NZMQrItKXJWvU02+A37Sx/4/A11ptPw08ncDQRETkGKnc9CQiIilAiUJERKJSohARkaiUKEREJColChERiUqJQkREolKiEBGRqJQoREQkKiUKERGJSolCRESiUqIQEZGolChERCQqJQoREYlKiUJERKJSohARkaiUKEREJColChFpU0VFBV/5yleYPHkyeXl5PProo8kOSZIkKSvciUjqaGxsJC3ti18FX/rSl3jwwQeZMGECf/zjHzn77LMpLi5myJAhiQ9SkkqJQqSHqays5PLLL2fHjh0ALFmyhJqaGjIzM7nvvvtIS0tj0qRJrFq1itraWm655RZ27NhBQ0MDt99+O7Nnz2bFihU8/vjj1NTU0NTUxEsvvfSFcr785S+3vD755JMZPnw4hw4dUqLog5QoRHqJ0tJS3nvvPdLT0zl8+DAAixcvZtq0aTzwwAMcPnyYoqIiLrnkEgC2bNnCtm3byMzM7PDcmzZt4vPPP2f8+PHxrIKkKPVRiPQSeXl5XHPNNTz00EMtTUkbNmygtLSU/Px8LrroIurq6ti7dy8A06dPjylJfPDBB8ydO5df/epXhEL6yuiL9KmL9DBpaWmEw+GW7bq6OgCeeuopbr75ZrZs2UJhYSGNjY24O4899hgVFRVUVFSwd+9eTj/9dAAGDBjQYVmfffYZl112GYsXL+bcc8+NT4Uk5SlRiPQwI0aM4ODBg1RVVVFfX8/69esJh8Ps27ePqVOncscdd1BdXU1NTQ3FxcWUlZXh7gC88cYbMZfz+eefc8UVV/Dd736XK6+8Ml7VkR5AfRQiPUz//v1ZtGgRRUVFjB49mokTJ9LU1MS1115LdXU17s78+fMZMmQIt912Gz/4wQ/Iy8sjHA4zbtw41q9fH1M5q1ev5uWXX6aqqooVK1YAsGLFCvLz8+NXOUlJ1vyfRm9SUFDg5eXlyQ5DRKTHMLPX3b2grffU9CQiIlGp6Umkj9u+fTtz5849al96ejqvvfZakiKSVKNEIdLH5ebmUlFRkewwJIWp6UlERKLSFYVIDxAOO5VVtXz0WR0jTswge9gAQiFLdljSRyhRiKS4cNh55s0PuXV1BXUNYTL6h7jzqnxmTh6pZCEJoaYnkRRXWVXbkiQA6hrC3Lq6gsqq2iRHJn2FEoVIivvos7qWJNGsriHMwSN1SYpI+holCpEUN+LEDDL6H/2nmtE/xPBBGUmKSPoaJQqRFJc9bAB3XpXfkiya+yiyh3U8qZ9Id0hKZ7aZzQFuB04Hity9zfk2zKwSOAI0AY3t3V4u0puFQsbMySOZOP8CDh6pY/ggjXqSxErWqKcdwDeAZTEcO9XdP45zPCIpLRQycrIGkpM1MNmhSB+UlETh7jsBzPQfkYhIqkv1PgoHNpjZ62Z2Y7KDERHpi+J2RWFmzwMj23hrobs/GeNpvuruB8xsOPCcmb3l7i+3U96NwI0AY8eOPa6YRUTki+KWKNz9km44x4Hg+aCZ/QYoAtpMFO6+HFgOkfUoulq2iIhEpGzTk5kNMLNBza+BGUQ6wUVEJIGSssKdmV0BlAFZwGGgwt2Lzexk4Jfu/jUzywF+E/xIGvCIuy+O8fyHgPe7P/K4OQnozSO7enP9VLeeSXX7olPdPautN3rlUqg9jZmV9+Z7RHpz/VS3nkl165yUbXoSEZHUoEQhIiJRKVGkhuXJDiDOenP9VLeeSXXrBPVRiIhIVLqiEBGRqJQoREQkKiWKJDCzOWb2ppmFzazdYWxmVmlm282swszanIo9FXWifjPN7G0z221mJYmM8XiZWaaZPWdmu4Lnoe0c1xR8bhVmti7RcXZGR5+DmaWb2aPB+6+ZWXYSwjwuMdTtejM71OqzmpeMOI+HmT1gZgfNrM0bkS3inqDu28xsyvGWpUSRHM3TrLc5Hckxprp7fg8b891h/cysH/Bz4FJgEvBtM5uUmPC6pAR4wd0nAC8E2235U/C55bv7rMSF1zkxfg43AJ+6+2nAUuCOxEZ5fDrxO/Zoq8/qlwkNsmtWADOjvH8pMCF43Ajce7wFKVEkgbvvdPe3kx1HvMRYvyJgt7u/6+6fA6uA2fGPrstmAyuD1yuBrycvlG4Ry+fQus5rgYutZ6wR0FN/x2ISTJD6SZRDZgMPesTvgSFmNup4ylKiSG29eZr10cC+Vtv7g32pboS7fxC8/hAY0c5xGWZWbma/N7OvJya04xLL59ByjLs3AtXAsIRE1zWx/o59M2iaWWtmpyQmtITotr+xZK1w1+slepr1ROum+qWkaHVrveHubmbtjS8/NfjscoDfmtl2d9/T3bFKl/0b8K/uXm9mNxG5cpqW5JhSjhJFnCR6mvVE64b6HQBa//c2JtiXdNHqZmYfmdkod/8guIw/2M45mj+7d81sI3AWkIqJIpbPofmY/WaWBgwGqhITXpd0WDd3b12PXwI/S0BcidJtf2NqekpRfWCa9c3ABDMbZ2YnAFcDKT06KLAOuC54fR3whasnMxtqZunB65OA84E/JCzCzonlc2hd5yuB33rPuFO3w7od02Y/C9iZwPjibR3w3WD007lAdatm085xdz0S/ACuINJeWA98BDwb7D8ZeDp4nQNsDR5vEmnSSXrs3VW/YPtrwDtE/tPuEfUj0jb/ArALeB7IDPYXEJkiH+A8YHvw2W0Hbkh23B3U6QufA/BTYFbwOgNYA+wGNgE5yY65G+v2f4O/r63Ai8DEZMfcibr9K/AB0BD8vd0A/DXw18H7RmTU157g97DgeMvSFB4iIhKVmp5ERCQqJQoREYlKiUJERKJSohARkaiUKEREJColCpFOMLOTzWxtB8dcZGbrExWTSLzpzmyRTnD3PxK56Uykz9AVhUg7zKzUzG5utX27mf1t8/z/ZpZhZr8K1gx5w8ymtnGOAcG6AZuCY2YH+683s8fN7JlgbYuftfqZmWa2xcy2mtkL0c4jkghKFCLtexS4qtX2VcBrrbZvJjI3YC7wbWClmWUcc46FRKa8KAKmAv8vmJIFIB/4FpALfMvMTjGzLOBfgG+6+5nAnBjOIxJXanoSaYe7v2Fmw83sZCAL+JSjp23+KlAWHPuWmb0PfPmY08wAZpnZ3wbbGcDY4PUL7l4NYGZ/AE4FhgIvu/t7wXk/6eA8vWluIklRShQi0a0h0icxksgVRmcZkauDoxZyMrNziMyF1ayJ6H+PbZ5HJBHU9CQS3aNEZh29kkjSaO0V4BoAM/sykf/wj/0ifxa4pXlFODM7q4Pyfg/8pZmNC47PPM7ziHQbJQqRKNz9TWAQcMC/OEXzL4CQmW0nklCud/f6Y475P0B/YJuZvRlsRyvvEJH1jR83s638+SqmU+cR6U6aPVZERKLSFYWIiESlRCEiIlEpUYiISFRKFCIiEpUShYiIRKVEISIiUSlRiIhIVP8JDExyqqoT9okAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "id_pairs = [(user_id, item_id) for user_id in range(3) for item_id in range(3)]\n", "\n", "for id_pair in id_pairs:\n", " print(\"Embedding for user {}\".format(id_pair[0]))\n", " print(embedding_nn.embedding(user_ids[id_pair[0]]))\n", " print(\"Representation for item {}\".format(id_pair[1]))\n", " print(items[id_pair[1]])\n", " print(\"Score={}\".format(round(embedding_nn((user_ids[id_pair[0]], items[id_pair[1]])).item(), 2)))\n", " print()\n", " \n", "embeddings = pd.DataFrame(\n", " [\n", " ['user_0'] + embedding_nn.embedding(user_ids[0]).tolist(),\n", " ['user_1'] + embedding_nn.embedding(user_ids[1]).tolist(),\n", " ['user_2'] + embedding_nn.embedding(user_ids[2]).tolist(),\n", " ['item_0'] + items[0].tolist(),\n", " ['item_1'] + items[1].tolist(),\n", " ['item_2'] + items[2].tolist()\n", " \n", " ],\n", " columns=['entity', 'violence', 'positive message', 'language']\n", ")\n", "\n", "ax = sns.heatmap(embeddings.loc[:, ['violence', 'positive message', 'language']], annot=True)\n", "ax.yaxis.set_major_formatter(ticker.FixedFormatter(embeddings.loc[:, 'entity'].tolist()))\n", "plt.yticks(rotation=0)\n", "plt.show()\n", "\n", "ax = sns.scatterplot(data=embeddings, x='violence', y='positive message')\n", "for i in range(embeddings.shape[0]):\n", " x = embeddings['violence'][i]\n", " x = x + (-0.1 + 0.1 * -np.sign(x - np.mean(embeddings['violence'])))\n", " y = embeddings['positive message'][i]\n", " y = y + (-0.02 + 0.13 * -np.sign(y - np.mean(embeddings['positive message'])))\n", " plt.text(x=x, y=y, s=embeddings['entity'][i])\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "middle-newman", "metadata": {}, "source": [ "## PyTorch advanced operations tasks" ] }, { "cell_type": "markdown", "id": "manual-serial", "metadata": {}, "source": [ "**Task 4.** Calculate the derivative $f'(w)$ using PyTorch and backward propagation (the backword method of the Tensor class) for the following functions and points:\n", " - $f(w) = w^3 + w^2$ and $w = 2.0$,\n", " - $f(w) = \\text{sin}(w)$ and $w = \\pi$,\n", " - $f(w) = \\ln(w * e^{3w})$ and $w = 1.0$." ] }, { "cell_type": "code", "execution_count": 28, "id": "copyrighted-perry", "metadata": {}, "outputs": [], "source": [ "# Write your code here" ] }, { "cell_type": "markdown", "id": "frequent-sarah", "metadata": {}, "source": [ "**Task 5.** Calculate the derivative $\\frac{\\partial f}{\\partial w_1}(w_1, w_2, w_3)$ using PyTorch and backward propagation (the backword method of the Tensor class) for the following functions and points:\n", " - $f(w_1, w_2) = w_1^3 + w_1^2 + w_2$ and $(w_1, w_2) = (2.0, 3.0)$,\n", " - $f(w_1, w_2, w_3) = \\text{sin}(w_1) * w_2 + w_1^2 * w_3$ and $(w_1, w_2) = (\\pi, 2.0, 4.0)$,\n", " - $f(w_1, w_2, w_3) = e^{w_1^2 + w_2^2 + w_3^2} + w_1^2 + w_2^2 + w_3^2$ and $(w_1, w_2, w_3) = (0.5, 0.67, 0.55)$." ] }, { "cell_type": "code", "execution_count": 29, "id": "dietary-columbia", "metadata": {}, "outputs": [], "source": [ "# Write your code here" ] }, { "cell_type": "markdown", "id": "short-border", "metadata": {}, "source": [ "**Task 6*.** Train a neural network with:\n", " - two input neurons, \n", " - four hidden neurons with sigmoid activation in the first hidden layer,\n", " - four hidden neurons with sigmoid activation in the second hidden layer,\n", " - one output neuron without sigmoid activation \n", " \n", "to get a good approximation of $f(x) = x_1 * x_2 + 1$ on the following dataset $D = \\{(1.0, 1.0), (0.0, 0.0), (2.0, -1.0), (-1.0, 0.5), (-0.5, -2.0)\\}$, i.e. the network should satisfy:\n", " - $\\text{net}(1.0, 1.0) \\sim 2.0$,\n", " - $\\text{net}(0.0, 0.0) \\sim 1.0$,\n", " - $\\text{net}(2.0, -1.0) \\sim -1.0$,\n", " - $\\text{net}(-1.0, 0.5) \\sim 0.5$,\n", " - $\\text{net}(-0.5, -2.0) \\sim 2.0$.\n", " \n", "After training print all weights and separately print $w_{1, 2}^{(1)}$ (the weight from the second input to the first hidden neuron in the first hidden layer) and $w_{1, 3}^{(3)}$ (the weight from the third hidden neuron in the second hidden layer to the output unit).\n", "\n", "Print the values of the network on the training points and verify that these values are closer to the real values of the $f$ function than $\\epsilon = 0.1$, i.e. $|\\text{net}(x) - f(x)| < \\epsilon$ for $x \\in D$.\n", "\n", "Because this network is only tested on the training set, it will certainly overfit if trained long enough. Train for 1000 epochs and then calculate\n", " - $\\text{net}(2.0, 2.0)$,\n", " - $\\text{net}(-1.0, -1.0)$,\n", " - $\\text{net}(3.0, -3.0)$.\n", " \n", "How far are these values from real values of the function $f$?" ] }, { "cell_type": "code", "execution_count": 30, "id": "documentary-petersburg", "metadata": {}, "outputs": [], "source": [ "# Write your code here" ] } ], "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": 5 }