猿问

如何从 Pytorch 中的单个图像中提取特征向量?

我正在尝试更多地了解计算机视觉模型,并且正在尝试探索它们的工作原理。为了更好地理解如何解释特征向量,我尝试使用 Pytorch 来提取特征向量。下面是我从不同地方拼凑而成的代码。


import torch

import torch.nn as nn

import torchvision.models as models

import torchvision.transforms as transforms

from torch.autograd import Variable

from PIL import Image




img=Image.open("Documents/01235.png")


# Load the pretrained model

model = models.resnet18(pretrained=True)


# Use the model object to select the desired layer

layer = model._modules.get('avgpool')


# Set model to evaluation mode

model.eval()


transforms = torchvision.transforms.Compose([

        torchvision.transforms.Resize(256),

        torchvision.transforms.CenterCrop(224),

        torchvision.transforms.ToTensor(),

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

    ])

    

def get_vector(image_name):

    # Load the image with Pillow library

    img = Image.open("Documents/Documents/Driven Data Competitions/Hateful Memes Identification/data/01235.png")

    # Create a PyTorch Variable with the transformed image

    t_img = transforms(img)

    # Create a vector of zeros that will hold our feature vector

    # The 'avgpool' layer has an output size of 512

    my_embedding = torch.zeros(512)

    # Define a function that will copy the output of a layer

    def copy_data(m, i, o):

        my_embedding.copy_(o.data)

    # Attach that function to our selected layer

    h = layer.register_forward_hook(copy_data)

    # Run the model on our transformed image

    model(t_img)

    # Detach our copy function from the layer

    h.remove()

    # Return the feature vector

    return my_embedding


pic_vector = get_vector(img)

当我这样做时,出现以下错误:


RuntimeError: Expected 4-dimensional input for 4-dimensional weight [64, 3, 7, 7], but got 3-dimensional input of size [3, 224, 224] instead

我确定这是一个基本错误,但我似乎无法弄清楚如何解决这个问题。我的印象是“totensor”转换会使我的数据成为 4-d,但它似乎无法正常工作或者我误解了它。感谢我可以用来了解更多信息的任何帮助或资源!


ibeautiful
浏览 218回答 3
3回答

萧十郎

pytorch 中的所有默认值都nn.Modules需要一个额外的批次维度。如果模块的输入是形状 (B, ...) 那么输出也将是 (B, ...) (尽管后面的维度可能会根据层而改变)。此行为允许同时对 B 批输入进行有效推理。为了使您的代码符合您的要求,您可以在将张量发送到您的模型以使其成为 (1, ...) 张量之前,在张量unsqueeze的前面增加一个单一维度。如果你想将它复制到你的一维张量中t_img,你还需要在存储它之前flatten的输出。layermy_embedding其他几件事:您应该在上下文中进行推断torch.no_grad()以避免计算梯度,因为您将不需要它们(请注意,model.eval()只是更改某些层的行为,如 dropout 和批归一化,它不会禁用计算图的构建,但会torch.no_grad()禁用)。我认为这只是一个复制粘贴问题,但它transforms是一个导入模块的名称以及一个全局变量。o.data只是返回o. 在旧Variable界面(大约 PyTorch 0.3.1 及更早版本)中,这曾经是必需的,但该Variable界面在 PyTorch 0.4.0中已被弃用,不再做任何有用的事情;现在它的使用只会造成混乱。不幸的是,许多教程仍在使用这种陈旧且不必要的界面编写。更新后的代码如下:import torchimport torchvisionimport torchvision.models as modelsfrom PIL import Imageimg = Image.open("Documents/01235.png")# Load the pretrained modelmodel = models.resnet18(pretrained=True)# Use the model object to select the desired layerlayer = model._modules.get('avgpool')# Set model to evaluation modemodel.eval()transforms = torchvision.transforms.Compose([    torchvision.transforms.Resize(256),    torchvision.transforms.CenterCrop(224),    torchvision.transforms.ToTensor(),    torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),])def get_vector(image):    # Create a PyTorch tensor with the transformed image    t_img = transforms(image)    # Create a vector of zeros that will hold our feature vector    # The 'avgpool' layer has an output size of 512    my_embedding = torch.zeros(512)    # Define a function that will copy the output of a layer    def copy_data(m, i, o):        my_embedding.copy_(o.flatten())                 # <-- flatten    # Attach that function to our selected layer    h = layer.register_forward_hook(copy_data)    # Run the model on our transformed image    with torch.no_grad():                               # <-- no_grad context        model(t_img.unsqueeze(0))                       # <-- unsqueeze    # Detach our copy function from the layer    h.remove()    # Return the feature vector    return my_embeddingpic_vector = get_vector(img)

qq_笑_17

您可以使用create_feature_extractorfrom 从torchvision.models.feature_extraction模型中提取所需层的特征。ResNet18 中最后一个隐藏层的节点名称flatten基本上是扁平化的 1D avgpool。你可以通过在下面的字典中添加它们来提取你想要的任何层return_nodes。from torchvision.io import read_imagefrom torchvision.models import resnet18, ResNet18_Weightsfrom torchvision.models.feature_extraction import create_feature_extractor# Step 1: Initialize the model with the best available weightsweights = ResNet18_Weights.DEFAULTmodel = resnet18(weights=weights)model.eval()# Step 2: Initialize the inference transformspreprocess = weights.transforms()# Step 3: Create the feature extractor with the required nodesreturn_nodes = {'flatten': 'flatten'}feature_extractor = create_feature_extractor(model, return_nodes=return_nodes)# Step 4: Load the image(s) and apply inference preprocessing transformsimage = "?"image = read_image(image).unsqueeze(0)model_input = preprocess(image)# Step 5: Extract the featuresfeatures = feature_extractor(model_input)flatten_fts = features["flatten"].squeeze()print(flatten_fts.shape)

潇潇雨雨

model(t_img)而不是这个在这里做——model(t_img[None])这将增加一个额外的维度,因此图像将具有形状[1,3,224,224]并且可以使用。
随时随地看视频慕课网APP

相关分类

Python
我要回答