diff --git a/.gitignore b/.gitignore index 5dc3011c..7c1137ca 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,6 @@ dmypy.json # Pyre type checker .pyre/ + +#Hayat changes +/lab2/data/* \ No newline at end of file diff --git a/HayatLabs/HLab2.ipynb b/HayatLabs/HLab2.ipynb new file mode 100644 index 00000000..58b58317 --- /dev/null +++ b/HayatLabs/HLab2.ipynb @@ -0,0 +1,389 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4d6888ef", + "metadata": {}, + "source": [ + "# Introuduction:\n", + "This is the lab-2 introducing the basic version of a Deep Learning Model implenentation in pytorch." + ] + }, + { + "cell_type": "markdown", + "id": "856aad4e", + "metadata": {}, + "source": [ + "# Class Inheritence\n", + "This section introduces the basic strucure of class inheritance which we will follow in pytorch for inheriting our classes from torch.nn.Modules." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "db337913", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Constructor of Parent Class\n", + "Constructor of Child Class\n" + ] + } + ], + "source": [ + "class parent ():\n", + " def __init__(self):\n", + " print(\"Constructor of Parent Class\")\n", + "class child(parent):\n", + " def __init__(self):\n", + " super().__init__()\n", + " print(\"Constructor of Child Class\")\n", + "\n", + "obj = child()\n" + ] + }, + { + "cell_type": "markdown", + "id": "554185a6", + "metadata": {}, + "source": [ + "Now Lets define a DenseLayer class" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "a2f690a6", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8005edf9", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "class ourDenseLayer(torch.nn.Module):\n", + " def __init__(self,num_input,num_output):\n", + " super(ourDenseLayer, self).__init__()\n", + " self.w = torch.nn.Parameter(torch.rand(num_input,num_output))\n", + " self.bias = torch.nn.Parameter(torch.rand(num_output))\n", + " def forward(self,x):\n", + " z = torch.matmul(x, self.w) +self.bias\n", + " y = torch.sigmoid(z)\n", + " return y\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb4d4652", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "layer.w: Parameter containing:\n", + "tensor([[0.3270, 0.3158, 0.8558],\n", + " [0.3883, 0.5105, 0.5351]], requires_grad=True) having shape: torch.Size([2, 3]) is 2-dimensional\n", + "layer.bias: Parameter containing:\n", + "tensor([0.3450, 0.5998, 0.4409], requires_grad=True) having shape torch.Size([3]) is 1-dimensional\n", + "x_input: tensor([[1., 2.]]) having shape:torch.Size([1, 2]) is 2-dimensional\n", + "y output: tensor([[0.8098, 0.8740, 0.9143]], grad_fn=) having shape:torch.Size([1, 3]) is 2-dimensional\n" + ] + } + ], + "source": [ + "num_input = 2\n", + "num_output = 3\n", + "layer = ourDenseLayer(num_input,num_output)\n", + "print(f\"layer.w: {layer.w} having shape: {layer.w.shape} is {layer.w.dim()}-dimensional\")\n", + "print(f\"layer.bias: {layer.bias} having shape {layer.bias.shape} is {layer.bias.dim()}-dimensional\")\n", + "\n", + "x_input= torch.tensor([[1,2.]])\n", + "print(f\"x_input: {x_input} having shape:{x_input.shape} is {x_input.dim()}-dimensional\")\n", + "\n", + "y=layer(x_input)\n", + "print(f\"y output: {y} having shape:{y.shape} is {y.dim()}-dimensional\")" + ] + }, + { + "cell_type": "markdown", + "id": "e3e4dda4", + "metadata": {}, + "source": [ + "# Defining NN using Sequential\n", + "NOw defining a NN in pytorch is somehow automatic and not manual as shown in ourDenseLayer example. Now instead of using single module we will use sequential which act as container for multiple layers (linear and non-linear). In the example below it takes a linear layer followed by non-linear(sigmoid)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a6e63ab", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_input:tensor([[1., 2., 3.]]) having shapetorch.Size([1, 3]) is 2-dimensional\n", + " y_output: tensor([[0.8024, 0.1951, 0.3637, 0.6053]], grad_fn=) having shape:torch.Size([1, 4]) is 2-dimensional\n" + ] + } + ], + "source": [ + "input_nodes = 3 # This is the Weights W which will be multiplied with x_input so their dimensions should match. W*x_input.\n", + "output_nodes = 4\n", + "model = nn.Sequential(nn.Linear(input_nodes,output_nodes),nn.Sigmoid())\n", + "x_input = torch.tensor([[1,2,3.]])\n", + "y = model(x_input)\n", + "\n", + "\n", + "print(f\"x_input:{x_input} having shape{x_input.shape} is {x_input.dim()}-dimensional\")\n", + "print(f\" y_output: {y} having shape:{y.shape} is {y.dim()}-dimensional\")" + ] + }, + { + "cell_type": "markdown", + "id": "cedbd779", + "metadata": {}, + "source": [ + "Although using the `nn.Sequential` is simple but if you want custom architecture, custom layers, custom forward pass and custom activation function then we can use the `nn.Module` to create a subclass as we have seen in ourDenseLayer example." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4adbd8ab", + "metadata": {}, + "outputs": [], + "source": [ + "class linearWithSigmoid(nn.Module):\n", + " def __init__(self,num_inputs,num_outputs):\n", + " super().__init__()\n", + " #super(lineraWithSigmoid, self).__init__() # This is an older way of calling the parent class constructor\n", + " self.linear = nn.Linear(num_inputs,num_outputs)\n", + " self.activation = nn.Sigmoid()\n", + "\n", + " def forward(self,inputs):\n", + " z = self.linear(inputs)\n", + " y = self.activation(z)\n", + " return y" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "48aa7c07", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_input(X) shape : torch.Size([1, 3]) is 2-dimensional\n", + " y_outputshape:torch.Size([1, 4]) is 2-dimensional\n" + ] + } + ], + "source": [ + "input_nodes = 3 # This is the Weights W which will be multiplied with x_input so their dimensions should match. W*x_input.\n", + "output_nodes = 4\n", + "layer = linearWithSigmoid(input_nodes,output_nodes)\n", + "x_input = torch.tensor([[1,2,3.]])\n", + "y = layer(x_input)\n", + "print(f\"x_input(X) shape : {x_input.shape} is {x_input.dim()}-dimensional\")\n", + "print(f\" y_outputshape:{y.shape} is {y.dim()}-dimensional\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "a834cf87", + "metadata": {}, + "source": [ + "# Model Returing Input as Output\n", + "Sometime we may want out model to return the input as output without any purterbation or change. We can implement this type of behaviour in forward pass. Suppose in this example we have a boolean variable `isidentity` to control this behaviour." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "65e151d5", + "metadata": {}, + "outputs": [], + "source": [ + "class linearWithIdentity(nn.Module):\n", + " def __init__(self,num_inputs,num_outputs):\n", + " super().__init__()\n", + " self.linear = nn.Linear(num_inputs,num_outputs)\n", + " def forward(self,num_inputs,isidentity = False):\n", + " if isidentity:\n", + " return num_inputs\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "be807020", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input :tensor([[[1., 2., 3.]]]) and output: tensor([[[1., 2., 3.]]])\n" + ] + } + ], + "source": [ + "input_nodes = 3\n", + "output_nodes = 4\n", + "\n", + "model = linearWithIdentity(input_nodes,output_nodes)\n", + "x_input = torch.tensor([[[1,2,3.]]])\n", + "\n", + "y = model(x_input, isidentity = True)\n", + "\n", + "print(f\"Input :{x_input} and output: {y}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "32f831bc", + "metadata": {}, + "source": [ + "# Backpropatation\n", + "In PyTorch, when a tensor has requires_grad=True, it means that operations involving this tensor will be tracked for automatic differentiation. During the backward pass (backpropagation), gradients — which are the partial derivatives of a loss (or output) with respect to the input tensor — are computed and stored in the .grad attribute of that tensor.\n", + "Suppose x is an input tensor and y is some output tensor (e.g., a loss value). If x was defined with requires_grad=True, then calling y.backward() will compute the gradient of y with respect to x, and store it in x.grad.\n", + "Lets compute the gradient of y i.e. \n", + "$y = x^2 $:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b44ce8c7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dy_dx of y=x^2 at x=3.0 is: 6.0\n", + "The y is 9.0 and dy_dx is 6.0\n", + "Value of x.grade is 6.0\n" + ] + } + ], + "source": [ + "x = torch.tensor(3.,requires_grad= True)\n", + "y = x**2\n", + "# Now to compute the gradient of y with respect to x, we call the backward method on y.\n", + "y.backward()\n", + "# The gradient of y with respect to x is now stored in x.grad\n", + "dy_dx = x.grad\n", + "print(\"dy_dx of y=x^2 at x=3.0 is: \", dy_dx.item())\n", + "print(f'The y is {y} and dy_dx is {dy_dx}')\n", + "print(f\"Value of x.grade is {x.grad}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "3dc3849c", + "metadata": {}, + "source": [ + "# Loss Function:\n", + "In NN we use differentiation and stogastic gradient descent to optimize the loss function. Let's use an example to find the minimum of loss function \n", + "$L = (x-x_f)^2$ \n", + "Here x_f is the variable for a desire value we are trying to optimize for. L is the loss function we are trying to minimize" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "34c37ac0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iniliazing x with random value: 0.7085890173912048\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "x = torch.rand(1)\n", + "print(f\"Iniliazing x with random value: {x.item()}\")\n", + "\n", + "learning_rate = 1e-2\n", + "history = []\n", + "x_f= 4\n", + "\n", + "# We will run the gradient descent for number of iterations\n", + "# At each iteration we compute the loss, derivative of the loss wit respect to x and update the value of x.\n", + "for i in range(300):\n", + " x = torch.tensor([x], requires_grad=True)\n", + " #Compute the loss function\n", + " loss = (x - x_f)**2\n", + " # Compute the gradient of the loss with respect to x\n", + " loss.backward()\n", + " # Update the value of x using the gradient descent formula\n", + " x = x.item() - learning_rate * x.grad\n", + " history.append(x.item())\n", + "\n", + "#plotting the value of X as we optimize toward Xf\n", + "plt.plot(history)\n", + "plt.plot([0,300],[x_f,x_f])\n", + "\n", + "plt.xlabel('Iteration')\n", + "plt.ylabel('x value')\n", + "plt.show()" + ] + } + ], + "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.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lab1/PT_Part1_Intro.ipynb b/lab1/PT_Part1_Intro.ipynb index db97d067..162cd69c 100644 --- a/lab1/PT_Part1_Intro.ipynb +++ b/lab1/PT_Part1_Intro.ipynb @@ -60,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "id": "LkaimNJfYZ2w" }, @@ -70,7 +70,7 @@ "import torch.nn as nn\n", "\n", "# Download and import the MIT Introduction to Deep Learning package\n", - "!pip install mitdeeplearning --quiet\n", + "#!pip install mitdeeplearning --quiet\n", "import mitdeeplearning as mdl\n", "\n", "import numpy as np\n", @@ -94,11 +94,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "id": "tFxztZQInlAB" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "`integer` is a 0-d Tensor: 1234\n", + "`decimal` is a 0-d Tensor: 3.1415927410125732\n" + ] + } + ], "source": [ "integer = torch.tensor(1234)\n", "decimal = torch.tensor(3.14159265359)\n", @@ -118,11 +127,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "id": "oaHXABe8oPcO" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "`fibonacci` is a 1-d Tensor with shape: torch.Size([6])\n", + "`count_to_100` is a 1-d Tensor with shape: torch.Size([100])\n" + ] + } + ], "source": [ "fibonacci = torch.tensor([1, 1, 2, 3, 5, 8])\n", "count_to_100 = torch.tensor(range(100))\n", @@ -142,29 +160,195 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "id": "tFeBBe1IouS3" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "matrix is a 2-d Tensor with shape: torch.Size([2, 3])\n", + "images is a 4-d Tensor with shape: torch.Size([10, 3, 256, 256])\n", + "tensor([[1, 2, 3],\n", + " [4, 5, 6]])\n", + "tensor([[[[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]]],\n", + "\n", + "\n", + " [[[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]]],\n", + "\n", + "\n", + " [[[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]]],\n", + "\n", + "\n", + " ...,\n", + "\n", + "\n", + " [[[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]]],\n", + "\n", + "\n", + " [[[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]]],\n", + "\n", + "\n", + " [[[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]],\n", + "\n", + " [[0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " ...,\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.],\n", + " [0., 0., 0., ..., 0., 0., 0.]]]])\n" + ] + } + ], "source": [ "### Defining higher-order Tensors ###\n", "\n", "'''TODO: Define a 2-d Tensor'''\n", - "matrix = # TODO\n", + "matrix = torch.tensor([[1, 2, 3], [4, 5, 6]])\n", "\n", "assert isinstance(matrix, torch.Tensor), \"matrix must be a torch Tensor object\"\n", "assert matrix.ndim == 2\n", - "\n", + "print(f\"matrix is a {matrix.ndim}-d Tensor with shape: {matrix.shape}\")\n", "'''TODO: Define a 4-d Tensor.'''\n", "# Use torch.zeros to initialize a 4-d Tensor of zeros with size 10 x 3 x 256 x 256.\n", "# You can think of this as 10 images where each image is RGB 256 x 256.\n", - "images = # TODO\n", + "images = torch.zeros(10, 3, 256, 256)\n", "\n", "assert isinstance(images, torch.Tensor), \"images must be a torch Tensor object\"\n", "assert images.ndim == 4, \"images must have 4 dimensions\"\n", "assert images.shape == (10, 3, 256, 256), \"images is incorrect shape\"\n", - "print(f\"images is a {images.ndim}-d Tensor with shape: {images.shape}\")" + "print(f\"images is a {images.ndim}-d Tensor with shape: {images.shape}\")\n", + "\n", + "# printing the Tensor for testing purposes\n", + "print(matrix)\n", + "print(images)" ] }, { @@ -176,13 +360,150 @@ "As you have seen, the `shape` of a tensor provides the number of elements in each tensor dimension. The `shape` is quite useful, and we'll use it often. You can also use slicing to access subtensors within a higher-rank tensor:" ] }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "zeroD: 0D Tensor with shape torch.Size([])\n", + "oneD: 1D Tensor with shape torch.Size([5])\n", + "twoD: 2D Tensor with shape torch.Size([2, 3])\n", + "threeD: 3D Tensor with shape torch.Size([2, 2, 2])\n", + "fourD: 4D Tensor with shape torch.Size([2, 2, 2, 2])\n" + ] + } + ], + "source": [ + "# Summarizing Tensor\n", + "# 0D Tensor\n", + "zeroD = torch.tensor(1)\n", + "# 1D Tensor\n", + "oneD= torch.tensor([1,2,3,4,5])\n", + "# 2D Tensor\n", + "twoD = torch.tensor([[1,2,3],[4,5,6]])\n", + "# 3D Tensor\n", + "threeD = torch.tensor([[[1,2],[3,4]],[[5,6],[7,8]]])\n", + "# 4D Tensor\n", + "fourD = torch.tensor([[[[1,2],[3,4]],[[5,6],[7,8]]],[[[9,10],[11,12]],[[13,14],[15,16]]]])\n", + "\n", + "# Printing the dimensions, Shape of the tensors.\n", + "\n", + "print(f\"zeroD: {zeroD.ndim}D Tensor with shape {zeroD.shape}\")\n", + "print(f\"oneD: {oneD.ndim}D Tensor with shape {oneD.shape}\")\n", + "print(f\"twoD: {twoD.ndim}D Tensor with shape {twoD.shape}\")\n", + "print(f\"threeD: {threeD.ndim}D Tensor with shape {threeD.shape}\")\n", + "print(f\"fourD: {fourD.ndim}D Tensor with shape {fourD.shape}\")\n", + "\n", + " \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "zeroD Tensor: 1\n", + "oneD Tensor: tensor([1, 2, 3, 4, 5])\n", + "twoD Tensor: tensor([[1, 2, 3],\n", + " [4, 5, 6]])\n", + "threeD Tensor: tensor([[[1, 2],\n", + " [3, 4]],\n", + "\n", + " [[5, 6],\n", + " [7, 8]]])\n" + ] + } + ], + "source": [ + "# Visualizing Tensors\n", + "print(f\"zeroD Tensor: {zeroD}\")\n", + "print(f\"oneD Tensor: {oneD}\")\n", + "print(f\"twoD Tensor: {twoD}\")\n", + "print(f\"threeD Tensor: {threeD}\") " + ] + }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "First element of oneD: 1\n", + "Last element of oneD 5\n", + "Third element of first row in twoD: 3\n", + "Third element of first row in twoD: 3\n", + "Last element of the last row in threeD: 8\n", + "Last element of the last row in fourD:16\n" + ] + } + ], + "source": [ + "#Accessing Tensor Elements: Scalor Vectors.\n", + "\n", + "# Accessing elements in a 1D Tensor\n", + "print(f\"First element of oneD: {oneD[0]}\")\n", + "print(f\"Last element of oneD {oneD[-1]}\")\n", + "#Accessing elements in a 2D Tensor\n", + "print(f\"Third element of first row in twoD: {twoD[0,2]}\")\n", + "print(f\"Third element of first row in twoD: {twoD[0][2]}\")\n", + "\n", + "#Accessing elements in a 3D Tensor\n", + "print(f\"Last element of the last row in threeD: {threeD[-1][-1][-1]}\")\n", + "\n", + "# Accessing elements in a 4D Tensor\n", + "print(f\"Last element of the last row in fourD:{fourD[-1][-1][-1][-1]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Row Vector of twoD: tensor([1, 2, 3])\n", + "Column Vector of twoD: tensor([1, 4])\n" + ] + } + ], + "source": [ + "# Row Vector and Columns Vector\n", + "\n", + "print(f\"Row Vector of twoD: {twoD[0]}\")\n", + "print (f\"Column Vector of twoD: {twoD[:,0]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, "metadata": { "id": "FhaufyObuLEG" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "`row_vector`: tensor([4, 5, 6])\n", + "`column_vector`: tensor([2, 5])\n", + "`scalar`: 2\n" + ] + } + ], "source": [ "row_vector = matrix[1]\n", "column_vector = matrix[:, 1]\n", @@ -208,11 +529,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "id": "X_YJrZsxYZ2z" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "c1: 76\n", + "c2: 76\n", + "Type of C2:\n" + ] + } + ], "source": [ "# Create the nodes in the graph and initialize values\n", "a = torch.tensor(15)\n", @@ -222,7 +553,8 @@ "c1 = torch.add(a, b)\n", "c2 = a + b # PyTorch overrides the \"+\" operation so that it is able to act on Tensors\n", "print(f\"c1: {c1}\")\n", - "print(f\"c2: {c2}\")\n" + "print(f\"c2: {c2}\")\n", + "print(f\"Type of C2:{type(c2)}\")\n" ] }, { @@ -244,7 +576,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { "id": "PJnfzpWyYZ23", "scrolled": true @@ -256,9 +588,9 @@ "# Construct a simple computation function\n", "def func(a, b):\n", " '''TODO: Define the operation for c, d, e.'''\n", - " c = # TODO\n", - " d = # TODO\n", - " e = # TODO\n", + " c = torch.add(a, b) # TODO: Add a and b\n", + " d = b-1\n", + " e = torch.mul(c,d) \n", " return e\n" ] }, @@ -277,13 +609,55 @@ "metadata": { "id": "pnwsf8w2uF7p" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "e_out: 3.5 and Type is :\n" + ] + } + ], "source": [ "# Consider example values for a,b\n", "a, b = 1.5, 2.5\n", "# Execute the computation\n", "e_out = func(a, b)\n", - "print(f\"e_out: {e_out}\")" + "print(f\"e_out: {e_out} and Type is :{type(e_out)}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Expanding the Tensors addition a little More" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a: tensor([[0.5022, 0.9503, 0.7633],\n", + " [0.0945, 0.6224, 0.5565]]) having shape: torch.Size([2, 3])\n", + "b: tensor([[1., 1., 1.],\n", + " [1., 1., 1.]]) having shape: torch.Size([2, 3])\n", + "c: tensor([[1.5022, 1.9503, 1.7633],\n", + " [1.0945, 1.6224, 1.5565]]) having shape: torch.Size([2, 3])\n" + ] + } + ], + "source": [ + "a = torch.rand(2,3)\n", + "b = torch.ones(2,3)\n", + "c = torch.add(a, b) # Add the two tensors\n", + "print(f\"a: {a} having shape: {a.shape}\")\n", + "print(f\"b: {b} having shape: {b.shape}\")\n", + "print(f\"c: {c} having shape: {c.shape}\") # c is a Tensor with the same shape as\n" ] }, { @@ -315,7 +689,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Parent class initialized\n", + "Child class initialized\n" + ] + } + ], + "source": [ + "# This code provides an understaning of how to define a class inherit from another class.\n", + "class parent():\n", + " def __init__(self):\n", + " print(\"Parent class initialized\")\n", + "class child(parent):\n", + " def __init__(self):\n", + " super().__init__() # Call the parent class constructor\n", + " print(\"Child class initialized\")\n", + "\n", + "# Create an instance of the child class\n", + "obj = child()\n", + "\n", + "# now lets use this in pytorch." + ] + }, + { + "cell_type": "code", + "execution_count": 17, "metadata": { "id": "HutbJk-1kHPh" }, @@ -337,11 +741,13 @@ "\n", " def forward(self, x):\n", " '''TODO: define the operation for z (hint: use torch.matmul).'''\n", - " z = # TODO\n", + " z = torch.matmul(x, self.W) + self.bias # TODO: compute the output of the layer\n", "\n", " '''TODO: define the operation for out (hint: use torch.sigmoid).'''\n", - " y = # TODO\n", - " return y\n" + " y = torch.sigmoid(z) # TODO: apply the activation function to z \n", + "\n", + " return y\n", + " \n" ] }, { @@ -359,15 +765,28 @@ "metadata": { "id": "2yxjCPa69hV_" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dimensions of input : 2\n", + "input shape: torch.Size([1, 2])\n", + "output shape: torch.Size([1, 3])\n", + "output result: tensor([[0.7662, 0.9735, 0.3949]], grad_fn=)\n" + ] + } + ], "source": [ "# Define a layer and test the output!\n", "num_inputs = 2\n", "num_outputs = 3\n", "layer = OurDenseLayer(num_inputs, num_outputs)\n", - "x_input = torch.tensor([[1, 2.]])\n", + "x_input = torch.tensor([[1, 2.]]) # 1 sample of 2 inputs\n", + "# Note that the input is a 2-d Tensor with shape (1, 2) where 1 is the batch size and 2 is the number of inputs\n", "y = layer(x_input)\n", "\n", + "print(f'Dimensions of input : {x_input.ndim} -d Tensor')\n", "print(f\"input shape: {x_input.shape}\")\n", "print(f\"output shape: {y.shape}\")\n", "print(f\"output result: {y}\")" @@ -386,7 +805,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": { "id": "7WXTpmoL6TDz" }, @@ -401,7 +820,8 @@ "# Define the model\n", "'''TODO: Use the Sequential API to define a neural network with a\n", " single linear (dense!) layer, followed by non-linearity to compute z'''\n", - "model = nn.Sequential( ''' TODO ''' )\n" + "\n", + "model = nn.Sequential(nn.Linear(n_input_nodes, n_output_nodes), nn.Sigmoid())\n" ] }, { @@ -415,11 +835,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": { "id": "zKhp6XqCFFa0" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "input shape: torch.Size([1, 2])\n", + "output shape: torch.Size([1, 3])\n", + "output result: tensor([[0.7662, 0.9735, 0.3949]], grad_fn=)\n" + ] + } + ], "source": [ "# Test the model with example input\n", "x_input = torch.tensor([[1, 2.]])\n", @@ -442,7 +872,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": { "id": "K4aCflPVyViD" }, @@ -454,8 +884,8 @@ " def __init__(self, num_inputs, num_outputs):\n", " super(LinearWithSigmoidActivation, self).__init__()\n", " '''TODO: define a model with a single Linear layer and sigmoid activation.'''\n", - " self.linear = '''TODO: linear layer'''\n", - " self.activation = '''TODO: sigmoid activation'''\n", + " self.linear = nn.Linear(num_inputs,num_outputs) #'''TODO: linear layer'''\n", + " self.activation = nn.Sigmoid() #'''TODO: sigmoid activation'''\n", "\n", " def forward(self, inputs):\n", " linear_output = self.linear(inputs)\n", @@ -474,11 +904,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": { "id": "V-eNhSyRG6hl" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "input shape: torch.Size([1, 2])\n", + "output shape: torch.Size([1, 3])\n", + "output result: tensor([[0.3291, 0.6476, 0.8159]], grad_fn=)\n" + ] + } + ], "source": [ "n_input_nodes = 2\n", "n_output_nodes = 3\n", @@ -501,7 +941,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "id": "P7jzGX5D1xT5" }, @@ -517,6 +957,9 @@ " '''TODO: Implement the behavior where the network outputs the input, unchanged,\n", " under control of the isidentity argument.'''\n", " def forward(self, inputs, isidentity=False):\n", + " if isidentity:\n", + " return inputs # TODO: return the input unchanged\n", + " \n", " ''' TODO '''\n" ] }, @@ -531,20 +974,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "id": "NzC0mgbk5dp2" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "input: tensor([[1., 2.]])\n", + "Network linear output: None; network identity output: tensor([[1., 2.]])\n" + ] + } + ], "source": [ "# Test the IdentityModel\n", "model = LinearButSometimesIdentity(num_inputs=2, num_outputs=3)\n", "x_input = torch.tensor([[1, 2.]])\n", "\n", "'''TODO: pass the input into the model and call with and without the input identity option.'''\n", - "out_with_linear = # TODO\n", + "out_with_linear = model(x_input) # TODO\n", "\n", - "out_with_identity = # TODO\n", + "out_with_identity = model (x_input,True) # TODO\n", "\n", "print(f\"input: {x_input}\")\n", "print(\"Network linear output: {}; network identity output: {}\".format(out_with_linear, out_with_identity))" @@ -576,11 +1028,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "metadata": { "id": "tdkqk8pw5yJM" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dy_dx of y=x^2 at x=3.0 is: tensor(6.)\n", + "The y is 9.0 and dy_dx is 6.0\n" + ] + } + ], "source": [ "### Gradient computation ###\n", "\n", @@ -592,6 +1053,7 @@ "\n", "dy_dx = x.grad\n", "print(\"dy_dx of y=x^2 at x=3.0 is: \", dy_dx)\n", + "print(f'The y is {y} and dy_dx is {dy_dx}')\n", "assert dy_dx == 6.0\n" ] }, @@ -606,7 +1068,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, "metadata": { "attributes": { "classes": [ @@ -616,7 +1078,25 @@ }, "id": "7g1yWiSXqEf-" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Initializing x=0.7111579179763794\n" + ] + }, + { + "data": { + "image/png": "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q1+/fk3uGTEMQ7fddptOnjypL7/88qLHZWdna926dRo4cKAcDofeeecdzZs3T2vWrLlgb8+Fem4SExNVVFRUb1jLV6zadVQTFmUqsV2I1v3+RlZKAQB8gt1ul81ma9D3t8smZPz9739vUI/LxTz88MPatm2bvvrqq0se1717d3Xv3t25nZaWpkOHDun555+/YLixWq2yWq1NrqulWZPNEnAAQOvW6HDTv3//el+ahmEoPz9fx44d06uvvtqkIh555BF9/PHHWrdunRISEhp9/jXXXKPFixc36b19iWEYP5lvw5AUAKB1anS4GTt2bL1tPz8/RUVFaejQoerRo0ejXsswDD3yyCP68MMPtWbNGiUnJze2HElSVlaW4uLimnSuL9lXcGYJeICf0jp3MLscAABM0ehwM2PGDJe9+aRJk/SXv/xFH330kcLDw5WfX3ujR5vNppCQEEnStGnTdPjwYS1atEiSNGvWLHXq1EkpKSmqqKjQ4sWLlZGRoYyMDJfV1VLV9dpc07m9QoL8L3M0AAC+qUHhpjGThBszSXfu3LmSpKFDh9bbv2DBAt13332SpLy8POXm5jqfq6io0NSpU3X48GGFhIQoJSVFn376qUaPHt3g9/VV6/bWhpsh3RiSAgC0Xg1aLeXn53fZyamGYchisai6utplxblDY2ZbtySOqmr1/eNKlVfWaOVvb1C3mHCzSwIAwGVcvlpq9erVLikM7rPl4CmVV9YoKtzKXcABAK1ag8LNkCFD3F0HmunrfYWSpJ9d2Z4l4ACAVq3J17kpKytTbm6uKioq6u1PTU1tdlFovK/qwk0XVkkBAFq3RoebY8eO6f7779fy5csv+Ly3z7nxRfbySm378ZQkwg0AAH6NPeGxxx7TyZMntWHDBoWEhGjFihV6++231bVrV3388cfuqBGXseGH46oxpM4dwhQfGWJ2OQAAmKrRPTdffPGFPvroIw0ePFh+fn664oorNHz4cEVERCg9PV233HKLO+rEJXzzw3FJ0rVd2ptcCQAA5mt0z01paamio6Ml1d69+9ix2mur9OnTR1u2bHFtdWiQuvk21zEkBQBA48NN9+7dlZ2dLUnq16+f5s+fr8OHD2vevHncAsEER+3l2ldQIoul9srEAAC0do0elnrssceUl5cnqfZWDCNHjtS7776roKAgLVy40NX14TLqloD36WhT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5pln9MILL+j222+XVNvDs2vXLs2fP1/jx4/Xu+++q+rqar311lsKDQ1VSkqKfvzxR/361792dbOdp0XNuVm/fr1GjBhRb9/IkSP15ptvXnQs0uFwyOFwOLftdrvb65Skgydqe26uoOcGADwuJNBfu/57pCnv21iffPKJ2rRpo6qqKlVWVuq2227TSy+9pFdffVVXXHGFM1xI0ubNm1VSUnLelZhPnz6tH374QZK0e/duTZw4sd7zaWlpWr169QXff/fu3XI4HM5A1RDHjh3ToUOH9OCDD2rChAnO/VVVVc75PLt371bfvn3rXVwxLS2twe/RHC0q3OTn5ysmJqbevpiYGFVVVamwsFBxcXHnnZOenq4//vGPnipRklRRVaPDJ09LkjrRcwMAHmexWJo9POQpN954o+bOnavAwEDFx8fX+x/1sLD6/4NcU1OjuLg4rVmz5rzXiYyMbNL7h4SENPqcmpoaSbVDU1dffXW95+qGz5oy/8hVWtxS8HNXHtU13sVWJE2bNk1FRUXOx6FDh9xe4+FTp1Vj1Cb4qHCr298PANByhYWFqUuXLrriiisuuxpqwIABys/PV0BAgLp06VLv0aFDB0m1UzY2bNhQ77xzt3+qa9euCgkJ0eeff37B5y90S4SYmBh17NhR+/fvP6+OugnIvXr10nfffafTp083qA5Xahmx9ozY2Fjl5+fX21dQUKCAgICL3izNarU6xyU95cCZycRJ7bgzLQDAdW6++WalpaVp7Nixeu6559S9e3cdOXJEy5Yt09ixYzVo0CBNnjxZ48eP16BBg3Tdddfp3Xff1c6dOy86oTg4OFhPPPGEHn/8cQUFBelnP/uZjh07pp07d+rBBx9UdHS0QkJCtGLFCiUkJCg4OFg2m01PP/20Hn30UUVERGjUqFFyOBzKzMzUyZMnNWXKFN1111168skn9eCDD+o///M/deDAAT3//PMeaacW1XOTlpamVatW1du3cuVKDRo0yGVr/12BycQAAHewWCxatmyZbrjhBj3wwAPq1q2b7rzzTh04cMA5bWPcuHF66qmn9MQTT2jgwIE6ePDgZSfx/td//Zd+97vf6amnnlLPnj01btw4FRQUSJICAgI0Z84czZ8/X/Hx8brtttskSb/61a/0xhtvaOHCherTp4+GDBmihQsXOntu2rRpo3/84x/atWuX+vfvryef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/etf69VXX1VQUJBsNpssFku99zvXZ599pm3btiknJ0eJiYmSpHfeeUcpKSnatGmTBg8eLEmqqanRwoULFR4eLkm655579Pnnn+vZZ59tXsMAcDl6bgCYavPmzVq9erXatGnjfPTo0UNSbW9JnUGDBp137urVqzV8+HB17NhR4eHhuvfee3X8+HGVlpY2+P13796txMREZ7CRpF69eikyMlK7d+927uvUqZMz2EhSXFycCgoKGvVZAXgGPTcATFVTU6MxY8boueeeO++5uLg4589hYWH1njt48KBGjx6tiRMn6plnnlG7du301Vdf6cEHH1RlZWWD398wDFkslsvuDwwMrPe8xWJRTU1Ng98HgOcQbgB4TFBQkKqrq+vtGzBggDIyMtSpUycFBDT8n6TMzExVVVXphRdekJ9fbSf0+++/f9n3O1evXr2Um5urQ4cOOXtvdu3apaKiIvXs2bPB9QDwHgxLAfCYTp066dtvv9WBAwdUWFiompoaTZo0SSdOnNAvf/lLbdy4Ufv379fKlSv1wAMPXDKYXHnllaqqqtJLL72k/fv365133tG8efPOe7+SkhJ9/vnnKiwsVFlZ2Xmvc/PNNys1NVV33323tmzZoo0bN+ree+/VkCFDLjgUBsD7EW4AeMzUqVPl7++vXr16KSoqSrm5uYqPj9fXX3+t6upqjRw5Ur1799bkyZNls9mcPTIX0q9fP7344ot67rnn1Lt3b7377rtKT0+vd8y1116riRMnaty4cYqKijpvQrJUO7y0dOlStW3bVjfccINuvvlmde7cWX/9619d/vkBeIbFMAzD7CIAAABchZ4bAADgUwg3AADApxBuAACATyHcAAAAn0K4AQAAPoVwAwAAfArhBgAA+BTCDQAA8CmEGwAA4FMINwAAwKcQbgAAgE/5/4bKKSE7/rYoAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "### Function minimization with autograd and gradient descent ###\n", "\n", @@ -635,7 +1115,7 @@ " x = torch.tensor([x], requires_grad=True)\n", "\n", " # TODO: Compute the loss as the square of the difference between x and x_f\n", - " loss = # TODO\n", + " loss = (x - x_f) ** 2 # TODO\n", "\n", " # Backpropagate through the loss to compute gradients\n", " loss.backward()\n", @@ -688,7 +1168,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.12.11" }, "vscode": { "interpreter": { diff --git a/lab1/PT_Part2_Music_Generation.ipynb b/lab1/PT_Part2_Music_Generation.ipynb index a99bca7d..1983f173 100644 --- a/lab1/PT_Part2_Music_Generation.ipynb +++ b/lab1/PT_Part2_Music_Generation.ipynb @@ -66,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "id": "riVZCVK65QTH" }, @@ -75,7 +75,7 @@ "!pip install comet_ml > /dev/null 2>&1\n", "import comet_ml\n", "# TODO: ENTER YOUR API KEY HERE!! instructions above\n", - "COMET_API_KEY = \"\"\n", + "COMET_API_KEY = \"Xg2mJUP2iMIjlVOUSERvKB3IN\"\n", "\n", "# Import PyTorch and other relevant libraries\n", "import torch\n", @@ -119,11 +119,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { - "id": "P7dFnP5q3Jve" + "id": "P7dFnP5q3Jve", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "6ce0924e-b013-4b0f-a755-80ddd060a90a" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Found 817 songs in text\n", + "\n", + "Example song: \n", + "X:1\n", + "T:Alexander's\n", + "Z: id:dc-hornpipe-1\n", + "M:C|\n", + "L:1/8\n", + "K:D Major\n", + "(3ABc|dAFA DFAd|fdcd FAdf|gfge fefd|(3efe (3dcB A2 (3ABc|!\n", + "dAFA DFAd|fdcd FAdf|gfge fefd|(3efe dc d2:|!\n", + "AG|FAdA FAdA|GBdB GBdB|Acec Acec|dfaf gecA|!\n", + "FAdA FAdA|GBdB GBdB|Aceg fefd|(3efe dc d2:|!\n" + ] + } + ], "source": [ "# Download the dataset\n", "songs = mdl.lab1.load_training_data()\n", @@ -145,11 +169,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { - "id": "11toYzhEEKDz" + "id": "11toYzhEEKDz", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 76 + }, + "outputId": "2652f959-0cbe-4dbd-8baa-ea76b6439200" }, - "outputs": [], + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "\n", + " \n", + " " + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], "source": [ "# Convert the ABC notation to audio file and listen to it\n", "mdl.lab1.play_song(example_song)" @@ -166,11 +214,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { - "id": "IlCgQBRVymwR" + "id": "IlCgQBRVymwR", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "3df88a58-1dba-4053-de24-a97082157643" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "There are 83 unique characters in the dataset\n" + ] + } + ], "source": [ "# Join our list of song strings into a single string containing all songs\n", "songs_joined = \"\\n\\n\".join(songs)\n", @@ -208,7 +268,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "id": "IalZLbvOzf-F" }, @@ -238,11 +298,45 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { - "id": "FYyNlCNXymwY" + "id": "FYyNlCNXymwY", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "53111d5f-aa1f-45b3-f6c3-d749d4f144dc" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{\n", + " '\\n': 0,\n", + " ' ' : 1,\n", + " '!' : 2,\n", + " '\"' : 3,\n", + " '#' : 4,\n", + " \"'\" : 5,\n", + " '(' : 6,\n", + " ')' : 7,\n", + " ',' : 8,\n", + " '-' : 9,\n", + " '.' : 10,\n", + " '/' : 11,\n", + " '0' : 12,\n", + " '1' : 13,\n", + " '2' : 14,\n", + " '3' : 15,\n", + " '4' : 16,\n", + " '5' : 17,\n", + " '6' : 18,\n", + " '7' : 19,\n", + " ...\n", + "}\n" + ] + } + ], "source": [ "print('{')\n", "for char, _ in zip(char2idx, range(20)):\n", @@ -252,7 +346,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "id": "g-LnKyu4dczc" }, @@ -270,6 +364,8 @@ "'''\n", "def vectorize_string(string):\n", " '''TODO'''\n", + " vectorized_output = np.array([char2idx[char] for char in string])\n", + " return vectorized_output\n", "\n", "vectorized_songs = vectorize_string(songs_joined)" ] @@ -285,11 +381,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { - "id": "l1VKcQHcymwb" + "id": "l1VKcQHcymwb", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "61aa8b28-2c7c-4eb7-fd18-1c55bfebb5b7" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "'X:1\\nT:Alex' ---- characters mapped to int ----> [49 22 13 0 45 22 26 67 60 79]\n" + ] + } + ], "source": [ "print ('{} ---- characters mapped to int ----> {}'.format(repr(songs_joined[:10]), vectorized_songs[:10]))\n", "# check that vectorized_songs is a numpy array\n", @@ -313,11 +421,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { - "id": "LF-N8F7BoDRi" + "id": "LF-N8F7BoDRi", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "80d2a45d-6329-4a17-d3da-d86f4b8e2032" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Batch function works correctly!\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + ":18: UserWarning: Creating a tensor from a list of numpy.ndarrays is extremely slow. Please consider converting the list to a single numpy.ndarray with numpy.array() before converting to a tensor. (Triggered internally at /pytorch/torch/csrc/utils/tensor_new.cpp:254.)\n", + " x_batch = torch.tensor(input_batch, dtype=torch.long)\n" + ] + } + ], "source": [ "### Batch definition to create training examples ###\n", "\n", @@ -328,10 +456,12 @@ " idx = np.random.choice(n - seq_length, batch_size)\n", "\n", " '''TODO: construct a list of input sequences for the training batch'''\n", - " input_batch = # TODO\n", + " #input_batch = # TODO\n", + " input_batch = [vectorized_songs[i:i+seq_length] for i in idx]\n", "\n", " '''TODO: construct a list of output sequences for the training batch'''\n", - " output_batch = # TODO\n", + " #output_batch = # TODO\n", + " output_batch = [vectorized_songs[i+1:i+seq_length+1] for i in idx]\n", "\n", " # Convert the input and output batches to tensors\n", " x_batch = torch.tensor(input_batch, dtype=torch.long)\n", @@ -360,11 +490,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { - "id": "0eBu9WZG84i0" + "id": "0eBu9WZG84i0", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "c07bbbf0-ced5-4505-dc47-b72b1bd7a912" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Step 0\n", + " input: 74 (np.str_('s'))\n", + " expected output: 74 (np.str_('s'))\n", + "Step 1\n", + " input: 74 (np.str_('s'))\n", + " expected output: 64 (np.str_('i'))\n", + "Step 2\n", + " input: 64 (np.str_('i'))\n", + " expected output: 69 (np.str_('n'))\n", + "Step 3\n", + " input: 69 (np.str_('n'))\n", + " expected output: 62 (np.str_('g'))\n", + "Step 4\n", + " input: 62 (np.str_('g'))\n", + " expected output: 1 (np.str_(' '))\n" + ] + } + ], "source": [ "x_batch, y_batch = get_batch(vectorized_songs, seq_length=5, batch_size=1)\n", "\n", @@ -431,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "id": "8DsWzojvkbc7" }, @@ -452,11 +608,14 @@ "\n", " '''TODO: Layer 2: LSTM with hidden_size `hidden_size`. note: number of layers defaults to 1.\n", " Use the nn.LSTM() module from pytorch.'''\n", - " self.lstm = nn.LSTM('''TODO''') # TODO\n", + " #self.lstm = nn.LSTM('''TODO''') # TODO\n", + " self.lstm = nn.LSTM(embedding_dim,hidden_size,batch_first=True)\n", "\n", " '''TODO: Layer 3: Linear (fully-connected) layer that transforms the LSTM output\n", " # into the vocabulary size.'''\n", - " self.fc = nn.Linear('''TODO''') # TODO\n", + " #self.fc = nn.Linear('''TODO''') # TODO\n", + " self.fc = nn.Linear(hidden_size,vocab_size)\n", + "\n", "\n", " def init_hidden(self, batch_size, device):\n", " # Initialize hidden state and cell state with zeros\n", @@ -486,11 +645,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": { - "id": "MtCrdfzEI2N0" + "id": "MtCrdfzEI2N0", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "ad9af331-a639-49b7-db24-6f865a62d164" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "LSTMModel(\n", + " (embedding): Embedding(83, 256)\n", + " (lstm): LSTM(256, 1024, batch_first=True)\n", + " (fc): Linear(in_features=1024, out_features=83, bias=True)\n", + ")\n" + ] + } + ], "source": [ "# Instantiate the model! Build a simple model with default hyperparameters. You\n", "# will get the chance to change these later.\n", @@ -522,11 +697,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": { - "id": "C-_70kKAPrPU" + "id": "C-_70kKAPrPU", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "7aa6c80b-1b52-47b6-d7e7-f698b3e924b2" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Input shape: torch.Size([32, 100]) # (batch_size, sequence_length)\n", + "Prediction shape: torch.Size([32, 100, 83]) # (batch_size, sequence_length, vocab_size)\n" + ] + } + ], "source": [ "# Test the model with some sample data\n", "x, y = get_batch(vectorized_songs, seq_length=100, batch_size=32)\n", @@ -557,11 +745,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": { - "id": "4V4MfFg0RQJg" + "id": "4V4MfFg0RQJg", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "dd88ac3e-46d4-4c41-9d73-66fc78c439ef" }, - "outputs": [], + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "array([24, 45, 2, 67, 53, 43, 64, 17, 78, 2, 49, 52, 43, 79, 51, 36, 77,\n", + " 51, 67, 0, 68, 23, 16, 8, 53, 55, 82, 5, 76, 29, 56, 43, 40, 50,\n", + " 57, 54, 4, 51, 34, 15, 55, 24, 23, 80, 14, 71, 69, 44, 45, 34, 33,\n", + " 6, 47, 34, 75, 60, 47, 77, 64, 10, 74, 19, 0, 60, 52, 14, 53, 22,\n", + " 60, 59, 35, 77, 65, 60, 82, 64, 82, 8, 22, 21, 42, 0, 48, 17, 12,\n", + " 58, 19, 6, 33, 11, 75, 14, 20, 12, 12, 27, 11, 33, 49, 38])" + ] + }, + "metadata": {}, + "execution_count": 16 + } + ], "source": [ "sampled_indices = torch.multinomial(torch.softmax(pred[0], dim=-1), num_samples=1)\n", "sampled_indices = sampled_indices.squeeze(-1).cpu().numpy()\n", @@ -579,11 +787,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": { - "id": "xWcFwPwLSo05" + "id": "xWcFwPwLSo05", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "2a084ab5-bedb-4455-da1c-f474805b04a3" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Input: \n", + " \"B c2|A3 G FG|A2 d3 c|B2 G3:|!\\n\\nX:10\\nT:Tommy Bhetty's\\nZ: id:dc-waltz-6\\nM:3/4\\nL:1/8\\nK:G Major\\nz D2|G3 \"\n", + "\n", + "Next Char Predictions: \n", + " \"=T!l]Ri5w!X[RxZKvZl\\nm<4,]_|'uDaROYb^#ZI3_= /dev/null 2>&1\n", + "#pip install comet_ml > /dev/null 2>&1\n", "import comet_ml\n", "# TODO: ENTER YOUR API KEY HERE!! instructions above\n", - "COMET_API_KEY = \"\"\n", + "COMET_API_KEY = \"Xg2mJUP2iMIjlVOUSERvKB3IN\"\n", "\n", "# Import PyTorch and other relevant libraries\n", "import torch\n", @@ -83,7 +91,7 @@ "import torch.optim as optim\n", "\n", "# Download and import the MIT Introduction to Deep Learning package\n", - "!pip install mitdeeplearning --quiet\n", + "#!pip install mitdeeplearning --quiet\n", "import mitdeeplearning as mdl\n", "\n", "# Import all remaining packages\n", @@ -99,7 +107,7 @@ "\n", "# Check that we are using a GPU, if not switch runtimes\n", "# using Runtime > Change Runtime Type > GPU\n", - "assert torch.cuda.is_available(), \"Please enable GPU from runtime settings\"\n", + "#assert torch.cuda.is_available(), \"Please enable GPU from runtime settings\"\n", "assert COMET_API_KEY != \"\", \"Please insert your Comet API Key\"\n", "\n" ] @@ -661,6 +669,11 @@ }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GuGUJB0ZT_Uo" + }, + "outputs": [], "source": [ "### compute the loss on the predictions from the untrained model from earlier. ###\n", "y.shape # (batch_size, sequence_length)\n", @@ -673,12 +686,7 @@ "\n", "print(f\"Prediction shape: {pred.shape} # (batch_size, sequence_length, vocab_size)\")\n", "print(f\"scalar_loss: {example_batch_loss.mean().item()}\")" - ], - "metadata": { - "id": "GuGUJB0ZT_Uo" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -1065,9 +1073,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.12.11" } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/lab1/solutions/TF_Part2_Music_Generation_Solution.ipynb b/lab1/solutions/TF_Part2_Music_Generation_Solution.ipynb index df0ded1c..33b81375 100644 --- a/lab1/solutions/TF_Part2_Music_Generation_Solution.ipynb +++ b/lab1/solutions/TF_Part2_Music_Generation_Solution.ipynb @@ -66,22 +66,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "id": "riVZCVK65QTH" }, "outputs": [], "source": [ - "!pip install comet_ml > /dev/null 2>&1\n", + "!pip install comet_ml > /trainings/null 2>&1\n", "import comet_ml\n", "# TODO: ENTER YOUR API KEY HERE!! instructions above\n", - "COMET_API_KEY = \"\"\n", + "COMET_API_KEY = \"Xg2mJUP2iMIjlVOUSERvKB3IN\"\n", "\n", "# Import Tensorflow 2.0\n", "import tensorflow as tf\n", "\n", "# Download and import the MIT Introduction to Deep Learning package\n", - "!pip install mitdeeplearning --quiet\n", + "#!pip install mitdeeplearning --quiet\n", "import mitdeeplearning as mdl\n", "\n", "# Import all remaining packages\n", @@ -92,7 +92,7 @@ "from IPython import display as ipythondisplay\n", "from tqdm import tqdm\n", "from scipy.io.wavfile import write\n", - "!apt-get install abcmidi timidity > /dev/null 2>&1\n", + "!apt-get install abcmidi timidity > /trainings/null 2>&1\n", "\n", "\n", "# Check that we are using a GPU, if not switch runtimes\n", @@ -116,11 +116,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "id": "P7dFnP5q3Jve" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 817 songs in text\n", + "\n", + "Example song: \n", + "X:1\n", + "T:Alexander's\n", + "Z: id:dc-hornpipe-1\n", + "M:C|\n", + "L:1/8\n", + "K:D Major\n", + "(3ABc|dAFA DFAd|fdcd FAdf|gfge fefd|(3efe (3dcB A2 (3ABc|!\n", + "dAFA DFAd|fdcd FAdf|gfge fefd|(3efe dc d2:|!\n", + "AG|FAdA FAdA|GBdB GBdB|Acec Acec|dfaf gecA|!\n", + "FAdA FAdA|GBdB GBdB|Aceg fefd|(3efe dc d2:|!\n" + ] + } + ], "source": [ "# Download the dataset\n", "songs = mdl.lab1.load_training_data()\n", @@ -163,11 +183,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": { "id": "IlCgQBRVymwR" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are 83 unique characters in the dataset\n" + ] + } + ], "source": [ "# Join our list of song strings into a single string containing all songs\n", "songs_joined = \"\\n\\n\".join(songs)\n", @@ -205,7 +233,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": { "id": "IalZLbvOzf-F" }, @@ -235,11 +263,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": { "id": "FYyNlCNXymwY" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " '\\n': 0,\n", + " ' ' : 1,\n", + " '!' : 2,\n", + " '\"' : 3,\n", + " '#' : 4,\n", + " \"'\" : 5,\n", + " '(' : 6,\n", + " ')' : 7,\n", + " ',' : 8,\n", + " '-' : 9,\n", + " '.' : 10,\n", + " '/' : 11,\n", + " '0' : 12,\n", + " '1' : 13,\n", + " '2' : 14,\n", + " '3' : 15,\n", + " '4' : 16,\n", + " '5' : 17,\n", + " '6' : 18,\n", + " '7' : 19,\n", + " ...\n", + "}\n" + ] + } + ], "source": [ "print('{')\n", "for char,_ in zip(char2idx, range(20)):\n", @@ -249,7 +307,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "metadata": { "id": "g-LnKyu4dczc" }, @@ -286,11 +344,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": { "id": "l1VKcQHcymwb" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'X:1\\nT:Alex' ---- characters mapped to int ----> [49 22 13 0 45 22 26 67 60 79]\n" + ] + } + ], "source": [ "print ('{} ---- characters mapped to int ----> {}'.format(repr(songs_joined[:10]), vectorized_songs[:10]))\n", "# check that vectorized_songs is a numpy array\n", @@ -314,11 +380,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": { "id": "LF-N8F7BoDRi" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[PASS] test_batch_func_types\n", + "[PASS] test_batch_func_shapes\n", + "[PASS] test_batch_func_next_step\n", + "======\n", + "[PASS] passed all tests!\n" + ] + } + ], "source": [ "### Batch definition to create training examples ###\n", "\n", @@ -364,11 +442,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": { "id": "0eBu9WZG84i0" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Step 0\n", + " input: 27 (np.str_('B'))\n", + " expected output: 58 (np.str_('c'))\n", + "Step 1\n", + " input: 58 (np.str_('c'))\n", + " expected output: 59 (np.str_('d'))\n", + "Step 2\n", + " input: 59 (np.str_('d'))\n", + " expected output: 1 (np.str_(' '))\n", + "Step 3\n", + " input: 1 (np.str_(' '))\n", + " expected output: 30 (np.str_('E'))\n", + "Step 4\n", + " input: 30 (np.str_('E'))\n", + " expected output: 32 (np.str_('G'))\n" + ] + } + ], "source": [ "x_batch, y_batch = get_batch(vectorized_songs, seq_length=5, batch_size=1)\n", "\n", @@ -420,7 +520,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "metadata": { "id": "8DsWzojvkbc7" }, @@ -447,7 +547,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": { "id": "MtCrdfzEI2N0" }, @@ -497,11 +597,93 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "id": "RwG1DD6rDrRM" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
Model: \"sequential\"\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+              "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+              "│ embedding (Embedding)           │ (32, 100, 256)         │        21,248 │\n",
+              "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+              "│ lstm (LSTM)                     │ (32, 100, 1024)        │     5,246,976 │\n",
+              "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+              "│ dense (Dense)                   │ (32, 100, 83)          │        85,075 │\n",
+              "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+              "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ embedding (\u001b[38;5;33mEmbedding\u001b[0m) │ (\u001b[38;5;34m32\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m21,248\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ lstm (\u001b[38;5;33mLSTM\u001b[0m) │ (\u001b[38;5;34m32\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m1024\u001b[0m) │ \u001b[38;5;34m5,246,976\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;34m32\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m83\u001b[0m) │ \u001b[38;5;34m85,075\u001b[0m │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 5,353,299 (20.42 MB)\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m5,353,299\u001b[0m (20.42 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 5,353,299 (20.42 MB)\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m5,353,299\u001b[0m (20.42 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "model.summary()" ] @@ -517,11 +699,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": { "id": "C-_70kKAPrPU" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input shape: (32, 100) # (batch_size, sequence_length)\n", + "Prediction shape: (32, 100, 83) # (batch_size, sequence_length, vocab_size)\n" + ] + } + ], "source": [ "x, y = get_batch(vectorized_songs, seq_length=100, batch_size=32)\n", "pred = model(x)\n", @@ -548,11 +739,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": { "id": "4V4MfFg0RQJg" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([47, 19, 41, 79, 32, 41, 13, 53, 60, 6, 18, 62, 7, 72, 21, 46, 31,\n", + " 59, 35, 70, 59, 55, 64, 18, 59, 5, 72, 26, 74, 63, 79, 73, 6, 77,\n", + " 14, 20, 57, 16, 14, 9, 18, 58, 78, 57, 32, 2, 54, 3, 18, 28, 70,\n", + " 14, 15, 2, 82, 16, 53, 81, 30, 20, 74, 61, 38, 4, 30, 40, 30, 55,\n", + " 22, 7, 12, 68, 43, 23, 36, 55, 17, 29, 64, 70, 59, 17, 42, 17, 6,\n", + " 27, 49, 68, 15, 36, 30, 60, 54, 19, 75, 74, 45, 79, 64, 77])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "sampled_indices = tf.random.categorical(pred[0], num_samples=1)\n", "sampled_indices = tf.squeeze(sampled_indices,axis=-1).numpy()\n", @@ -570,11 +777,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": { "id": "xWcFwPwLSo05" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Input: \n", + " \"gg2 dgbg|dgbg agfe|dega bgdB|cAFA G4:|!\\n\\nX:285\\nT:Paddy's Trip to Scotland\\nZ: id:dc-reel-265\\nM:C\\nL:1/\"\n", + "\n", + "Next Char Predictions: \n", + " 'V7PxGP1]e(6g)q9UFdJod_i6d\\'qAshxr(v28b42-6cwbG!^\"6Co23!|4]zE8sfM#EOE_:)0mR" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 3000/3000 [52:43<00:00, 1.05s/it]\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "### Define optimizer and training operation ###\n", "\n", @@ -829,11 +1095,93 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "metadata": { "id": "LycQ-ot_jjyu" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
Model: \"sequential_5\"\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential_5\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+              "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+              "│ embedding_5 (Embedding)         │ (1, None, 256)         │        21,248 │\n",
+              "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+              "│ lstm_5 (LSTM)                   │ (1, None, 1024)        │     5,246,976 │\n",
+              "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+              "│ dense_5 (Dense)                 │ (1, None, 83)          │        85,075 │\n",
+              "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+              "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ embedding_5 (\u001b[38;5;33mEmbedding\u001b[0m) │ (\u001b[38;5;34m1\u001b[0m, \u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m21,248\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ lstm_5 (\u001b[38;5;33mLSTM\u001b[0m) │ (\u001b[38;5;34m1\u001b[0m, \u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1024\u001b[0m) │ \u001b[38;5;34m5,246,976\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dense_5 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;34m1\u001b[0m, \u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m83\u001b[0m) │ \u001b[38;5;34m85,075\u001b[0m │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 5,353,299 (20.42 MB)\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m5,353,299\u001b[0m (20.42 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 5,353,299 (20.42 MB)\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m5,353,299\u001b[0m (20.42 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+              "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "'''TODO: Rebuild the model using a batch_size=1'''\n", "model = build_model(vocab_size, params[\"embedding_dim\"], params[\"rnn_units\"], batch_size=1) # TODO\n", @@ -880,7 +1228,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 45, "metadata": { "id": "WvuwZBX5Ogfd" }, @@ -929,11 +1277,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 46, "metadata": { "id": "ktovv0RFhrkn" }, - "outputs": [], + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'Sequential' object has no attribute 'reset_states'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[46]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[33;03m'''TODO: Use the model and the function defined above to generate ABC format text of length 1000!\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[33;03m As you may notice, ABC files start with \"X\" - this may be a good start string.'''\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m generated_text = \u001b[43mgenerate_text\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstart_string\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mX\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgeneration_length\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m1000\u001b[39;49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# TODO\u001b[39;00m\n\u001b[32m 4\u001b[39m \u001b[38;5;66;03m# generated_text = generate_text('''TODO''', start_string=\"X\", generation_length=1000)\u001b[39;00m\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[45]\u001b[39m\u001b[32m, line 15\u001b[39m, in \u001b[36mgenerate_text\u001b[39m\u001b[34m(model, start_string, generation_length)\u001b[39m\n\u001b[32m 12\u001b[39m text_generated = []\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Here batch size == 1\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m15\u001b[39m \u001b[43mmodel\u001b[49m\u001b[43m.\u001b[49m\u001b[43mreset_states\u001b[49m()\n\u001b[32m 16\u001b[39m tqdm._instances.clear()\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m tqdm(\u001b[38;5;28mrange\u001b[39m(generation_length)):\n", + "\u001b[31mAttributeError\u001b[39m: 'Sequential' object has no attribute 'reset_states'" + ] + } + ], "source": [ "'''TODO: Use the model and the function defined above to generate ABC format text of length 1000!\n", " As you may notice, ABC files start with \"X\" - this may be a good start string.'''\n", @@ -956,11 +1317,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 47, "metadata": { "id": "LrOtG64bfLto" }, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'generated_text' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[47]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m### Play back generated songs ###\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m generated_songs = mdl.lab1.extract_song_snippet(\u001b[43mgenerated_text\u001b[49m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m i, song \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(generated_songs):\n\u001b[32m 6\u001b[39m \u001b[38;5;66;03m# Synthesize the waveform from a song\u001b[39;00m\n\u001b[32m 7\u001b[39m waveform = mdl.lab1.play_song(song)\n", + "\u001b[31mNameError\u001b[39m: name 'generated_text' is not defined" + ] + } + ], "source": [ "### Play back generated songs ###\n", "\n", @@ -1051,9 +1424,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.12.9" } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/lab1/solutions/tmp.abc b/lab1/solutions/tmp.abc new file mode 100644 index 00000000..575b4f3b --- /dev/null +++ b/lab1/solutions/tmp.abc @@ -0,0 +1,10 @@ +X:1 +T:Alexander's +Z: id:dc-hornpipe-1 +M:C| +L:1/8 +K:D Major +(3ABc|dAFA DFAd|fdcd FAdf|gfge fefd|(3efe (3dcB A2 (3ABc|! +dAFA DFAd|fdcd FAdf|gfge fefd|(3efe dc d2:|! +AG|FAdA FAdA|GBdB GBdB|Acec Acec|dfaf gecA|! +FAdA FAdA|GBdB GBdB|Aceg fefd|(3efe dc d2:|! \ No newline at end of file diff --git a/lab1/tmp.abc b/lab1/tmp.abc new file mode 100644 index 00000000..575b4f3b --- /dev/null +++ b/lab1/tmp.abc @@ -0,0 +1,10 @@ +X:1 +T:Alexander's +Z: id:dc-hornpipe-1 +M:C| +L:1/8 +K:D Major +(3ABc|dAFA DFAd|fdcd FAdf|gfge fefd|(3efe (3dcB A2 (3ABc|! +dAFA DFAd|fdcd FAdf|gfge fefd|(3efe dc d2:|! +AG|FAdA FAdA|GBdB GBdB|Acec Acec|dfaf gecA|! +FAdA FAdA|GBdB GBdB|Aceg fefd|(3efe dc d2:|! \ No newline at end of file diff --git a/lab2/PT_Part1_MNIST.ipynb b/lab2/PT_Part1_MNIST.ipynb index bcfae490..a0eab211 100644 --- a/lab2/PT_Part1_MNIST.ipynb +++ b/lab2/PT_Part1_MNIST.ipynb @@ -55,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "id": "RsGqx_ai_N8F" }, @@ -72,7 +72,7 @@ "from torchsummary import summary\n", "\n", "# MIT introduction to deep learning package\n", - "!pip install mitdeeplearning --quiet\n", + "#!pip install mitdeeplearning --quiet\n", "import mitdeeplearning as mdl\n", "\n", "# other packages\n", @@ -93,20 +93,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "id": "GSR_PAqjbzyZ" }, "outputs": [], "source": [ - "!pip install comet_ml > /dev/null 2>&1\n", + "#!pip install comet_ml > /dev/null 2>&1\n", "import comet_ml\n", "# TODO: ENTER YOUR API KEY HERE!!\n", - "COMET_API_KEY = \"\"\n", + "COMET_API_KEY = \"Xg2mJUP2iMIjlVOUSERvKB3IN\"\n", "\n", "# Check that we are using a GPU, if not switch runtimes\n", "# using Runtime > Change Runtime Type > GPU\n", - "assert torch.cuda.is_available(), \"Please enable GPU from runtime settings\"\n", + "#assert torch.cuda.is_available(), \"Please enable GPU from runtime settings\"\n", "assert COMET_API_KEY != \"\", \"Please insert your Comet API Key\"\n", "\n", "# Set GPU for computation\n", @@ -115,11 +115,38 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "id": "wGPDtVxvTtPk" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[1;38;5;214mCOMET WARNING:\u001b[0m comet_ml.init() is deprecated and will be removed soon. Please use comet_ml.login()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Please paste your Comet API key from https://www.comet.com/api/my/settings/\n", + "(api key may not show as you type)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[1;38;5;39mCOMET INFO:\u001b[0m Valid Comet API Key saved in C:\\Users\\USER\\.comet.config (set COMET_CONFIG to change where it is saved).\n", + "\u001b[1;38;5;214mCOMET WARNING:\u001b[0m To get all data logged automatically, import comet_ml before the following modules: keras, sklearn, tensorflow, torch.\n", + "\u001b[1;38;5;214mCOMET WARNING:\u001b[0m As you are running in a Jupyter environment, you will need to call `experiment.end()` when finished to ensure all metrics and code are logged before exiting.\n", + "\u001b[1;38;5;39mCOMET INFO:\u001b[0m Experiment is live on comet.com https://www.comet.com/code4geoai/6s191-lab2-part1-nn/e38f86aba0494e739cbbc84cc06bd771\n", + "\n" + ] + } + ], "source": [ "# start a first comet experiment for the first part of the lab\n", "comet_ml.init(project_name=\"6S191_lab2_part1_NN\")\n", @@ -139,11 +166,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "id": "G1Bryi5ssUNX" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 9.91M/9.91M [03:04<00:00, 53.6kB/s]\n", + "100%|██████████| 28.9k/28.9k [00:00<00:00, 48.2kB/s]\n", + "100%|██████████| 1.65M/1.65M [00:45<00:00, 36.4kB/s]\n", + "100%|██████████| 4.54k/4.54k [00:00<00:00, 6.66MB/s]\n" + ] + } + ], "source": [ "# Download and transform the MNIST dataset\n", "transform = transforms.Compose([\n", @@ -167,11 +205,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { "id": "LpxeLuaysUNX" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([1, 28, 28])\n", + "5\n" + ] + } + ], "source": [ "image, label = train_dataset[0]\n", "print(image.size()) # For a tensor: torch.Size([1, 28, 28])\n", @@ -196,7 +243,30 @@ "id": "bDBsR2lP_N8O", "scrolled": true }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'web': 'https://www.comet.com/api/image/download?imageId=5b0597948b994d0e83f53a1ed491c8d3&experimentKey=e38f86aba0494e739cbbc84cc06bd771',\n", + " 'api': 'https://www.comet.com/api/rest/v1/image/get-image?imageId=5b0597948b994d0e83f53a1ed491c8d3&experimentKey=e38f86aba0494e739cbbc84cc06bd771',\n", + " 'imageId': '5b0597948b994d0e83f53a1ed491c8d3'}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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GbVq1VL5hRdeULlp06Yq582b19sSAQCG9evXq7x3797ExxMmTFDHDhw44NV7ValSRWWzv65z585uX//AAw+onBb3TOKKBgAAAADrmGgAAAAAsI6JBgAAAADr6NH4Fz///LPKjzzyiMrXrl1TOUOGDG4zAt/Ro0dVbtSokcrm+v23337b5zXBt5o3b67yvn37VDb30ZgxY4bKefLk8U1h8BtmH8/8+fM9ev2ZM2dUjo6OVrlu3bqJj/v37+9ZcUh1ly9fVnn79u0qz5o1S+XFixerfP78+dt+72zZsqk8fvx4lfv27Xvb5/Y3Z8+eVXnDhg0qP/300yqfPHnylucy9zvylPn3osnsFzFVqlRJ5a+//lrlsLCw2yvMj/AXMQAAAADrmGgAAAAAsI6JBgAAAADr6NH4F6+99prKhw8fdqgS+Atz7fXBgwdVNvt24P8SEhJU/uCDD1Q2P+MGDRqoPHPmTJVz585trzg4wtwbxdz7xFzrbY6hGzduWK3niy++SHxsrvefO3eu1fdC8s6dO6ey+beCub7e7OFxuVwqm/0ByfULJO3DuHLlijoWFxenstn/k5aYvS29evVyqBLv7dq1S2Wz33P58uUq58+f3+c12cYVDQAAAADWMdEAAAAAYB1LpywoUqSIyu3bt3eoEtiyZs0alYcPH+72+eYSC/g/c2lBnz59VM6aNavK/fr1U5mlUoHP/EzNWxRfvXrVp+9v3gK5QIECKiddymUuoYB95jLp999/X2XzM/j111+9er9SpUqp/NBDD6ls3kY96d8aW7ZsUceyZ8+ucuPGjb2qLZC0aNFC5Xz58t3yuS+99JLKd999t1fvbd7edurUqSqbS6N27tzp9nw7duxQ2bzlMUunAAAAAECYaAAAAADwASYaAAAAAKyjR8OCggULqvzwww87VAlsiY+PV9m8jWWVKlVUNtfWwv/8/fffKjdr1szt85999lmVH3nkEes1wbc+/vhjlQcNGqSyuf7Z/HderFgxlZcuXapyz549Vd68ebPberp3766yeXvUxx9//JavrVGjhttzw3OnTp1S+bnnnlPZ7MlI7vazZs+F+beA+R1SuXJllXPkyOH2/EmZv4PM/pK77rorxecKNOYtYDt06KBycHBwqtVy7733us1HjhxRuWbNmiqbt8w2TZw4UWWzjywQcEUDAAAAgHVMNAAAAABY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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plt.figure(figsize=(10,10))\n", "random_inds = np.random.choice(60000,36)\n", @@ -204,7 +274,7 @@ " plt.subplot(6, 6, i + 1)\n", " plt.xticks([])\n", " plt.yticks([])\n", - " plt.grid(False)\n", + " plt.grid(True) # Original False\n", " image_ind = random_inds[i]\n", " image, label = train_dataset[image_ind]\n", " plt.imshow(image.squeeze(), cmap=plt.cm.binary)\n", @@ -252,9 +322,11 @@ "\n", " # '''TODO: Define the activation function for the first fully connected (Dense/Linear) layer.'''\n", " nn.Linear(28 * 28, 128),\n", - " '''TODO'''\n", - "\n", - " '''TODO: Define the second Linear layer to output the classification probabilities'''\n", + " #'''TODO'''\n", + " nn.ReLU(),\n", + " #'''TODO: Define the second Linear layer to output the classification probabilities'''\n", + " nn.Linear(128,10)\n", + " \n", " )\n", " return fc_model\n", "\n", @@ -303,7 +375,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "id": "7JhFJXjYsUNX" }, @@ -317,10 +389,10 @@ " self.fc1 = nn.Linear(28 * 28, 128)\n", "\n", " # '''TODO: Define the activation function for the first fully connected layer'''\n", - " self.relu = # TODO\n", + " self.relu = nn.ReLU() # TODO\n", "\n", " # '''TODO: Define the second Linear layer to output the classification probabilities'''\n", - " self.fc2 = # TODO\n", + " self.fc2 = nn.Linear(128,10) # TODO\n", "\n", " def forward(self, x):\n", " x = self.flatten(x)\n", @@ -328,6 +400,10 @@ "\n", " # '''TODO: Implement the rest of forward pass of the model using the layers you have defined above'''\n", " '''TODO'''\n", + " x= self.relu(x)\n", + " print(f\"x after relu: {x.shape}\") # Debugging line to check shape after ReLU\n", + " x = self.fc2(x)\n", + "\n", "\n", " return x\n", "\n", @@ -355,7 +431,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "id": "Lhan11blCaW7" }, @@ -996,7 +1072,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.7" + "version": "3.12.11" } }, "nbformat": 4,