En aquest tema, aprendrem a crear una xarxa neuronal simple utilitzant PyTorch. Aquest és un pas fonamental per a qualsevol persona que vulgui treballar amb xarxes neuronals, ja que proporciona una base sòlida per a la construcció de models més complexos en el futur.

Objectius

  • Entendre la construcció bàsica d'una xarxa neuronal en PyTorch.
  • Aprendre a definir les capes d'una xarxa neuronal.
  • Implementar una xarxa neuronal simple per a una tasca de classificació bàsica.

  1. Definició d'una Xarxa Neuronal

1.1 Importació de Llibreries Necessàries

Primer, importem les llibreries necessàries per a la construcció de la nostra xarxa neuronal.

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

1.2 Definició de la Classe de la Xarxa Neuronal

En PyTorch, les xarxes neuronals es defineixen com a subclasses de nn.Module. Aquí definirem una xarxa neuronal simple amb una capa d'entrada, una capa oculta i una capa de sortida.

class SimpleNeuralNetwork(nn.Module):
    def __init__(self):
        super(SimpleNeuralNetwork, self).__init__()
        self.fc1 = nn.Linear(784, 128)  # Capa d'entrada a capa oculta
        self.fc2 = nn.Linear(128, 10)   # Capa oculta a capa de sortida

    def forward(self, x):
        x = F.relu(self.fc1(x))  # Aplicació de la funció d'activació ReLU
        x = self.fc2(x)          # Sortida de la capa oculta a la capa de sortida
        return x

Explicació del Codi

  • nn.Linear(784, 128): Defineix una capa lineal (totalment connectada) amb 784 neurones d'entrada i 128 neurones de sortida.
  • F.relu(self.fc1(x)): Aplica la funció d'activació ReLU a la sortida de la primera capa.
  • self.fc2(x): Passa la sortida de la capa oculta a la capa de sortida.

  1. Entrenament de la Xarxa Neuronal

2.1 Preparació de les Dades

Per a aquest exemple, utilitzarem el conjunt de dades MNIST, que conté imatges de dígits escrits a mà.

from torchvision import datasets, transforms

# Transformació de les dades a tensors i normalització
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])

# Càrrega del conjunt de dades d'entrenament
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)

2.2 Definició de la Funció de Pèrdua i l'Optimitzador

model = SimpleNeuralNetwork()
criterion = nn.CrossEntropyLoss()  # Funció de pèrdua per a classificació
optimizer = optim.SGD(model.parameters(), lr=0.01)  # Optimitzador SGD amb taxa d'aprenentatge de 0.01

2.3 Bucle d'Entrenament

epochs = 5
for epoch in range(epochs):
    running_loss = 0.0
    for images, labels in trainloader:
        # Aplanar les imatges de 28x28 a 784
        images = images.view(images.shape[0], -1)
        
        # Netejar els gradients
        optimizer.zero_grad()
        
        # Passar les imatges pel model
        outputs = model(images)
        
        # Calcular la pèrdua
        loss = criterion(outputs, labels)
        
        # Retropropagació
        loss.backward()
        
        # Actualitzar els pesos
        optimizer.step()
        
        running_loss += loss.item()
    print(f"Epoch {epoch+1}, Loss: {running_loss/len(trainloader)}")

Explicació del Codi

  • images.view(images.shape[0], -1): Aplana les imatges de 28x28 píxels a vectors de 784 elements.
  • optimizer.zero_grad(): Neteja els gradients acumulats.
  • outputs = model(images): Passa les imatges pel model per obtenir les prediccions.
  • loss = criterion(outputs, labels): Calcula la pèrdua entre les prediccions i les etiquetes reals.
  • loss.backward(): Realitza la retropropagació per calcular els gradients.
  • optimizer.step(): Actualitza els pesos del model.

  1. Validació del Model

Després d'entrenar el model, és important validar-lo per assegurar-nos que generalitza bé a dades no vistes.

# Càrrega del conjunt de dades de prova
testset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)

correct = 0
total = 0
with torch.no_grad():
    for images, labels in testloader:
        images = images.view(images.shape[0], -1)
        outputs = model(images)
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(f'Accuracy: {100 * correct / total}%')

Explicació del Codi

  • torch.no_grad(): Desactiva el càlcul de gradients per a la validació.
  • torch.max(outputs, 1): Obté les prediccions del model.
  • correct += (predicted == labels).sum().item(): Compta el nombre de prediccions correctes.

Conclusió

En aquest tema, hem après a crear una xarxa neuronal simple utilitzant PyTorch. Hem definit les capes de la xarxa, hem entrenat el model amb el conjunt de dades MNIST i hem validat la seva precisió. Aquest coneixement és fonamental per a la construcció de models més complexos i avançats en el futur.

Exercici Pràctic

Exercici: Modifica la xarxa neuronal per afegir una segona capa oculta amb 64 neurones. Entrena el model de nou i compara la precisió amb la xarxa original.

Solució:

class ModifiedNeuralNetwork(nn.Module):
    def __init__(self):
        super(ModifiedNeuralNetwork, self).__init__()
        self.fc1 = nn.Linear(784, 128)
        self.fc2 = nn.Linear(128, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

model = ModifiedNeuralNetwork()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# Entrenament i validació segueixen el mateix procés que abans

Aquest exercici ajuda a comprendre com afegir capes addicionals a una xarxa neuronal i com això pot afectar el rendiment del model.

© Copyright 2024. Tots els drets reservats