DEV Community

ThatMLGuy
ThatMLGuy

Posted on

Introduction to Pytorch

What is Pytorch?

PyTorch is an open-source machine learning framework that lets you build models for applications such as computer vision and natural language processing

How to install Pytorch

Pytorch can be installed using pip via the command pip install torch or if you would like torch to utilize your GPU, you can follow the installation guide from Pytorch over here. To discover what CUDA version your GPU is utilizing, you can open the terminal (on windows) and use the command nvidia-smi and look at the version and choose that version at the Pytorch installation guide.

Tensors

The fundamental data type in pytorch is a tensor, it can be considered as a data type similar to numpy arrays. A list of values can be converted into a tensor by using torch.tensor(list_of_values), as shown below

list1 = [1,2,3]
list2 = [[1, 2, 3],
         [4, 5, 6],
         [7, 8, 9]]


tensor1  = torch.tensor(list1)
print(tensor1)
"""
Output:

tensor([1, 2, 3])
"""
tensor2 = torch.tensor(list2)
print(tensor2)
"""
Output:
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
"""


Enter fullscreen mode Exit fullscreen mode

You can perform mathematical operations on tensors as you do for numpy for example

tensor1 * tensor2

"""
tensor([[ 1,  4,  9],
        [ 4, 10, 18],
        [ 7, 16, 27]])
"""

tensor1 + tensor2

"""
tensor([[ 2,  4,  6],
        [ 5,  7,  9],
        [ 8, 10, 12]])
"""
Enter fullscreen mode Exit fullscreen mode

Dataset and DataLoader

Dataset allows you to establish how your data is loaded via __len__ and __getItem__. It prevents your entire data from being loaded, by loading them in samples.

DataLoader groups single samples into batches for efficient computation on the GPU, as well as it supports parallel data loading, shuffling and sampling.

To utilise the Dataset and Dataloader we import these functions from torch.utils.data. Here is an example of creating a custom Dataset and DataLoader.

class DATA:
    def __init__(self,x,y):
        self.x = torch.tensor(x)
        self.y = torch.tensor(y)

    def __len__(self):
        return len(self.x)

    def __getitem__(self, index):
        return self.x[index], self.y[index]


x = [[1,2,3],
     [4,5,6],
     [7,8,9]]

Y = [1,2,3]


dataset = DATA(x,Y)

loader = DataLoader(dataset, batch_size=2, shuffle=True)

for batch_inputs, batch_targets in loader:
    print(f"Inputs: {batch_inputs}, Targets: {batch_targets}")

"""
Output

Inputs: tensor([[7, 8, 9],
        [1, 2, 3]]), Targets: tensor([3, 1])
Inputs: tensor([[4, 5, 6]]), Targets: tensor([2])
"""
Enter fullscreen mode Exit fullscreen mode

Neural Networks

Neural networks in PyTorch are built using the torch.nn module. Each model inherits from nn.Module and defines two main parts:

  • Layers: defined in __init__()
  • Forward pass: defined in forward()
  • Backward pass: define in backward()

class ANN(nn.Module):
    def __init__(self):
        super().__init__()  # Uses the base Neural Network constructor from nn.Module
        self.layer1 = nn.Linear(3, 5)  # Creates the first layer: input of size 3, output of size 5
        self.layer2 = nn.Linear(5, 1)  # Creates the second layer: input of size 5, output of size 1
        self.optimizer = torch.optim.SGD(self.parameters(), lr=0.01)  # Defines the optimizer (Stochastic Gradient Descent) with learning rate 0.01
        self.loss_fn = nn.BCELoss()  # Defines the loss function (Binary Cross Entropy Loss) for binary classification

    def forward(self, x):
        # Defines how data flows through the network:
        x = self.layer1(x)  # Pass input through first layer (3 → 5)
        x = torch.relu(x)   # Apply ReLU activation to introduce non-linearity
        x = self.layer2(x)  # Pass through second layer (5 → 1)
        x = torch.sigmoid(x)  # Apply Sigmoid activation to output probabilities between 0 and 1
        return x  # Return final prediction

    def backward(self, loss):
        # Defines the backward propagation step:
        self.optimizer.zero_grad()  # Clears previously stored gradients
        loss.backward()  # Computes gradients using backpropagation
        self.optimizer.step()  # Updates model parameters (weights and biases)

Enter fullscreen mode Exit fullscreen mode

Code implementation


import torch
import torch.nn as nn
from torch.utils.data import DataLoader

class DATA:
    def __init__(self,x,y):
        self.x = torch.tensor(x)
        self.y = torch.tensor(y)

    def __len__(self):
        return len(self.x)

    def __getitem__(self, index):
        return self.x[index], self.y[index]

# Define your ANN class
class ANN(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1 = nn.Linear(3, 5)
        self.layer2 = nn.Linear(5, 1)
        self.optimizer = torch.optim.SGD(self.parameters(), lr=0.01)
        self.loss_fn = nn.BCELoss()

    def forward(self, x):
        x = self.layer1(x)
        x = torch.relu(x)
        x = self.layer2(x)
        x = torch.sigmoid(x)
        return x

    def backward(self, loss):
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()



torch.manual_seed(42)

X = torch.randn(100, 3)

y = (X.sum(dim=1) > 0).float().unsqueeze(1)

dataset = DATA(X,y)

loader = DataLoader(dataset, batch_size=2, shuffle=True)

model = ANN()
epochs = 50

for epoch in range(epochs):
    total_loss = 0
    correct = 0
    total = 0

    for batch_X, batch_y in loader:
        y_pred = model(batch_X)
        loss = model.loss_fn(y_pred, batch_y)
        model.backward(loss)
        total_loss += loss.item()

        predicted = (y_pred >= 0.5).float()
        correct += (predicted == batch_y).sum().item()
        total += batch_y.size(0)

    accuracy = correct / total

    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch+1}/{epochs}], Loss: {total_loss/len(loader):.4f}, Accuracy: {accuracy:.4f}")
Enter fullscreen mode Exit fullscreen mode

Top comments (0)