尝试打印犬种的类名,但它不断说列表索引超出范围

时间:2019-03-05 22:51:47

标签: python deep-learning pytorch

我正在使用resnet模型对狗的品种进行分类,但是当我尝试打印带有狗的品种标签的图像时,它表示列表索引超出范围。 这是我的代码:

import torchvision.models as models
import torch.nn as nn


model_transfer = models.resnet18(pretrained=True)

if use_cuda:
    model_transfer = model_transfer.cuda()

model_transfer.fc.out_features = 133

然后,我训练模型并获得超过70%的犬种准确性。

然后这是我的代码,对狗进行分类并打印狗的品种:

data_transfer = {'train': 
 datasets.ImageFolder('/data/dog_images/train',transform=transforms.Compose([transforms.RandomResizedCrop(224),transforms.ToTensor()]))}
class_names[0]
class_names = [item[4:].replace("_", " ") for item in data_transfer['train'].classes]

def predict_breed_transfer(img_path):

    image = Image.open(img_path)

    # large images will slow down processing


    in_transform = transforms.Compose([
                        transforms.CenterCrop(224),
                        transforms.ToTensor(),
                        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                             std=[0.229, 0.224, 0.225])])

    # discard the transparent, alpha channel (that's the :3) and add the batch dimension
    image = in_transform(image)[:3,:,:].unsqueeze(0)

    image = image

    output = model_transfer(image)
    pred = torch.argmax(output)

    return class_names[pred]
    predict_breed_transfer('images/Labrador_retriever_06455.jpg')

代码总是出于某种原因预测狗是错误的 然后,当我尝试打印图像和标签时:

import matplotlib.pyplot as plt
def run_app(img_path):
    img = Image.open(img_path)
    dog = dog_detector(img_path)
    if not dog: 
        print('hello, human!')
        plt.imshow(img)
        print('You look like a ... ')
        print(predict_breed_transfer(img_path))
    if dog: 
        print('hello, dog!')
        print('Your predicted breed is ....')
        print(predict_breed_transfer(img_path))
        plt.imshow(img)
    else: 
        print('Niether human nor dog')

并运行for循环,在某些狗图像上调用它,它将打印出某些品种,然后说列表索引超出范围,并且不显示任何图像。

class_names的长度为133 当我打印出resnet模型时,输出只有133个节点,没有人知道为什么它说列表索引超出范围或为什么它如此不准确。

`IndexError                                Traceback (most recent 
call last)
<ipython-input-26-473a9ba884b5> in <module>()
      5 ## suggested code, below
      6 for file in np.hstack((human_files[:3], dog_files[:3])):
----> 7     run_app(file)
      8 
 <ipython-input-25-1d44200e44cc> in run_app(img_path)
      10         plt.show(img)
      11         print('You look like a ... ')
 ---> 12         print(predict_breed_transfer(img_path))
      13     if dog:
      14         print('hello, dog!')

 <ipython-input-20-a51fb205659e> in predict_breed_transfer(img_path)
      26     pred = torch.argmax(output)
      27 
 ---> 28     return class_names[pred]
      29 
predict_breed_transfer('images/Labrador_retriever_06455.jpg')
      30 

IndexError: list index out of range`

这是完整错误

1 个答案:

答案 0 :(得分:0)

我想您有13个字符可以解决的几个问题。

首先,我建议@Alekhya Vemavarapu建议-使用调试器运行代码以隔离每一行并检查输出。 这是使用pytorch动态图的最大优点之一。

第二,引起问题的最可能原因是您错误地使用了argmax语句。您未指定执行argmax的维度,因此 PyTorch 自动使图像变平并对全长矢量执行操作。 因此,您得到的数字介于0MB_Size x num_classes -1 之间。参见Official doc on this method

因此,由于您具有完全连接的层,因此我假设您的输出为(MB_Size, num_classes)形状。如果是这样,则需要将代码更改为以下行:

pred = torch.argmax(output,dim=1)

就这样。否则,只需选择logits的尺寸即可。

您要考虑的第三件事是训练配置可能对推理造成的辍学和其他影响。例如,某些框架中的退出可能需要在推论中将输出乘以1/(1-p)(或者因为在训练时可以完成,所以不这样做),由于批量大小不同,可能会取消批量归一化,依此类推。此外,为减少内存消耗,不应计算任何梯度。 幸运的是,PyTorch开发人员非常体贴,为此提供了torch.no_grad()model.eval()

我强烈建议对此进行练习,可能会用几个字母更改代码:

output = model_transfer.eval()(image)

您完成了!

修改
这是错误使用PyTorch框架,不阅读docs且不调试代码的简单用例。以下代码是完全不正确的:

model_transfer.fc.out_features = 133

此行实际上并未创建新的完全连接的层。它只是改变了该张量的属性。在您的控制台中尝试:

import torch
a = torch.nn.Linear(1,2)
a.out_features = 3
print(a.bias.data.shape, a.weight.data.shape)

输出:

torch.Size([2]) torch.Size([2, 1])

表示权重的实际矩阵和偏差矢量保持其原始尺寸。
进行迁移学习的正确方法是保留主干(通常是卷积层,直到这些类型的模型中的卷积层完全连接)并用您的头部覆盖磁头(在这种情况下为FC层)。如果原始模型中仅存在一层完全连接的层,则无需更改模型的前向通过,您就可以进行了。 由于此答案已经足够长,因此只需访问PyTorch文档中的Transfer learning tutorial即可了解该方法。

祝你好运。