""" Shows a small example of how to use transformations (perhaps unecessarily many) on CIFAR10 dataset and training on a small CNN toy network. Video explanation: https://youtu.be/Zvd276j9sZ8 Got any questions leave a comment I'm pretty good at responding on youtube Programmed by Aladdin Persson * 2020-04-09 Initial coding """ # Imports import torch import torch.nn as nn # All neural network modules, nn.Linear, nn.Conv2d, BatchNorm, Loss functions import torch.optim as optim # For all Optimization algorithms, SGD, Adam, etc. import torch.nn.functional as F # All functions that don't have any parameters from torch.utils.data import ( DataLoader, ) # Gives easier dataset managment and creates mini batches import torchvision.datasets as datasets # Has standard datasets we can import in a nice way import torchvision.transforms as transforms # Transformations we can perform on our dataset # Simple CNN class CNN(nn.Module): def __init__(self, in_channels, num_classes): super(CNN, self).__init__() self.conv1 = nn.Conv2d( in_channels=in_channels, out_channels=8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), ) self.pool = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2)) self.conv2 = nn.Conv2d( in_channels=8, out_channels=16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), ) self.fc1 = nn.Linear(16 * 8 * 8, num_classes) def forward(self, x): x = F.relu(self.conv1(x)) x = self.pool(x) x = F.relu(self.conv2(x)) x = self.pool(x) x = x.reshape(x.shape[0], -1) x = self.fc1(x) return x # Set device device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # Hyperparameters learning_rate = 1e-4 batch_size = 64 num_epochs = 5 # Load pretrain model & modify it model = CNN(in_channels=3, num_classes=10) model.classifier = nn.Sequential(nn.Linear(512, 100), nn.ReLU(), nn.Linear(100, 10)) model.to(device) # Load Data my_transforms = transforms.Compose( [ # Compose makes it possible to have many transforms transforms.Resize((36, 36)), # Resizes (32,32) to (36,36) transforms.RandomCrop((32, 32)), # Takes a random (32,32) crop transforms.ColorJitter(brightness=0.5), # Change brightness of image transforms.RandomRotation( degrees=45 ), # Perhaps a random rotation from -45 to 45 degrees transforms.RandomHorizontalFlip( p=0.5 ), # Flips the image horizontally with probability 0.5 transforms.RandomVerticalFlip( p=0.05 ), # Flips image vertically with probability 0.05 transforms.RandomGrayscale(p=0.2), # Converts to grayscale with probability 0.2 transforms.ToTensor(), # Finally converts PIL image to tensor so we can train w. pytorch transforms.Normalize( mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5] ), # Note: these values aren't optimal ] ) train_dataset = datasets.CIFAR10( root="dataset/", train=True, transform=my_transforms, download=True ) train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) # Loss and optimizer criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # Train Network for epoch in range(num_epochs): losses = [] for batch_idx, (data, targets) in enumerate(train_loader): # Get data to cuda if possible data = data.to(device=device) targets = targets.to(device=device) # forward scores = model(data) loss = criterion(scores, targets) losses.append(loss.item()) # backward optimizer.zero_grad() loss.backward() # gradient descent or adam step optimizer.step() print(f"Cost at epoch {epoch} is {sum(losses)/len(losses):.5f}") # Check accuracy on training & test to see how good our model def check_accuracy(loader, model): if loader.dataset.train: print("Checking accuracy on training data") else: print("Checking accuracy on test data") num_correct = 0 num_samples = 0 model.eval() with torch.no_grad(): for x, y in loader: x = x.to(device=device) y = y.to(device=device) scores = model(x) _, predictions = scores.max(1) num_correct += (predictions == y).sum() num_samples += predictions.size(0) print( f"Got {num_correct} / {num_samples} with accuracy {float(num_correct)/float(num_samples)*100:.2f}" ) model.train() check_accuracy(train_loader, model)