0
$\begingroup$

I'm building a CNN neural network with Pytorch. Although the model accuracy is 85.6%, after getting image probabilities with torch.exp(output) and getting the top probabilities, the top 5 probabilities are almost the same- the image has 5 classes with 100% probability. Even if this problem is solved, the conversion to NumPy array divides the tensor array by 100 which drastically impacted on the image probability. WHAT IS HAPPENING? Here is my code Importing data and applying transformation

data_dir = 'flowers'
train_dir = data_dir + '/train'
valid_dir = data_dir + '/valid'
test_dir = data_dir + '/test'

data_transforms = {'train_transforms':transforms.Compose([
    transforms.RandomRotation(30),
    transforms.RandomHorizontalFlip(),
    transforms.RandomResizedCrop(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406],
                         [0.229, 0.224, 0.225])
]),
                  'valid_test_transforms':transforms.Compose([
                      transforms.Resize(225),
                      transforms.CenterCrop(224),
                      transforms.ToTensor(),
                      transforms.Normalize([0.485, 0.456, 0.406],
                                           [0.229, 0.224, 0.225])
                  ])}

# TODO: Load the datasets with ImageFolder
image_datasets = {'train_data':datasets.ImageFolder(train_dir, transform= data_transforms['train_transforms']),
                  'valid_data':datasets.ImageFolder(valid_dir, transform= data_transforms['valid_test_transforms']),
                  'test_data':datasets.ImageFolder(test_dir, transform= data_transforms['valid_test_transforms'])}

# TODO: Using the image datasets and the trainforms, define the dataloaders
dataloaders = {'train_loader':torch.utils.data.DataLoader(image_datasets['train_data'], batch_size= 64, shuffle= True),
               'valid_loader':torch.utils.data.DataLoader(image_datasets['valid_data'], batch_size= 32),
               'test_loader':torch.utils.data.DataLoader(image_datasets['test_data'], batch_size= 32)}

importing a pre-trained network

model= models.vgg16(pretrained=True) 
# freezing model's parameters
for paramerter in model.parameters():
    paramerter.requires_grad= False

building the new classifier

classifier= nn.Sequential(nn.Linear(25088,4096),
                          nn.ReLU(),
                          nn.Dropout(p=0.3),
                          nn.Linear(4096, 4096),
                          nn.ReLU(),
                          nn.Dropout(p=0.3),
                          nn.Linear(4096,1000),
                          nn.ReLU(),
                          nn.Dropout(0.3),
                          nn.Linear(1000,102),
                          nn.LogSoftmax(dim=1))
model.classifier= classifier

passing the model to GPU

device= torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model= model.to(device)

initializing loss function and optimizer

criterion= nn.NLLLoss()
optimizer= optim.Adam(model.classifier.parameters(), lr=0.001)
epochs= 12
steps= 0
training_loss= 0
print_every= 5

Training and testing the network

from workspace_utils import active_session
with active_session():
    for epoch in range(epochs):
        #train the model
        for images, labels in dataloaders['train_loader']:
            steps += 1
            images, labels= images.to(device), labels.to(device) #passing images & labels to GPU
            optimizer.zero_grad() #clears the last gradients from the last step
            train_output= model.forward(images) #forwarding images to the model
            tr_loss= criterion(train_output, labels) #calculating the error function
            tr_loss.backward() #computes the derivatives of the loss using backprobagation
            optimizer.step() #telling the optimizer to take a step based on the gradients of the parameters
            training_loss += tr_loss.item() #calculating the training loss
            if steps % print_every == 0:
                testing_loss= 0
                accuracy= 0
                model.eval()
                with torch.no_grad():
                        #test the model
                        for images, labels in dataloaders['valid_loader']:
                            images, labels= images.to(device), labels.to(device)
                            test_output= model.forward(images)
                            test_loss= criterion(test_output, labels)
                            testing_loss += test_loss.item()
                            #getting accuracy
                            ps= torch.exp(test_output)
                            top_p, top_class= ps.topk(1, dim=1)
                            equal= top_class == labels.view(*top_class.shape)
                            accuracy += torch.mean(equal.type(torch.FloatTensor)).item()
                print(f"Epoch {epoch+1}/{epochs}.. "
                      f"Train loss: {training_loss/steps:.3f}.. "
                      f"Test loss: {testing_loss/len(dataloaders['valid_loader']):.3f}.."
                      f"Test accuracy: {accuracy/len(dataloaders['valid_loader']):.3f}")
                model.train()

saving the model

checkpoint={
    'architecture': 'vgg16',
    'state_dict': model.state_dict(),
    'optimizer': optimizer.state_dict(),
    'classifier': model.classifier,
    'class_label': image_datasets['train_data'].class_to_idx,
    'input_size': 25088,
    'output_size': 102,
    'learning_rate': 0.001,
    'batch_size': 64,
    'epochs': epochs + 1
}
torch.save(checkpoint, 'checkpoint.pth')

loading the model

def load_checkpoint(file):
    checkpoint= torch.load(file)
    model= getattr(torchvision.models, checkpoint['architecture'])(pretrained=True) #it returns the value of the named attribute of an object
    model.classifier = checkpoint['classifier']
    model.epochs = checkpoint['epochs']
    model.load_state_dict(checkpoint['state_dict'])
    model.class_to_idx = checkpoint['class_label']
    optimizer.load_state_dict(checkpoint['optimizer'])
    learning_rate = checkpoint['learning_rate']
    return model
model= load_checkpoint('checkpoint.pth')

image preprocessing

def process_image(image):
    ''' Scales, crops, and normalizes a PIL image for a PyTorch model,
        returns an Numpy array
    '''

    # TODO: Process a PIL image for use in a PyTorch model
    pic= Image.open(image)
    transform = transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406],
                             [0.229, 0.224, 0.225])
    ])
    pic_trnasform= transform(pic)
    pic_to_array= np.array(pic_trnasform)
    return pic_to_array

predicting image class

def predict(image_path, model, topk=5):
    ''' Predict the class (or classes) of an image using a trained deep learning model.
    '''

    # TODO: Implement the code to predict the class from an image file
    load_model= load_checkpoint(model).cpu()
    pic= process_image(image_path)
    pic_to_tensor= torch.from_numpy(pic)#.type(torch.FloatTensor)
    pic_dim= pic_to_tensor.unsqueeze_(0)
    load_model.eval()
    with torch.no_grad():
        output= load_model.forward(pic_dim)
        ps= torch.exp(output)
        top_probs = np.array(ps.topk(topk, dim=1)[0])[0]
        top_class = np.array(ps.topk(topk, dim=1)[1])[0]
        class_to_idx= load_model.class_to_idx
        idx_to_class= {x: y for y, x in class_to_idx.items()}
        list_of_top_classes= []
        for classes in top_class:
            list_of_top_classes += [idx_to_class[classes]]
    return top_probs, list_of_top_classes

using the model

model_path = 'checkpoint.pth' 
image_path = data_dir + '/test' + '/1/' + 'image_06743.jpg'
probs,classes = predict(image_path, model_path, topk=5)
print(probs)
print(classes)

This is the last output enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.