diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d583158 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +data/ +runs/ \ No newline at end of file diff --git a/loss.png b/loss.png new file mode 100644 index 0000000..7b69d62 Binary files /dev/null and b/loss.png differ diff --git a/main.py b/main.py index dfe56fe..db0841d 100644 --- a/main.py +++ b/main.py @@ -14,4 +14,122 @@ import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.utils.data import DataLoader +from torchvision import datasets +from torchvision.transforms import ToTensor + +from torch.utils.tensorboard import SummaryWriter + # Your working code here + +training_data = datasets.CIFAR10( + root="data", + train=True, + download=True, + transform=ToTensor(), +) + +test_data = datasets.CIFAR10( + root="data", + train=False, + download=True, + transform=ToTensor(), +) + + +batch_size = 64 + +# Create data loaders. +train_dataloader = DataLoader(training_data, batch_size=batch_size) +test_dataloader = DataLoader(test_data, batch_size=batch_size) + +for X, y in test_dataloader: + print(f"Shape of X [N, C, H, W]: {X.shape}") + print(f"Shape of y: {y.shape} {y.dtype}") + break + +# Get cpu or gpu device for training. +device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" +print(f"Using {device} device") + +# Define model +class NeuralNetwork(nn.Module): + def __init__(self): + super().__init__() + self.conv1 = nn.Conv2d(3, 6, 5) + self.pool = nn.MaxPool2d(2, 2) + self.conv2 = nn.Conv2d(6, 16, 5) + self.fc1 = nn.Linear(16 * 5 * 5, 120) + self.fc2 = nn.Linear(120, 84) + self.fc3 = nn.Linear(84, 10) + + def forward(self, x): + x = self.pool(F.relu(self.conv1(x))) + x = self.pool(F.relu(self.conv2(x))) + x = torch.flatten(x, 1) # flatten all dimensions except batch + x = F.relu(self.fc1(x)) + x = F.relu(self.fc2(x)) + x = self.fc3(x) + return x + +model = NeuralNetwork().to(device) +print(model) + +loss_fn = nn.CrossEntropyLoss() +optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9) + +writer = SummaryWriter() + +def train(dataloader, model, loss_fn, optimizer): + size = len(dataloader.dataset) + model.train() + losses = [] + for batch, (X, y) in enumerate(dataloader): + X, y = X.to(device), y.to(device) + + # Compute prediction error + pred = model(X) + loss = loss_fn(pred, y) + + # Backpropagation + optimizer.zero_grad() + loss.backward() + optimizer.step() + + if batch % 100 == 0: + loss, current = loss.item(), batch * len(X) + losses.append(loss) + print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]") + return np.mean(losses) + +def test(dataloader, model, loss_fn): + size = len(dataloader.dataset) + num_batches = len(dataloader) + model.eval() + test_loss, correct = 0, 0 + with torch.no_grad(): + for X, y in dataloader: + X, y = X.to(device), y.to(device) + pred = model(X) + test_loss += loss_fn(pred, y).item() + correct += (pred.argmax(1) == y).type(torch.float).sum().item() + test_loss /= num_batches + correct /= size + print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n") + return test_loss + +epochs = 5 +for t in range(epochs): + print(f"Epoch {t+1}\n-------------------------------") + training_loss = train(train_dataloader, model, loss_fn, optimizer) + testing_loss = test(test_dataloader, model, loss_fn) + + writer.add_scalar("Loss/train", training_loss, t) + writer.add_scalar("Loss/test", testing_loss, t) + +writer.close () + +print("Done!") \ No newline at end of file