首页 > 解决方案 > vgg pytorch 是概率分布应该加起来为 1?

问题描述

我已经训练了一个 vgg16 模型来预测 102 类花卉。但是现在它起作用了,因为我试图理解它的一个预测,我觉得它的行为不正常。

模型布局

# Imports here
import os
import numpy as np
import torch

import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import json
from pprint import pprint
from scipy import misc

%matplotlib inline

data_dir = 'flower_data'
train_dir = data_dir + '/train'
test_dir = data_dir + '/valid'

json_data=open('cat_to_name.json').read()
main_classes = json.loads(json_data)
main_classes = {int(k):v for k,v in classes.items()}

train_transform_2 = transforms.Compose([transforms.RandomResizedCrop(224), 
                                    transforms.RandomRotation(30),
                                    transforms.RandomHorizontalFlip(),
                                    transforms.ToTensor()])

test_transform_2= transforms.Compose([transforms.RandomResizedCrop(224), 
                                    transforms.ToTensor()])

# TODO: Load the datasets with ImageFolder
train_data = datasets.ImageFolder(train_dir, transform=train_transform_2)
test_data = datasets.ImageFolder(test_dir, transform=test_transform_2)

# define dataloader parameters
batch_size = 20
num_workers=0

# TODO: Using the image datasets and the trainforms, define the dataloaders
train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, 
                                        num_workers=num_workers, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, 
                                        num_workers=num_workers, shuffle=True)

vgg16 = models.vgg16(pretrained=True)

# Freeze training for all "features" layers
for param in vgg16.features.parameters():
    param.requires_grad = False

import torch.nn as nn

n_inputs = vgg16.classifier[6].in_features

# add last linear layer (n_inputs -> 102 flower classes)
# new layers automatically have requires_grad = True
last_layer = nn.Linear(n_inputs, len(classes))

vgg16.classifier[6] = last_layer

import torch.optim as optim

# specify loss function (categorical cross-entropy)
criterion = nn.CrossEntropyLoss()

# specify optimizer (stochastic gradient descent) and learning rate = 0.001
optimizer = optim.SGD(vgg16.classifier.parameters(), lr=0.001)

pre_trained_model=torch.load("model.pt")
new=list(pre_trained_model.items())

my_model_kvpair=vgg16.state_dict()
count=0

for key,value in my_model_kvpair.items():
    layer_name, weights = new[count]      
    my_model_kvpair[key] = weights
    count+=1

# number of epochs to train the model
n_epochs = 6

# initialize tracker for minimum validation loss
valid_loss_min = np.Inf # set initial "min" to infinity

for epoch in range(1, n_epochs+1):

    # keep track of training and validation loss
    train_loss = 0.0
    valid_loss = 0.0

    ###################
    # train the model #
    ###################
    # model by default is set to train
    vgg16.train()

    for batch_i, (data, target) in enumerate(train_loader):
        # clear the gradients of all optimized variables
        optimizer.zero_grad()
        # forward pass: compute predicted outputs by passing inputs to the model
        output = vgg16(data)
        # calculate the batch loss
        loss = criterion(output, target)
        # backward pass: compute gradient of the loss with respect to model parameters
        loss.backward()
        # perform a single optimization step (parameter update)
        optimizer.step()
        # update training loss 
        train_loss += loss.item()

        if batch_i % 20 == 19:    # print training loss every specified number of mini-batches
            print('Epoch %d, Batch %d loss: %.16f' %
                (epoch, batch_i + 1, train_loss / 20))
            train_loss = 0.0

    ######################    
    # validate the model #
    ######################
    vgg16.eval() # prep model for evaluation
    for data, target in test_loader:
        # forward pass: compute predicted outputs by passing inputs to the model
        output = vgg16(data)
        # calculate the loss
        loss = criterion(output, target)
        # update running validation loss 
        valid_loss += loss.item()

    # print training/validation statistics 
    # calculate average loss over an epoch
    train_loss = train_loss/len(train_loader.dataset)
    valid_loss = valid_loss/len(test_loader.dataset)

    print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(
        epoch+1, 
        train_loss,
        valid_loss
        ))

    # save model if validation loss has decreased
    if valid_loss <= valid_loss_min:
        print('Validation loss decreased ({:.6f} --> {:.6f}).  Saving model ...'.format(
        valid_loss_min,
        valid_loss))
        torch.save(vgg16.state_dict(), 'model.pt')
        valid_loss_min = valid_loss

在单个图像上测试

tensor = torch.from_numpy(test_image)
reshaped = tensor.permute(2, 0, 1).unsqueeze(0)
floatified = reshaped.to(torch.float32) / 255
vgg16(floatified)
>>>
tensor([[ 2.5686, -1.1964, -0.0872, -1.7010, -1.6669, -1.0638,  0.4515,  0.1124,
          0.0166,  0.3156,  1.1699,  1.5374,  1.8720,  2.5184,  2.9046, -0.8241,
         -1.1949, -0.5700,  0.8692, -1.0485,  0.0390, -1.3783, -3.4632, -0.0143,
          1.0986,  0.2667, -1.1127, -0.8515,  0.7759, -0.7528,  1.6366, -0.1170,
         -0.4983, -2.6970,  0.7545,  0.0188,  0.1094,  0.5002,  0.8838, -0.0006,
         -1.7993, -1.3706,  0.4964, -0.3251, -1.7313,  1.8731,  2.4963,  1.1713,
         -1.5726,  1.5476,  3.9576,  0.7388,  0.0228,  0.3947, -1.7237, -1.8350,
         -2.0297,  1.4088, -1.3469,  1.6128, -1.0851,  2.0257,  0.5881,  0.7498,
          0.0738,  2.0592,  1.8034, -0.5468,  1.9512,  0.4534,  0.7746, -1.0465,
         -0.7254,  0.3333, -1.6506, -0.4242,  1.9529, -0.4542,  0.2396, -1.6804,
         -2.7987, -0.6367, -0.3599,  1.0102,  2.6319,  0.8305, -1.4333,  3.3043,
         -0.4021, -0.4877,  0.9125,  0.0607, -1.0326,  1.3186, -2.5861,  0.1211,
         -2.3177, -1.5040,  1.0416,  1.4008,  1.4225, -2.7291]],
       grad_fn=<ThAddmmBackward>)

sum([ 2.5686, -1.1964, -0.0872, -1.7010, -1.6669, -1.0638,  0.4515,  0.1124,
          0.0166,  0.3156,  1.1699,  1.5374,  1.8720,  2.5184,  2.9046, -0.8241,
         -1.1949, -0.5700,  0.8692, -1.0485,  0.0390, -1.3783, -3.4632, -0.0143,
          1.0986,  0.2667, -1.1127, -0.8515,  0.7759, -0.7528,  1.6366, -0.1170,
         -0.4983, -2.6970,  0.7545,  0.0188,  0.1094,  0.5002,  0.8838, -0.0006,
         -1.7993, -1.3706,  0.4964, -0.3251, -1.7313,  1.8731,  2.4963,  1.1713,
         -1.5726,  1.5476,  3.9576,  0.7388,  0.0228,  0.3947, -1.7237, -1.8350,
         -2.0297,  1.4088, -1.3469,  1.6128, -1.0851,  2.0257,  0.5881,  0.7498,
          0.0738,  2.0592,  1.8034, -0.5468,  1.9512,  0.4534,  0.7746, -1.0465,
         -0.7254,  0.3333, -1.6506, -0.4242,  1.9529, -0.4542,  0.2396, -1.6804,
         -2.7987, -0.6367, -0.3599,  1.0102,  2.6319,  0.8305, -1.4333,  3.3043,
         -0.4021, -0.4877,  0.9125,  0.0607, -1.0326,  1.3186, -2.5861,  0.1211,
         -2.3177, -1.5040,  1.0416,  1.4008,  1.4225, -2.7291])
>>>
5.325799999999998

鉴于这是我在单个图像上测试它的方式(并且模型像往常一样在批次上进行训练和测试,它返回一个似乎没有被归一化或加起来为 1 的预测矩阵。

这是正常的吗?

标签: conv-neural-networkpytorchvgg-net

解决方案


如果没有看到您的训练代码,我无法确定,但很可能您的模型是用交叉熵损失训练的,因此它输出的是 logits而不是类概率。您可以通过应用softmax函数将它们转换为适当的概率。


推荐阅读