import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
# --------------------------------------------------
# 1. Select device
# --------------------------------------------------
device = torch.device(
"cuda" if torch.cuda.is_available() else "cpu"
)
print("Using:", device)
# --------------------------------------------------
# 2. Image transformation
# --------------------------------------------------
transform = transforms.ToTensor()
# --------------------------------------------------
# 3. Load training dataset
# --------------------------------------------------
train_dataset = datasets.MNIST(
root="./data",
train=True,
download=True,
transform=transform
)
# --------------------------------------------------
# 4. Load test dataset
# --------------------------------------------------
test_dataset = datasets.MNIST(
root="./data",
train=False,
download=True,
transform=transform
)
# --------------------------------------------------
# 5. Create DataLoaders
# --------------------------------------------------
train_loader = DataLoader(
train_dataset,
batch_size=64,
shuffle=True
)
test_loader = DataLoader(
test_dataset,
batch_size=64,
shuffle=False
)
# --------------------------------------------------
# 6. Check dataset
# --------------------------------------------------
print("Training Samples:", len(train_dataset))
print("Test Samples:", len(test_dataset))
# Check one image
image, label = train_dataset[0]
print("Image Shape:", image.shape)
print("Label:", label)
# --------------------------------------------------
# 7. Define neural network
# --------------------------------------------------
class SimpleNN(nn.Module):
def __init__(self):
super().__init__()
# 28 x 28 = 784 input pixels
self.fc1 = nn.Linear(28 * 28, 128)
# 128 hidden neurons -> 10 output classes
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
# Flatten image
x = x.view(x.size(0), -1)
# First layer
x = self.fc1(x)
# Activation function
x = torch.relu(x)
# Output layer
x = self.fc2(x)
return x
# --------------------------------------------------
# 8. Create model
# --------------------------------------------------
model = SimpleNN().to(device)
print(model)
# --------------------------------------------------
# 9. Loss function
# --------------------------------------------------
criterion = nn.CrossEntropyLoss()
# --------------------------------------------------
# 10. Optimizer
# --------------------------------------------------
optimizer = optim.Adam(
model.parameters(),
lr=0.001
)
# --------------------------------------------------
# 11. Training
# --------------------------------------------------
epochs = 10
for epoch in range(epochs):
model.train()
total_loss = 0
for images, labels in train_loader:
# Move data to CPU/GPU
images = images.to(device)
labels = labels.to(device)
# Clear old gradients
optimizer.zero_grad()
# Forward pass
outputs = model(images)
# Calculate loss
loss = criterion(outputs, labels)
# Backpropagation
loss.backward()
# Update weights
optimizer.step()
# Add batch loss
total_loss += loss.item()
# Average loss
average_loss = total_loss / len(train_loader)
print(
f"Epoch {epoch + 1}/{epochs}, "
f"Loss: {average_loss:.4f}"
)
# --------------------------------------------------
# 12. Evaluation
# --------------------------------------------------
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images = images.to(device)
labels = labels.to(device)
# Get predictions
outputs = model(images)
# Get class with highest score
_, predicted = torch.max(outputs, 1)
# Count samples
total += labels.size(0)
# Count correct predictions
correct += (predicted == labels).sum().item()
# --------------------------------------------------
# 13. Calculate accuracy
# --------------------------------------------------
accuracy = 100 * correct / total
print(f"Test Accuracy: {accuracy:.2f}%")