#!/usr/bin/env python # coding: utf-8 # Deep Learning Models -- A collection of various deep learning architectures, models, and tips for TensorFlow and PyTorch in Jupyter Notebooks. # - Author: Sebastian Raschka # - GitHub Repository: https://github.com/rasbt/deeplearning-models # In[1]: get_ipython().run_line_magic('load_ext', 'watermark') get_ipython().run_line_magic('watermark', "-a 'Sebastian Raschka' -v -p torch") # - Runs on CPU or GPU (if available) # # Model Zoo -- Multilayer Perceptron with Sequential Wrapper # ## Imports # In[2]: import time import numpy as np from torchvision import datasets from torchvision import transforms from torch.utils.data import DataLoader import torch.nn.functional as F import torch if torch.cuda.is_available(): torch.backends.cudnn.deterministic = True # ## Settings and Dataset # In[3]: ########################## ### SETTINGS ########################## # Device device = torch.device("cuda:3" if torch.cuda.is_available() else "cpu") # Hyperparameters random_seed = 1 learning_rate = 0.1 num_epochs = 10 batch_size = 64 # Architecture num_features = 784 num_hidden_1 = 128 num_hidden_2 = 256 num_classes = 10 ########################## ### MNIST DATASET ########################## # Note transforms.ToTensor() scales input images # to 0-1 range train_dataset = datasets.MNIST(root='data', train=True, transform=transforms.ToTensor(), download=True) test_dataset = datasets.MNIST(root='data', train=False, transform=transforms.ToTensor()) train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False) # Checking the dataset for images, labels in train_loader: print('Image batch dimensions:', images.shape) print('Image label dimensions:', labels.shape) break # In[4]: ########################## ### MODEL ########################## class MultilayerPerceptron(torch.nn.Module): def __init__(self, num_features, num_classes): super(MultilayerPerceptron, self).__init__() self.net = torch.nn.Sequential( torch.nn.Linear(num_features, num_hidden_1), torch.nn.ReLU(inplace=True), torch.nn.Linear(num_hidden_1, num_hidden_2), torch.nn.ReLU(inplace=True), torch.nn.Linear(num_hidden_2, num_classes) ) def forward(self, x): logits = self.net(x) probas = F.log_softmax(logits, dim=1) return logits, probas torch.manual_seed(random_seed) model = MultilayerPerceptron(num_features=num_features, num_classes=num_classes) model = model.to(device) optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) # In[5]: def compute_accuracy(net, data_loader): net.eval() correct_pred, num_examples = 0, 0 with torch.no_grad(): for features, targets in data_loader: features = features.view(-1, 28*28).to(device) targets = targets.to(device) logits, probas = net(features) _, predicted_labels = torch.max(probas, 1) num_examples += targets.size(0) correct_pred += (predicted_labels == targets).sum() return correct_pred.float()/num_examples * 100 start_time = time.time() for epoch in range(num_epochs): model.train() for batch_idx, (features, targets) in enumerate(train_loader): features = features.view(-1, 28*28).to(device) targets = targets.to(device) ### FORWARD AND BACK PROP logits, probas = model(features) cost = F.cross_entropy(logits, targets) optimizer.zero_grad() cost.backward() ### UPDATE MODEL PARAMETERS optimizer.step() ### LOGGING if not batch_idx % 50: print ('Epoch: %03d/%03d | Batch %03d/%03d | Cost: %.4f' %(epoch+1, num_epochs, batch_idx, len(train_loader), cost)) with torch.set_grad_enabled(False): print('Epoch: %03d/%03d training accuracy: %.2f%%' % ( epoch+1, num_epochs, compute_accuracy(model, train_loader))) print('Time elapsed: %.2f min' % ((time.time() - start_time)/60)) print('Total Training Time: %.2f min' % ((time.time() - start_time)/60)) # In[6]: print('Test accuracy: %.2f%%' % (compute_accuracy(model, test_loader))) # ## Accessing Intermediate Results via Hooks # One disadvantage of the Sequential wrapper is that we cannot readily access (or "print") intermediate values. However, we can use custom hooks for that. For instance, the order of operations in our Sequential wrapper is as follows: # In[7]: model.net # If we want to get the output from the 2nd layer during the forward pass, we can register a hook as follows: # In[8]: outputs = [] def hook(module, input, output): outputs.append(output) model.net[2].register_forward_hook(hook) # Now, if we call the model on some inputs, it will save the intermediate results in the "outputs" list: # In[9]: _ = model(features) print(outputs) # In[10]: get_ipython().run_line_magic('watermark', '-iv')