运行ResNet预训练模型提取特征时出现register_forward_hook属性报错求解决
错误原因定位
你遇到的'NoneType' object has no attribute 'register_forward_hook'错误的直接原因是layer = model._modules.get('avgpool')返回了None值。_modules.get()当找不到对应命名的层时会返回None而不是报错,导致你后续对None调用hook方法触发异常。
出现这个问题的核心是你使用的第三方resnet50_ft_dag自定义模型的avgpool层没有放在模型最顶层,或者层的命名不是avgpool。你可以先执行print(model)打印完整模型结构,确认avgpool层的层级路径和实际命名。
比如如果avgpool是嵌套在features子模块下,就需要修改层获取的代码为:
# 按实际层级修改,优先用属性访问而不是_modules.get layer = model.features.avgpool
现有代码的其他修复点
- 弃用的API替换:
transforms.Scale已经被PyTorch弃用,替换为transforms.Resize - 移除冗余的
Variable调用:PyTorch 0.4之后已经不需要用Variable封装张量,直接用原生张量即可 - 新增
torch.no_grad()上下文:关闭梯度计算可以大幅降低内存占用、提升推理速度 - 缺失的变量定义:你调用
get_vector时用到的list_dir没有定义,需要先补充目录读取代码:list_dir = os.listdir('C:/Users/Public/Documents/DIN_Image/average_images/') - 新增图像通道校验:调用
Image.open后加.convert('RGB'),避免灰度图、RGBA图后续处理报错
更优的特征提取方案
不需要手动写hook就能实现稳定的特征提取,推荐以下两种更易维护的方案:
方案1:截断模型去掉分类头
直接去掉模型最后的全连接分类层,前向传播直接返回avgpool的输出:
# 截断模型,保留到avgpool层为止 feature_extractor = nn.Sequential(*list(model.children())[:-1]) feature_extractor.eval() # 有GPU的话可以执行 feature_extractor = feature_extractor.cuda() # 特征提取函数 def get_vector(image_path): img = Image.open(image_path).convert('RGB') # 预处理合并为Compose更易维护 transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) t_img = transform(img).unsqueeze(0) # 有GPU的话加 t_img = t_img.cuda() with torch.no_grad(): feature = feature_extractor(t_img).flatten() return feature.cpu().numpy() # 可以直接转numpy数组供后续使用
方案2:用官方特征提取接口(适配嵌套层结构)
如果模型层嵌套很深、不好截断,可以用PyTorch官方的特征提取工具:
from torchvision.models.feature_extraction import get_graph_node_names, create_feature_extractor # 先打印所有推理阶段的节点名,找到avgpool对应的实际节点名 train_nodes, eval_nodes = get_graph_node_names(model) print(eval_nodes) # 替换下面的'avgpool'为你找到的实际节点名 feature_extractor = create_feature_extractor(model, return_nodes=['avgpool']) feature_extractor.eval() def get_vector(image_path): img = Image.open(image_path).convert('RGB') transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) t_img = transform(img).unsqueeze(0) with torch.no_grad(): out = feature_extractor(t_img) feature = out['avgpool'].flatten() return feature.cpu().numpy()
内容的提问来源于stack exchange,提问作者Derrick Xiao
相关产品推荐
相关产品推荐

