从最后一个隐藏层提取特征Pytorch Resnet18 [英] Extract features from last hidden layer Pytorch Resnet18

查看:63
本文介绍了从最后一个隐藏层提取特征Pytorch Resnet18的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Oxford Pet数据集实现图像分类器带有预训练的Resnet18 CNN.数据集包含37个类别,每个类别中都有约200张图像.

我不想使用CNN的最后一个fc层作为输出进行预测,而是希望使用CNN作为特征提取器对宠物进行分类.

对于每个图像,我都希望从最后一个隐藏层(应该在 1000维输出层之前)获取要素.我的模型正在使用Relu激活,因此我应该在ReLU之后抓取输出(因此所有值都是非负的)

这是代码(在Pytorch上的转让学习教程之后):

加载数据

  normalize = transforms.Normalize(平均值= [0.485,0.456,0.406],std = [0.229,0.224,0.225])image_datasets = {"train":datasets.ImageFolder("images_new/train",transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizo​​ntalFlip(),transforms.ToTensor(),归一化])),测试":datasets.ImageFolder('images_new/test',transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),归一化]))}dataloaders = {x:torch.utils.data.DataLoader(image_datasets [x],batch_size = 4,shuffle = True,num_workers = 4,pin_memory = True)对于[[train],"test"]}中的xdataset_sizes = {x:[[train],'test']}中x的len(image_datasets [x])train_class_names = image_datasets ['train'].classes设备= torch.device("cuda:0&";如果torch.cuda.is_available(),否则为"cpu") 

火车功能

  def train_model(模型,标准,优化器,调度程序,num_epochs = 25):由于= time.time()best_model_wts = copy.deepcopy(model.state_dict())best_acc = 0.0对于范围内的纪元(num_epochs):print('Epoch {}/{}'.format(epoch,num_epochs-1))打印('-'* 10)#每个时期都有训练和验证阶段对于['train','test']中的阶段:如果phase =='train':scheduler.step()model.train()#将模型设置为训练模式别的:model.eval()#设置模型为评估模式running_loss = 0.0running_corrects = 0#遍历数据.对于输入,数据加载器中的标签[阶段]:输入= inputs.to(设备)标签= labels.to(设备)#零参数梯度optimizer.zero_grad()# 向前#跟踪历史记录(仅在火车上)使用torch.set_grad_enabled(phase =='train'):输出=模型(输入)_,preds = torch.max(输出,1)损失=标准(输出,标签)#向后+仅在训练阶段才进行优化如果phase =='train':loss.backward()Optimizer.step()# 统计数据running_loss + = loss.item()* inputs.size(0)running_corrects + = torch.sum(preds == labels.data)epoch_loss = running_loss/dataset_sizes [phase]epoch_acc = running_corrects.double()/dataset_sizes [阶段]print('{}损失:{:. 4f} Acc:{:. 4f}'.format(阶段,epoch_loss,epoch_acc))#深度复制模型如果phase =='test'并且epoch_acc>best_acc:best_acc = epoch_accbest_model_wts = copy.deepcopy(model.state_dict())打印()time_elapsed = time.time()-自print('在{:.0f} m {:.0f} s中完成培训'.format(time_elapsed//60,time_elapsed%60))print('Best val Acc:{:4f}'.format(best_acc))#加载最佳模型权重model.load_state_dict(best_model_wts)退货模式 

计算SGD交叉熵损失

  model_ft = models.resnet18(pretrained = True)num_ftrs = model_ft.fc.in_featuresprint(功能数:",num_ftrs)model_ft.fc = nn.Linear(num_ftrs,len(train_class_names))model_ft = model_ft.to(设备)准则= nn.CrossEntropyLoss()#观察所有参数是否正在优化optimizer_ft = optim.SGD(model_ft.parameters(),lr = 0.001,动量= 0.9)#每7个周期将LR衰减0.1exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft,step_size = 7,gamma = 0.1)model_ft = train_model(model_ft,条件,optimizer_ft,exp_lr_scheduler,num_epochs = 24) 

现在如何从每个图像的最后一个隐藏层中获取特征向量?我知道我必须冻结上一层,以便不对它们进行梯度计算,但是在提取特征向量时遇到了麻烦.

我的最终目标是使用这些特征向量来训练线性分类器(例如Ridge或类似的东西).

谢谢!

解决方案

这可能不是最好的主意,但是您可以执行以下操作:

  #assuming model_ft现在接受培训model_ft.fc_backup = model_ft.fcmodel_ft.fc = nn.Sequential()#空的连续层不执行任何操作(直通)#现在您将网络用作特征提取器 

我还检查了 fc 是要更改的正确属性,请查看the Oxford Pet dataset with the pre-trained Resnet18 CNN. The dataset consists of 37 categories with ~200 images in each of them.

Rather than using the final fc layer of the CNN as output to make predictions I want to use the CNN as a feature extractor to classify the pets.

For each image i'd like to grab features from the last hidden layer (which should be before the 1000-dimensional output layer). My model is using Relu activation so I should grab the output just after the ReLU (so all values will be non-negative)

Here is code (following the transfer learning tutorial on Pytorch):

loading data

normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                std=[0.229, 0.224, 0.225])


image_datasets = {"train": datasets.ImageFolder('images_new/train', transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        normalize
    ])), "test": datasets.ImageFolder('images_new/test', transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        normalize
    ]))
               }

dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,
                                             shuffle=True, num_workers=4, pin_memory=True)
              for x in ['train', 'test']}

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'test']}

train_class_names = image_datasets['train'].classes

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

train function

def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
    since = time.time()

    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0

    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch, num_epochs - 1))
        print('-' * 10)

        # Each epoch has a training and validation phase
        for phase in ['train', 'test']:
            if phase == 'train':
                scheduler.step()
                model.train()  # Set model to training mode
            else:
                model.eval()   # Set model to evaluate mode

            running_loss = 0.0
            running_corrects = 0

            # Iterate over data.
            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                # zero the parameter gradients
                optimizer.zero_grad()

                # forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    
                    
                    loss = criterion(outputs, labels)

                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                # statistics
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]

            print('{} Loss: {:.4f} Acc: {:.4f}'.format(
                phase, epoch_loss, epoch_acc))

            # deep copy the model
            if phase == 'test' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())

        print()

    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val Acc: {:4f}'.format(best_acc))

    # load best model weights
    model.load_state_dict(best_model_wts)
    return model

Compute SGD cross-entropy loss

model_ft = models.resnet18(pretrained=True)
num_ftrs = model_ft.fc.in_features

print("number of features: ", num_ftrs)

model_ft.fc = nn.Linear(num_ftrs, len(train_class_names))

model_ft = model_ft.to(device)
criterion = nn.CrossEntropyLoss()

# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)

# Decay LR by a factor of 0.1 every 7 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,
                       num_epochs=24)

Now how do I get a feature vector from the last hidden layer for each of my images? I know I have to freeze the previous layer so that gradient isn't computed on them but I'm having trouble extracting the feature vectors.

My ultimate goal is to use those feature vectors to train a linear classifier such as Ridge or something like that.

Thanks!

解决方案

This is probably not the best idea, but you can do something like this:

#assuming model_ft is trained now
model_ft.fc_backup = model_ft.fc
model_ft.fc = nn.Sequential() #empty sequential layer does nothing (pass-through)
# now you use your network as a feature extractor

I also checked fc is the right attribute to change, look at forward

这篇关于从最后一个隐藏层提取特征Pytorch Resnet18的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆