How to test one single image in pytorch

Viewed 7197

I created my model in pytorch and is working really good, but when i want to test just one image batch_size=1 always return the second class (in this case a dog).

I tried to test with batch > 1 and in all cases this works!

The architecture:

model = models.densenet121(pretrained=True)

for param in model.parameters():
param.requires_grad = False
from collections import OrderedDict
classifier = nn.Sequential(OrderedDict([
                          ('fc1', nn.Linear(1024, 500)),
                          ('relu', nn.ReLU()),
                          ('fc2', nn.Linear(500, 2)),
                          ('output', nn.LogSoftmax(dim=1))
                          ]))

model.classifier = classifier

so my tensors are [batch, 3, 224, 224]

i have tried with:

resize
reshape
unsqueeze(0)

the response when is one image is always [[0.4741, 0.5259]]

My Test Code

from PIL import *
msize = 256
loader = transforms.Compose([transforms.Scale(imsize), transforms.ToTensor()])

def image_loader(image_name):
    """load image, returns cuda tensor"""
    image = Image.open(image_name)
    image = loader(image).float()
    image = image.unsqueeze(0) 
    return image.cuda()
image = image_loader('Cat_Dog_data/test/cat/cat.16.jpg') 
with torch.no_grad():
    logits = model.forward(image)
ps = torch.exp(logits)
_, predTest = torch.max(ps,1)
print(ps) ## same value in all cases
imagen_mostrar = images[ii].to('cpu') 
helper.imshow(imagen_mostrar,title=clas_perro_gato(predTest), normalize=True)

Second Test Code

andrea_data = datasets.ImageFolder(data_dir + '/andrea', transform=test_transforms)
andrealoader = torch.utils.data.DataLoader(andrea_data, batch_size=1, shuffle=True)
dataiter = iter(andrealoader)
images, labels = dataiter.next()
images, labels = images.to(device), labels.to(device)
ps = torch.exp(model.forward(images))
_, predTest = torch.max(ps,1) 
print(ps.float())

if i changed my batch_size to 1 always returned a tensor who say that is a dog [0.43,0.57] for example.

Thanks!

3 Answers

I realized that my model wasn't in eval mode.

So i just added model.eval() and now that's all, works for any size batch

If your model is "correct" it just predicts a dog, you can get the label with torch.argmax(output, dim=1) no matter the size of batch.

Anyway, you shouldn't use LogSoftmax as activation, please use torch.nn.BCEWithLogitsLoss as your loss function and remove activation from your final layer and output only one neuron (probability of the image being a dog only). It would look like this in your case:

classifier = nn.Sequential(
    OrderedDict(
        [
            ("fc1", nn.Linear(1024, 500)),
            ("relu", nn.ReLU()),
            ("fc2", nn.Linear(500, 1)),
            # See? No activation needed
        ]
    )
)

You can the correct label with the above network simply by running output > 0 + you get numerical stability "for free".

You can use this code for test single image for your model train:

import torchvision.transforms as transforms
import torchvision.datasets as datasets
from torch.utils.data import DataLoader,Dataset
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
def pre_image(image_path,model):
   img = Image.open(image_path)
   mean = [0.485, 0.456, 0.406] 
   std = [0.229, 0.224, 0.225]
   transform_norm = transforms.Compose([transforms.ToTensor(), 
   transforms.Resize((224,224)),transforms.Normalize(mean, std)])
   # get normalized image
   img_normalized = transform_norm(img).float()
   img_normalized = img_normalized.unsqueeze_(0)
   # input = Variable(image_tensor)
   img_normalized = img_normalized.to(device)
   # print(img_normalized.shape)
   with torch.no_grad():
      model.eval()  
      output =model(img_normalized)
     # print(output)
      index = output.data.cpu().numpy().argmax()
      classes = train_ds.classes
      class_name = classes[index]
      return class_name

example:

predict_class = pre_image("C:/Users/Salio/Desktop/example.jpeg",your_model)
print(predict_class)
Related