微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ResNet 对象没有属性“预测”

如何解决ResNet 对象没有属性“预测”

我在 PyTorch 中训练了一个 CNN 模型来检测 6 个不同类别的皮肤病。我的模型的准确率为 92%,我将它保存在一个 .pth 文件中。我想使用这个模型进行预测,但我不知道如何去做。如果有人可以帮助我完成必要的步骤,我将不胜感激。

我曾尝试直接从文件夹中获取图像输入,调整其大小,然后通过模型运行以进行预测。我面临的错误是 ModuleAttributeAError ,它表示没有名为 predict 的属性。现在我不明白我哪里出错了,我知道这对大多数人来说是一项简单的任务,但我希望在这方面得到一些指导。我使用的数据集是来自 kaggle 的皮肤癌 MNIST:HAM10000 数据集,并在 resnet18 上对其进行了训练。如果有人对模型微调有任何建议,我将不胜感激。

TLDR:我收到一个名为 ModuleAttributeError 的错误,指出“resnet”模块没有“预测”属性

这里对图片进行了如下预处理:

import os,cv2,itertools
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import pickle
from tqdm import tqdm
from glob import glob
from PIL import Image

# pytorch libraries
import torch
from torch import optim,nn
from torch.autograd import Variable
from torch.utils.data import DataLoader,Dataset
from torchvision import models,transforms

# sklearn libraries
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report


np.random.seed(10)
torch.manual_seed(10)
torch.cuda.manual_seed(10)

print(os.listdir("/content/drive/My Drive/input"))

from google.colab import drive
drive.mount('/content/drive')

"""**Data analysis and preprocessing**"""

data_dir = '/content/drive/My Drive/input'
all_image_path = glob(os.path.join(data_dir,'*','*.jpg'))
imageid_path_dict = {os.path.splitext(os.path.basename(x))[0]: x for x in all_image_path}
lesion_type_dict = {
    'nv': 'Melanocytic nevi','mel': 'Melanoma','bkl': 'Benign keratosis-like lesions ','bcc': 'Basal cell carcinoma','akiec': 'Actinic keratoses','vasc': 'Vascular lesions','df': 'Dermatofibroma'
}

def compute_img_mean_std(image_paths):
    """
        computing the mean and std of three channel on the whole dataset,first we should normalize the image from 0-255 to 0-1
    """

    img_h,img_w = 224,224
    imgs = []
    means,stdevs = [],[]

    for i in tqdm(range(len(image_paths))):
        img = cv2.imread(image_paths[i])
        img = cv2.resize(img,(img_h,img_w))
        imgs.append(img)

    imgs = np.stack(imgs,axis=3)
    print(imgs.shape)

    imgs = imgs.astype(np.float32) / 255.

    for i in range(3):
        pixels = imgs[:,:,i,:].ravel()  # resize to one row
        means.append(np.mean(pixels))
        stdevs.append(np.std(pixels))

    means.reverse()  # BGR --> RGB
    stdevs.reverse()

    print("normMean = {}".format(means))
    print("normStd = {}".format(stdevs))
    return means,stdevs

# norm_mean,norm_std = compute_img_mean_std(all_image_path)

norm_mean = (0.763035,0.54564625,0.5700399)
norm_std = (0.1409281,0.15261264,0.16997051)

df_original = pd.read_csv(os.path.join(data_dir,'HAM10000_Metadata.csv'))
df_original['path'] = df_original['image_id'].map(imageid_path_dict.get)
df_original['cell_type'] = df_original['dx'].map(lesion_type_dict.get)
df_original['cell_type_idx'] = pd.Categorical(df_original['cell_type']).codes
df_original.head()

# this will tell us how many images are associated with each lesion_id
df_undup = df_original.groupby('lesion_id').count()
# Now we filter out lesion_id's that have only one image associated with it
df_undup = df_undup[df_undup['image_id'] == 1]
df_undup.reset_index(inplace=True)
df_undup.head()

# here we identify lesion_id's that have duplicate images and those that have only one image.
def get_duplicates(x):
    unique_list = list(df_undup['lesion_id'])
    if x in unique_list:
        return 'unduplicated'
    else:
        return 'duplicated'

# create a new colum that is a copy of the lesion_id column
df_original['duplicates'] = df_original['lesion_id']
# apply the function to this new column
df_original['duplicates'] = df_original['duplicates'].apply(get_duplicates)
df_original.head()

df_original['duplicates'].value_counts()

# Now we filter out images that don't have duplicates
df_undup = df_original[df_original['duplicates'] == 'unduplicated']
df_undup.shape

# Now we create a val set using df because we are sure that none of these images have augmented duplicates in the train set
y = df_undup['cell_type_idx']
_,df_val = train_test_split(df_undup,test_size=0.2,random_state=101,stratify=y)
df_val.shape

df_val['cell_type_idx'].value_counts()

# This set will be df_original excluding all rows that are in the val set
# This function identifies if an image is part of the train or val set.
def get_val_rows(x):
    # create a list of all the lesion_id's in the val set
    val_list = list(df_val['image_id'])
    if str(x) in val_list:
        return 'val'
    else:
        return 'train'

# identify train and val rows
# create a new colum that is a copy of the image_id column
df_original['train_or_val'] = df_original['image_id']
# apply the function to this new column
df_original['train_or_val'] = df_original['train_or_val'].apply(get_val_rows)
# filter out train rows
df_train = df_original[df_original['train_or_val'] == 'train']
print(len(df_train))
print(len(df_val))

df_train['cell_type_idx'].value_counts()

df_val['cell_type'].value_counts()

# copy fewer class to balance the number of 7 classes
data_aug_rate = [15,10,5,50,40,5]
for i in range(7):
    if data_aug_rate[i]:
        df_train=df_train.append([df_train.loc[df_train['cell_type_idx'] == i,:]]*(data_aug_rate[i]-1),ignore_index=True)
df_train['cell_type'].value_counts()

# # We can split the test set again in a validation set and a true test set:
# df_val,df_test = train_test_split(df_val,test_size=0.5)
df_train = df_train.reset_index()
df_val = df_val.reset_index()
# df_test = df_test.reset_index()

这里是我构建模型的地方:

# feature_extract is a boolean that defines if we are finetuning or feature extracting. 
# If feature_extract = False,the model is finetuned and all model parameters are updated. 
# If feature_extract = True,only the last layer parameters are updated,the others remain fixed.
def set_parameter_requires_grad(model,feature_extracting):
    if feature_extracting:
        for param in model.parameters():
            param.requires_grad = False

def initialize_model(model_name,num_classes,feature_extract,use_pretrained=True):
    # Initialize these variables which will be set in this if statement. Each of these
    #   variables is model specific.
    model_ft = None
    input_size = 0

    if model_name == "resnet":
        """ resnet18,resnet34,resnet50,resnet101
        """
        model_ft = models.resnet18(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft,feature_extract)
        num_ftrs = model_ft.fc.in_features
        model_ft.fc = nn.Linear(num_ftrs,num_classes)
        input_size = 224


    elif model_name == "vgg":
        """ VGG11_bn
        """
        model_ft = models.vgg11_bn(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft,feature_extract)
        num_ftrs = model_ft.classifier[6].in_features
        model_ft.classifier[6] = nn.Linear(num_ftrs,num_classes)
        input_size = 224


    elif model_name == "densenet":
        """ Densenet121
        """
        model_ft = models.densenet121(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft,feature_extract)
        num_ftrs = model_ft.classifier.in_features
        model_ft.classifier = nn.Linear(num_ftrs,num_classes)
        input_size = 224

    elif model_name == "inception":
        """ Inception v3
        """
        model_ft = models.inception_v3(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft,feature_extract)
        # Handle the auxilary net
        num_ftrs = model_ft.AuxLogits.fc.in_features
        model_ft.AuxLogits.fc = nn.Linear(num_ftrs,num_classes)
        # Handle the primary net
        num_ftrs = model_ft.fc.in_features
        model_ft.fc = nn.Linear(num_ftrs,num_classes)
        input_size = 299

    else:
        print("Invalid model name,exiting...")
        exit()
    return model_ft,input_size

# resnet,vgg,densenet,inception
model_name = 'resnet'
num_classes = 7
feature_extract = False
# Initialize the model for this run
model_ft,input_size = initialize_model(model_name,use_pretrained=True)
# Define the device:
device = torch.device('cuda:0')
# Put the model on the device:
model = model_ft.to(device)

# norm_mean = (0.49139968,0.48215827,0.44653124)
# norm_std = (0.24703233,0.24348505,0.26158768)
# define the transformation of the train images.
train_transform = transforms.Compose([transforms.Resize((input_size,input_size)),transforms.RandomHorizontalFlip(),transforms.RandomVerticalFlip(),transforms.Randomrotation(20),transforms.ColorJitter(brightness=0.1,contrast=0.1,hue=0.1),transforms.ToTensor(),transforms.normalize(norm_mean,norm_std)])
# define the transformation of the val images.
val_transform = transforms.Compose([transforms.Resize((input_size,norm_std)])

# Define a pytorch DataLoader for this dataset
class HAM10000(Dataset):
    def __init__(self,df,transform=None):
        self.df = df
        self.transform = transform

    def __len__(self):
        return len(self.df)

    def __getitem__(self,index):
        # Load data and get label
        X = Image.open(self.df['path'][index])
        y = torch.tensor(int(self.df['cell_type_idx'][index]))

        if self.transform:
            X = self.transform(X)

        return X,y

# Define the training set using the table train_df and using our defined transitions (train_transform)
training_set = HAM10000(df_train,transform=train_transform)
train_loader = DataLoader(training_set,batch_size=64,shuffle=True,num_workers=4)
# Same for the validation set:
validation_set = HAM10000(df_val,transform=train_transform)
val_loader = DataLoader(validation_set,shuffle=False,num_workers=4)

# we use Adam optimizer,use cross entropy loss as our loss function
optimizer = optim.Adam(model.parameters(),lr=1e-5)
criterion = nn.CrossEntropyLoss().to(device)

最后是带有预测函数的训练过程:

# this function is used during training process,to calculation the loss and accuracy
class AverageMeter(object):
    def __init__(self):
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self,val,n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

total_loss_train,total_acc_train = [],[]
def train(train_loader,model,criterion,optimizer,epoch):
    model.train()
    train_loss = AverageMeter()
    train_acc = AverageMeter()
    curr_iter = (epoch - 1) * len(train_loader)
    for i,data in enumerate(train_loader):
        images,labels = data
        N = images.size(0)
        # print('image shape:',images.size(0),'label shape',labels.size(0))
        images = Variable(images).to(device)
        labels = Variable(labels).to(device)

        optimizer.zero_grad()
        outputs = model(images)

        loss = criterion(outputs,labels)
        loss.backward()
        optimizer.step()
        prediction = outputs.max(1,keepdim=True)[1]
        train_acc.update(prediction.eq(labels.view_as(prediction)).sum().item()/N)
        train_loss.update(loss.item())
        curr_iter += 1
        if (i + 1) % 100 == 0:
            print('[epoch %d],[iter %d / %d],[train loss %.5f],[train acc %.5f]' % (
                epoch,i + 1,len(train_loader),train_loss.avg,train_acc.avg))
            total_loss_train.append(train_loss.avg)
            total_acc_train.append(train_acc.avg)
    return train_loss.avg,train_acc.avg

def validate(val_loader,epoch):
    model.eval()
    val_loss = AverageMeter()
    val_acc = AverageMeter()
    with torch.no_grad():
        for i,data in enumerate(val_loader):
            images,labels = data
            N = images.size(0)
            images = Variable(images).to(device)
            labels = Variable(labels).to(device)

            outputs = model(images)
            prediction = outputs.max(1,keepdim=True)[1]

            val_acc.update(prediction.eq(labels.view_as(prediction)).sum().item()/N)

            val_loss.update(criterion(outputs,labels).item())

    print('------------------------------------------------------------')
    print('[epoch %d],[val loss %.5f],[val acc %.5f]' % (epoch,val_loss.avg,val_acc.avg))
    print('------------------------------------------------------------')
    return val_loss.avg,val_acc.avg


import cv2
from PIL import Image,ImageOps
import numpy as np

model = model_ft
model.load_state_dict(torch.load("/content/drive/MyDrive/input/trainbest.pth"))
model.eval()

def import_and_predict(image_data,model):
  size = (224,224)
  image = ImageOps.fit(image_data,size,Image.ANTIALIAS)
  img = np.asarray(image)
  image_reshape = img[np.newaxis,...]
  prediction = model.predict(img_reshape)
  return prediction

image = Image.open('/content/0365-0596-abd-88-05-0712-gf03.jpg')
# st.image(image,use_column_width = True)
predictions = import_and_predict(image,model)
class_names = ["Melanocytic nevi","dermatofibroma","Benign keratosis-like lesions","Basal cell carcinoma","Actinic keratoses","Vascular lesions","Dermatofibroma"]
string = "It is: " + class_names[np.argmax(predictions)]
print(string)

这是执行后立即出现的错误

---------------------------------------------------------------------------
ModuleAttributeError                      Traceback (most recent call last)
<ipython-input-219-d563271b78c6> in <module>()
     32 image = Image.open('/content/0365-0596-abd-88-05-0712-gf03.jpg')
     33 # st.image(image,use_column_width = True)
---> 34 predictions = import_and_predict(image,model)
     35 class_names = ["Melanocytic nevi","Dermatofibroma"]
     36 string = "It is: " + class_names[np.argmax(predictions)]

1 frames
<ipython-input-219-d563271b78c6> in import_and_predict(image_data,model)
     27   img = np.asarray(image)
     28   image_reshape = img[np.newaxis,...]
---> 29   prediction = model.predict(img_reshape)
     30   return prediction
     31 

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in __getattr__(self,name)
    777                 return modules[name]
    778         raise ModuleAttributeError("'{}' object has no attribute '{}'".format(
--> 779             type(self).__name__,name))
    780 
    781     def __setattr__(self,name: str,value: Union[Tensor,'Module']) -> None:

ModuleAttributeError: 'resnet' object has no attribute 'predict'

如果有人能帮我解决这个问题并让它作为皮肤病的分类器工作,我会非常感激。

解决方法

nn.Module 没有 predict 函数,只需调用对象进行推理:

prediction = model(img_reshape)

这将调用对象的 __call__ 函数,而后者又调用模型的 forward 函数。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。