A genetic NN with PyTorch -- extracting output layer for the fitness function

I am trying to build my first genetic NN. I have to admit that I am not that proficient in ML and I probably should have started from something more basic, but here I am…

I have this simple CNN for MNIST, inspired by these. I want to extract weights from each forward-processed image-label pair so that then I could write a custom fitness function for the GNN.

import torch
from pylab import *

from torchvision import datasets
from torchvision.transforms import ToTensor

train_data = datasets.MNIST(
    root = 'data',
    train = True,                         
    transform = ToTensor(), 
    download = True,            
)
test_data = datasets.MNIST(
    root = 'data', 
    train = False, 
    transform = ToTensor()
)

from torch.utils.data import DataLoader
loaders = {
    'train' : torch.utils.data.DataLoader(train_data, 
                                          batch_size=1, 
                                          shuffle=True, 
                                          num_workers=1),
    
    'test'  : torch.utils.data.DataLoader(test_data, 
                                          batch_size=1, 
                                          shuffle=True, 
                                          num_workers=1),
}
loaders

import torch.nn as nn

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(         
            nn.Conv2d(
                in_channels=1,              
                out_channels=16,            
                kernel_size=5,              
                stride=1,                   
                padding=2,                  
            ),                              
            nn.ReLU(),                      
            nn.MaxPool2d(kernel_size=2),    
        )
        self.conv2 = nn.Sequential(         
            nn.Conv2d(16, 32, 5, 1, 2),     
            nn.ReLU(),                      
            nn.MaxPool2d(2),                
        )
        self.out = nn.Linear(32 * 7 * 7, 10)
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)
        output = self.out(x)
        return output, x

cnn = CNN()
activation = {}
def getActivation(name):
  # the hook signature
  def hook(model, input, output):
    activation[name] = output.detach()
  return hook

h = cnn.out.register_forward_hook(getActivation('out'))
from torch.autograd import Variable

num_epochs = 1
def train(num_epochs, cnn, loaders):

  cnn.train()

images, labels = next(iter(loaders['train']))

imshow(torch.squeeze(images))

print(labels)

b_x = Variable(images)   # batch x
b_y = Variable(labels)   # batch y
output = cnn(b_x)[0] 

print(activation['out'])
h.remove()

My question is how do the values in activation relate to the actual final accuracy, and how do one “reads” negative values? I was expecting ten tensor elements to be proportional to what the NN “thinks” of where the input image belongs to: if the largest float in activation tensor is the 4th element, then at this point CNN “thinks” that the input image is an integer “3”.

The logits (last layer model activations) for this kind of multiclass classification problem typically go through a softmax to convert the output to a probability distribution: Softmax — PyTorch 1.11.0 documentation.

In this case negative values just move the value of exp(x) closer to zero.

1 Like