!转载请注明原文地址!——东方旅行者

更多行人重识别文章移步我的专栏:行人重识别专栏

本文目录

  • 模型结构(ReIDNet.py)
    • 一、ReIDNet.py作用
    • 二、ReIDNet.py编写思路
    • 三、代码

模型结构(ReIDNet.py)

一、ReIDNet.py作用

本文件指定了网络的结构,并根据“损失函数类型”决定网络返回哪些计算结果。本模型适用于表征学习与度量学习阶段,在之后编写AlignedReID时,还需要对本网络做部分修改。

二、ReIDNet.py编写思路

  • 论文《AlignedReID: Surpassing Human-Level Performance in Person Re-Identification》中基础网络为ResNet50,受算力限制使用AlexNet代替。
  • 自定义的网络需要继承torch.nn当中的Module类。在torch.nn.modules下的Module.py中介绍该类是所有神经网络的基础类,自定义的网络类需要继承此类。同时需要重写其中的两个方法__init__(),forward(),第一个方法用于初始化网络,第二个方法用于网络的计算前向传播结果(反向传播不需要自己编写)。

注,以下假设每次训练的batch批量为32,输入图片为128*64,3通道。

  • __init__方法有三个参数:第一个参数num_classes指定网络训练时输出的分类结果有几个类。第二个参数loss指定训练网络使用的损失函数,有softmax、metric、softmax+matric三种。Softmax是表征学习损失,使用该损失则网络输出的是经过全连接层输出的分类向量(维度[32, 751])。Metric是度量学习损失,使用该损失则网络输出的是未经过全连接层的特征向量(维度[32, 2048])。若使用Softmax+Metric,则说明该网络为AlingedReID网络,同时计算表征学习损失与度量学习损失,网络不仅输出分类向量(维度[32, 751])、特征向量(维度[32, 2048])还输出局部特征向量(维度[32, 128, 3, 1])。第三个参数aligned指定该网络是否使用AlignedReID的局部特征分支,若该参数为True,则使用AlingedReID局部特征分支,网络需要输出分类向量(维度[32, 751])、特征向量(维度[32, 2048])与局部特征向量(维度[32, 128, 3, 1])。
  • __init__方法需要首先使用父类的初始化方法super().__init__(),然后指定基础网络这里可以使用torchvision.models.中的可选网络并尽量将预训练参数指定为True,该模型预训练的数据集是ImageNet数据集。指定完基础网络之后,需要对基础网络做一定修改,我们使用基础网络一般不需要使用其池化层与最后的全连接层,这两个层我们可以根据需要子集指定,所以需要对基础网络进行修改,使用list(yournet.children())将网络按照层次分开,然后只选取你想要的层(特征层),然后前面加星号将列表内元素每一个都作为nn.Sequential单独参数形成一个新的网络层序列,注意nn.Sequential函数不能是list,只能是网络层。然后根据需要加入全连接层将特征向量转换到指定大小。之后指定分类器也就是另一个全连接层将特征向量转化到目标分类数目。
  • 总结网络结构,该网络使用基础网络的特征层、两个全连接层(一个标准化特征向量,一个用作分类器计算分类向量)。
  • forward方法用于指定前向传播计算过程。首先输入x,维度(32, 3, 128, 64),经过基础网络形成非标准规模的特征向量x1,维度(32, 256, 3, 1),然后该特征向量经过一个平均池化层形成新特征向量,维度(32, 256, 1, 1),然后使用torch张量的view函数改变特征向量维度为(32, 256),再经过一个调整特征向量维度的全连接层即可计算出最终的全局特征向量f,维度(32, 2048)。若模型处于测试状态,则结束,返回全局特征向量f;若模型处于训练阶段(没有使用模型的eval()方法),则利用分类器(也是一个全连接层)计算分类向量y,维度(32,751)。
  • forward函数共可以计算全局特征向量f,分类向量y。根据损失函数,若损失函数为softmax,则返回y;若损失函数为metric,则返回f;若损失函数为softmax与metric,则返回y,f。

三、代码

import torch
import torchvision
from torch import nn
from torch.nn import functional as F
from IPython import embed 
"""
该文件指定网络的结构
根据“是否计算局部特征、损失函数类型”决定网络返回哪些计算结果
"""
class ReIDNet(nn.Module):
    """
    自定义的网络需要继承torch.nn当中的Module类
    Module.py类是所有神经网络的基础类,自定义的网络类需要继承此类,同时需要重写其中的两个方法
    __init__(),用于初始化网络
    forward(),用于网络的计算前向传播结果(反向传播不需要自己编写)
    """
    def __init__(self, num_classes, loss={'softmax, metric'},**kwargs):
        #第一个参数num_classes指定网络训练时输出的分类结果有几个类
        #第二个参数loss指定训练网络使用的损失函数
        super().__init__()
        orinet=torchvision.models.alexnet(pretrained=True)#预训练参数指定为True,预训练的数据集是ImageNet数据集
        self.loss=loss
        #进行基础网络修改
        """
        使用list(yournet.children())将网络按照层次分开
        list前面加星号将列表内元素每一个都作为nn.Sequential单独参数形成一个新的网络层序列
        !!注意nn.Sequential函数不能是list,只能是网络层!!
        """
        self.basenet=nn.Sequential(*list(orinet.children())[0:1])
        #将特征向量转化到目标规模
        self.linear=nn.Linear(256, 2048)
        #分类器
        self.classifier=nn.Linear(2048, num_classes)
    def forward(self, x):
        x=self.basenet(x)
        cnn_result=F.avg_pool2d(x, x.size()[2:]).view(x.size(0),-1)
        f=self.linear(cnn_result)
        #归一化
        f=1.*f / (torch.norm(f,2,dim=-1, keepdim=True).expand_as(f)+1e-12)
        #如果是用于测试,只返回feature张量
        if not self.training:
            return f
        
        if self.loss=={'softmax'}:#表征学习
            y=self.classifier(f)
            return y
        elif self.loss=={'metric'}:#度量学习
            return f
        elif self.loss=={'softmax, metric'}:#表征学习度量学习结合
            y=self.classifier(f)
            return y,f
        else:
            print('loss setting error')