Pytorch 如何将1x1卷积作为分类层添加到VGG?

Pytorch 如何将1x1卷积作为分类层添加到VGG?,pytorch,vgg-net,Pytorch,Vgg Net,我正在尝试使用VGG16的前5层作为特征提取器,使用Imagenet预先训练的权重来训练神经网络。这些层包含5个最大池层,将图像大小减少到原始图像大小的1/32。对于尺寸为640x360的图像,我有20x11和512个通道的激活图 我想将每个激活划分为20个类,通过创建1x1卷积将512个通道作为输入,如下所示: #模型定义 类BlockWiseCSRNet(nn.模块): """ 顺时针分类法实现纸张计数对象 一种CRSNet后端方法的实现 """ 定义初始值(自身、负载权重=False、计

我正在尝试使用VGG16的前5层作为特征提取器,使用Imagenet预先训练的权重来训练神经网络。这些层包含5个最大池层,将图像大小减少到原始图像大小的1/32。对于尺寸为640x360的图像,我有20x11和512个通道的激活图

我想将每个激活划分为20个类,通过创建1x1卷积将512个通道作为输入,如下所示:


#模型定义
类BlockWiseCSRNet(nn.模块):
"""
顺时针分类法实现纸张计数对象
一种CRSNet后端方法的实现
"""
定义初始值(自身、负载权重=False、计数级别=10):
超级(BlockWiseCSRNet,self)。\uuuu初始化
self.seen=0
self.backend_feat=[64,64,'M',128,128,'M',256,256,256,'M',512,512,512,'M',512,512,512,'M']
self.backend=make_层(self.backend_专长)
self.count\u levels=计数\u levels
self.classification=nn.Sequential(
nn.Conv2d(输入通道=512,输出通道=计数级别,内核大小=1),
nn.Softmax(尺寸=1)
)
如果未加载重量:
mod=models.vgg16(预训练=真)
self.\u初始化\u权重()
#将重量从VGG预训练复制到前端
对于self.backend.state_dict().items()中的k,v:
如果“重量”单位为k:
self.backend.state_dict()[k]。数据[:]=mod.state_dict()['features.+k][1]。数据[:]
其他:
self.backend.state_dict()[k].data=mod.state_dict()['features.+k][1]。数据
def冻结_后端(自身):
"""
冻结后端参数以使其不可训练
:返回:
"""
对于self.backend.parameters()中的p:
p、 需要_grad=False
def解冻_分类(自):
对于self.classification.parameters()中的p:
p、 需要_grad=True
def前进(自身,x):
x=self.backend(x)
x=自分类(x)
返回x
def_初始化_权重(自身):
对于self.modules()中的m:
如果存在(m,nn.Conv2d):
nn.初始正常(m.重量,标准=0.01)
如果m.bias不是无:
nn.初始常数(m.偏差,0)
elif isinstance(m,nn.2d):
nn.初始常数(m.重量,1)
nn.初始常数(m.偏差,0)
def make_层(cfg,in_Channel=3,batch_norm=False,Diagration=False):
如果扩张:
d_率=2
其他:
d_率=1
层=[]
对于cfg中的v:
如果v=='M':
层+=[nn.MaxPool2d(内核大小=2,步幅=2)]
其他:
conv2d=nn.conv2d(在通道中,v,内核大小=3,填充率=d\u,扩展率=d\u)
如果批次规格:
层+=[conv2d,nn.BatchNorm2d(v),nn.ReLU(inplace=True)]
其他:
层+=[conv2d,nn.ReLU(inplace=True)]
in_通道=v
返回nn.顺序(*层)
###相关列车回路
模型=分块CSRNET(计数级别=20)
标准=torch.nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(过滤器(lambda x:x.requires_grad,model.parameters()),args.learning_rate)
#列车环路台阶
def序列步骤(历元、设备、数据加载器、模型、标准、优化器):
打印('train step!')
运行损耗=0.0
#将模型设置为训练模式
模型列车()
#只训练分类层,保留后端的权重
model.freeze_backend()
模型.解冻_分类()
对于enumerate(data_loader)中的mini_batch(批次、标签、文件名):
#转移到GPU
批处理=批处理到(设备)
标签=标签。到(设备)
#将参数梯度归零
optimizer.zero_grad()
#工艺批次
输出=型号(批次)
损失=标准(输出、标签)
a=列表(model.classification.parameters())[0]。克隆()
loss.backward()
optimizer.step()
b=列表(model.classification.parameters())[0]。克隆()
打印('weights updated?{}'。格式(非torch.equal(a.data,b.data)))
#打印(torch.sum(model.classification[0].weight.sum())
#打印统计信息每个打印统计信息步骤小批量
运行损失+=损失。项目()
打印('[{}]列车总损耗:{}'。格式(历元,运行损耗))
此解决方案能够处理图像并以适当的大小激活输出

但是,我无法训练网络。我使用的是CrossEntropyLoss和Adam optimizer,但输出映射始终保持不变(即使在多次训练迭代之后)

#批处理是一个映像
batch.shape->torch.Size([1,3,360,640])
输出=型号(批次)
output.shape->torch.Size([1,20,11,20])
标准=torch.nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(model.parameters(),args.learning\u rate)
_,预测等级图=火炬最大值(输出,尺寸=1)
#预测的类映射始终为0
我尝试了几种学习速率和配置,但预测的类映射始终为0。我调试了权重更新,更新始终为0(优化器步骤前后权重相等)

我做错了什么?我不确定问题是在体系结构还是在培训循环中(我从PyTorch教程中获取)

编辑:在检查了净输出的内容之后,我认为问题在于输出中的所有通道对于所有图像都具有相同的值。因此:

all_means=[范围(0,outputs.shape[1])内t的输出[0,t,:,:]
有一个所有位置相等的向量


谢谢

输出形状不应该是2D吗?(批次大小,数量类)?输出形状已经是2d,[1,20,11,20],批次大小=1,数量类=20,形状11x20什么是11 x 20?11x20是最终激活映射尺寸(h