1
0
Fork 0

Compare commits

...

3 Commits

4 changed files with 479 additions and 3 deletions

View File

@ -0,0 +1,398 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Neural networks comprise of layers/modules that perform operations on data. The torch.nn namespace provides all the building blocks you need to build your own neural network. Every module in PyTorch subclasses the nn.Module. A neural network is a module itself that consists of other modules (layers). This nested structure allows for building and managing complex architectures easily."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import torch\n",
"from torch import nn\n",
"from torch.utils.data import DataLoader\n",
"from torchvision import datasets, transforms"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"We want to be able to train our model on a hardware accelerator like the GPU, if it is available. Lets check to see if torch.cuda is available, else we continue to use the CPU.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using cuda device\n"
]
}
],
"source": [
"device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
"print(f\"Using {device} device\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"We define our neural network by subclassing nn.Module, and initialize the neural network layers in __init__. Every nn.Module subclass implements the operations on input data in the forward method."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class NeuralNetwork(nn.Module):\n",
" def __init__(self):\n",
" super().__init__()\n",
" self.flatten = nn.Flatten()\n",
" self.linear_relu_stack = nn.Sequential(\n",
" nn.Linear(28*28, 512),\n",
" nn.ReLU(),\n",
" nn.Linear(512,512),\n",
" nn.ReLU(),\n",
" nn.Linear(512,10)\n",
" )\n",
"\n",
" def forward(self, x):\n",
" x = self.flatten(x)\n",
" logits = self.linear_relu_stack(x)\n",
" return logits"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"NeuralNetwork(\n",
" (flatten): Flatten(start_dim=1, end_dim=-1)\n",
" (linear_relu_stack): Sequential(\n",
" (0): Linear(in_features=784, out_features=512, bias=True)\n",
" (1): ReLU()\n",
" (2): Linear(in_features=512, out_features=512, bias=True)\n",
" (3): ReLU()\n",
" (4): Linear(in_features=512, out_features=10, bias=True)\n",
" )\n",
")\n"
]
}
],
"source": [
"# Create an instance of NeuralNetwork , and move it to the device \n",
"model = NeuralNetwork().to(device)\n",
"# Print its structure\n",
"print(model)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"To use the model, we pass it the input data. This executes the models forward, along with some background operations. Do not call model.forward() directly!\n",
"\n",
"Calling the model on the input returns a 2-dimensional tensor with dim=0 corresponding to each output of 10 raw predicted values for each class, and dim=1 corresponding to the individual values of each output. We get the prediction probabilities by passing it through an instance of the nn.Softmax module."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Predicted class: tensor([9], device='cuda:0')\n"
]
}
],
"source": [
"X = torch.rand(1,28,28, device=device)\n",
"logits = model(X)\n",
"pred_probab = nn.Softmax(dim=1)(logits)\n",
"y_pred = pred_probab.argmax(1)\n",
"print(f\"Predicted class: {y_pred}\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets break down the layers in the FashionMNIST model. To illustrate it, we will take a sample minibatch of 3 images of size 28x28 and see what happens to it as we pass it through the network."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"torch.Size([3, 28, 28])\n"
]
}
],
"source": [
"input_image = torch.rand(3,28,28)\n",
"print(input_image.size())"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"We initialize the nn.Flatten layer to convert each 2D 28x28 image into a contiguous array of 784 pixel values ( the minibatch dimension (at dim=0) is maintained)."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"torch.Size([3, 784])\n"
]
}
],
"source": [
"flatten = nn.Flatten()\n",
"flat_image = flatten(input_image)\n",
"print(flat_image.size())"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"The linear layer is a module that applies a linear transformation on the input using its stored weights and biases."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"torch.Size([3, 20])\n"
]
}
],
"source": [
"layer1 = nn.Linear(in_features=28*28, out_features=20)\n",
"hidden1 = layer1(flat_image)\n",
"print(hidden1.size())"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Non-linear activations are what create the complex mappings between the models inputs and outputs. They are applied after linear transformations to introduce nonlinearity, helping neural networks learn a wide variety of phenomena.\n",
"\n",
"In this model, we use nn.ReLU between our linear layers, but theres other activations to introduce non-linearity in your model."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Before ReLU: tensor([[ 0.5346, -0.0702, 0.3048, -0.2614, -0.5357, 0.2483, -0.1851, 0.2514,\n",
" 0.6062, -0.5254, 0.5784, 0.0366, 0.5520, 0.4593, -0.3674, -0.0193,\n",
" 0.1552, 0.5918, 0.0862, 0.0201],\n",
" [ 0.0443, -0.2323, 0.2446, 0.3351, -0.3610, 0.3804, -0.2164, 0.3526,\n",
" 0.2713, -0.4427, 0.3077, -0.2736, 0.9974, 0.2289, -0.1414, 0.0126,\n",
" 0.4709, 0.0131, -0.2745, 0.6273],\n",
" [-0.0822, -0.1703, 0.6460, -0.1720, -0.5338, 0.1044, -0.3253, 0.4759,\n",
" 0.7618, -0.7128, 0.5533, 0.0803, 0.7058, 0.8018, -0.3034, 0.1789,\n",
" 0.1912, 0.1924, 0.0492, 0.6753]], grad_fn=<AddmmBackward0>)\n",
"\n",
"\n",
"After ReLU: tensor([[0.5346, 0.0000, 0.3048, 0.0000, 0.0000, 0.2483, 0.0000, 0.2514, 0.6062,\n",
" 0.0000, 0.5784, 0.0366, 0.5520, 0.4593, 0.0000, 0.0000, 0.1552, 0.5918,\n",
" 0.0862, 0.0201],\n",
" [0.0443, 0.0000, 0.2446, 0.3351, 0.0000, 0.3804, 0.0000, 0.3526, 0.2713,\n",
" 0.0000, 0.3077, 0.0000, 0.9974, 0.2289, 0.0000, 0.0126, 0.4709, 0.0131,\n",
" 0.0000, 0.6273],\n",
" [0.0000, 0.0000, 0.6460, 0.0000, 0.0000, 0.1044, 0.0000, 0.4759, 0.7618,\n",
" 0.0000, 0.5533, 0.0803, 0.7058, 0.8018, 0.0000, 0.1789, 0.1912, 0.1924,\n",
" 0.0492, 0.6753]], grad_fn=<ReluBackward0>)\n"
]
}
],
"source": [
"print(f\"Before ReLU: {hidden1}\\n\\n\")\n",
"hidden1 = nn.ReLU()(hidden1)\n",
"print(f\"After ReLU: {hidden1}\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"nn.Sequential is an ordered container of modules. The data is passed through all the modules in the same order as defined. You can use sequential containers to put together a quick network like seq_modules."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"seq_modules = nn.Sequential(\n",
" flatten,\n",
" layer1,\n",
" nn.ReLU(),\n",
" nn.Linear(20,10)\n",
")\n",
"\n",
"input_image = torch.rand(3,28,28)\n",
"logits = seq_modules(input_image)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"The last linear layer of the neural network returns logits - raw values in [-infty, infty] - which are passed to the nn.Softmax module. The logits are scaled to values [0, 1] representing the models predicted probabilities for each class. dim parameter indicates the dimension along which the values must sum to 1."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"softmax = nn.Softmax(dim=1)\n",
"pred_probab = softmax(logits)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Many layers inside a neural network are parameterized, i.e. have associated weights and biases that are optimized during training. Subclassing nn.Module automatically tracks all fields defined inside your model object, and makes all parameters accessible using your models parameters() or named_parameters() methods."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model Structure: NeuralNetwork(\n",
" (flatten): Flatten(start_dim=1, end_dim=-1)\n",
" (linear_relu_stack): Sequential(\n",
" (0): Linear(in_features=784, out_features=512, bias=True)\n",
" (1): ReLU()\n",
" (2): Linear(in_features=512, out_features=512, bias=True)\n",
" (3): ReLU()\n",
" (4): Linear(in_features=512, out_features=10, bias=True)\n",
" )\n",
")\n",
"\n",
"\n",
"Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values: tensor([[ 0.0008, -0.0301, 0.0043, ..., -0.0193, 0.0307, 0.0316],\n",
" [ 0.0214, -0.0338, 0.0241, ..., 0.0107, -0.0228, -0.0153]],\n",
" device='cuda:0', grad_fn=<SliceBackward0>)\n",
"\n",
"Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values: tensor([0.0091, 0.0180], device='cuda:0', grad_fn=<SliceBackward0>)\n",
"\n",
"Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values: tensor([[ 0.0204, 0.0072, -0.0056, ..., 0.0131, 0.0127, 0.0308],\n",
" [ 0.0283, 0.0042, -0.0219, ..., -0.0164, 0.0343, 0.0426]],\n",
" device='cuda:0', grad_fn=<SliceBackward0>)\n",
"\n",
"Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values: tensor([ 0.0314, -0.0035], device='cuda:0', grad_fn=<SliceBackward0>)\n",
"\n",
"Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values: tensor([[ 0.0233, 0.0182, -0.0222, ..., 0.0058, -0.0052, -0.0185],\n",
" [-0.0088, -0.0054, -0.0018, ..., -0.0288, 0.0305, 0.0189]],\n",
" device='cuda:0', grad_fn=<SliceBackward0>)\n",
"\n",
"Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values: tensor([-0.0093, 0.0282], device='cuda:0', grad_fn=<SliceBackward0>)\n",
"\n"
]
}
],
"source": [
"print(f\"Model Structure: {model}\\n\\n\")\n",
"\n",
"for name, param in model.named_parameters():\n",
" print(f\"Layer: {name} | Size: {param.size()} | Values: {param[:2]}\\n\")\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.10.10 (tags/v3.10.10:aad5f6a, Feb 7 2023, 17:20:36) [MSC v.1929 64 bit (AMD64)]"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "4944a85e4459d92b06dc1c94852b4e8e8e6d0531f16bd543c843a0ca37cdfcdb"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -284,7 +284,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "venv",
"display_name": ".venv",
"language": "python",
"name": "python3"
},
@ -298,12 +298,12 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.10"
"version": "3.10.10 (tags/v3.10.10:aad5f6a, Feb 7 2023, 17:20:36) [MSC v.1929 64 bit (AMD64)]"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "f4b5116e1c1eac4da82e4f519e811a9a213a412fad4fdb2c86d0bd3e5d22b3b4"
"hash": "4944a85e4459d92b06dc1c94852b4e8e8e6d0531f16bd543c843a0ca37cdfcdb"
}
}
},

View File

@ -0,0 +1,78 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Data does not always come in its final processed form that is required for training machine learning algorithms. We use transforms to perform some manipulation of the data and make it suitable for training.\n",
"\n",
"All TorchVision datasets have two parameters -transform to modify the features and target_transform to modify the labels - that accept callables containing the transformation logic. The torchvision.transforms module offers several commonly-used transforms out of the box.\n",
"\n",
"The FashionMNIST features are in PIL Image format, and the labels are integers. For training, we need the features as normalized tensors, and the labels as one-hot encoded tensors. To make these transformations, we use ToTensor and Lambda"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"from torchvision import datasets\n",
"from torchvision.transforms import ToTensor, Lambda\n",
"\n",
"ds = datasets.FashionMNIST(\n",
" root=\"data\",\n",
" train=True,\n",
" download=True,\n",
" transform=ToTensor(),\n",
" target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y),value=1))\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"ToTensor converts a PIL image or NumPy ndarray into a FloatTensor. and scales the images pixel intensity values in the range [0., 1.]"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Lambda transforms apply any user-defined lambda function. Here, we define a function to turn the integer into a one-hot encoded tensor. It first creates a zero tensor of size 10 (the number of labels in our dataset) and calls scatter_ which assigns a value=1 on the index as given by the label y."
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.10.10"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "4944a85e4459d92b06dc1c94852b4e8e8e6d0531f16bd543c843a0ca37cdfcdb"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}