当前位置:   article > 正文

【OpenGait 之 GaitSet 系列】 了解 GaitSet 代码与原论文算法框架图的对应关系以及算法流程

opengait

最近在使用AutoDL云服务器跑步态识别的代码,用的是开放步态识别框架OpenGait,记录一下自己跑代码的步骤和遇到的问题以及解决方式。

这篇文章主要记录OpenGait项目里GaitSet代码与原论文框架图的对应关系以及算法流程。


一、GaitSet论文算法框架图

论文题目:《Gaitset: Regarding gait as a set for cross-view gait recognition》
下载地址:GaitSet2019

注:GaitSet最初版本是2019年发布的,2021年该团队又在2019年版本基础上发表了另一篇文章,题目为《GaitSet: Cross-view gait recognition through utilizing gait as a deep set》,21年和19年文章内容大致相同。2021版本下载地址为:GaitSet2021

Gaitset算法框架图如下:
在这里插入图片描述

二、OpenGait项目里的GaitSet代码

为什么要强调“OpenGait项目里的GaitSet代码”?因为源代码和OpenGait项目里的在组织结构上不太一样,本文只是针对OpenGait项目里的。

OpenGait项目里的GaitSet代码文件路径为:OpenGait/opengait/modeling/models/gaitset.py

gaitset.py内容如下:

import torch
import copy
import torch.nn as nn

from ..base_model import BaseModel
from ..modules import SeparateFCs, BasicConv2d, SetBlockWrapper, HorizontalPoolingPyramid, PackSequenceWrapper

class GaitSet(BaseModel):
    def build_network(self, model_cfg):
        in_c = model_cfg['in_channels']
        self.set_block1 = nn.Sequential(BasicConv2d(in_c[0], in_c[1], 5, 1, 2),
                                        nn.LeakyReLU(inplace=True),
                                        BasicConv2d(in_c[1], in_c[1], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        nn.MaxPool2d(kernel_size=2, stride=2))

        self.set_block2 = nn.Sequential(BasicConv2d(in_c[1], in_c[2], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        BasicConv2d(in_c[2], in_c[2], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        nn.MaxPool2d(kernel_size=2, stride=2))

        self.set_block3 = nn.Sequential(BasicConv2d(in_c[2], in_c[3], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        BasicConv2d(in_c[3], in_c[3], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True))

        self.gl_block2 = copy.deepcopy(self.set_block2)
        self.gl_block3 = copy.deepcopy(self.set_block3)
        
        self.set_block1 = SetBlockWrapper(self.set_block1)
        self.set_block2 = SetBlockWrapper(self.set_block2)
        self.set_block3 = SetBlockWrapper(self.set_block3)
        
        self.Head = SeparateFCs(**model_cfg['SeparateFCs'])

        self.set_pooling = PackSequenceWrapper(torch.max)

        self.HPP = HorizontalPoolingPyramid(bin_num=model_cfg['bin_num'])
        
    def forward(self, inputs):
        ipts, labs, _, _, seqL = inputs
        sils = ipts[0]  # [n, s, h, w]
        if len(sils.size()) == 4:
            sils = sils.unsqueeze(1)

        del ipts
        
        outs = self.set_block1(sils)
        gl = self.set_pooling(outs, seqL, options={"dim": 2})[0]
        gl = self.gl_block2(gl)

        outs = self.set_block2(outs)
        gl = gl + self.set_pooling(outs, seqL, options={"dim": 2})[0]
        gl = self.gl_block3(gl)

        outs = self.set_block3(outs)
        outs = self.set_pooling(outs, seqL, options={"dim": 2})[0]
        gl = gl + outs

        feature1 = self.HPP(outs)  # [n, c, p]
        feature2 = self.HPP(gl)  # [n, c, p]
        feature = torch.cat([feature1, feature2], -1)  # [n, c, p]
        embs = self.Head(feature)

        n, _, s, h, w = sils.size()
        retval = {
            'training_feat': {
                'triplet': {'embeddings': embs, 'labels': labs}
            },
            'visual_summary': {
                'image/sils': sils.view(n*s, 1, h, w)
            },
            'inference_feat': {
                'embeddings': embs
            }
        }
        return retval
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

三、GaitSet 代码与论文算法框架图的对应关系

1、3个set_block:提取每一帧的特征
①代码:

        self.set_block1 = nn.Sequential(BasicConv2d(in_c[0], in_c[1], 5, 1, 2),
                                        nn.LeakyReLU(inplace=True),
                                        BasicConv2d(in_c[1], in_c[1], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        nn.MaxPool2d(kernel_size=2, stride=2))

        self.set_block2 = nn.Sequential(BasicConv2d(in_c[1], in_c[2], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        BasicConv2d(in_c[2], in_c[2], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        nn.MaxPool2d(kernel_size=2, stride=2))

        self.set_block3 = nn.Sequential(BasicConv2d(in_c[2], in_c[3], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True),
                                        BasicConv2d(in_c[3], in_c[3], 3, 1, 1),
                                        nn.LeakyReLU(inplace=True))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

②对应原文算法图位置:
在这里插入图片描述
2、2个gl_block:提取所有帧集合后的特征
①代码

        self.gl_block2 = copy.deepcopy(self.set_block2)
        self.gl_block3 = copy.deepcopy(self.set_block3)
  • 1
  • 2

②对应原文算法图位置:
在这里插入图片描述
③注:gl_block只有2个,分别是gl_block2和gl_block3,没有gl_block1,我认为是为了和set_block的数字对应

3、SetBlockWrapper操作:不对应原文图片内容,只是为了把3个set_block 封装起来

        self.set_block1 = SetBlockWrapper(self.set_block1)
        self.set_block2 = SetBlockWrapper(self.set_block2)
        self.set_block3 = SetBlockWrapper(self.set_block3)
  • 1
  • 2
  • 3

4、SeparateFCs:独立全连接操作
①代码

        self.Head = SeparateFCs(**model_cfg['SeparateFCs'])
  • 1

②对应原文算法图位置:
在这里插入图片描述
5、set_pooling:集合池化操作
①代码:

       self.set_pooling = PackSequenceWrapper(torch.max)
  • 1

②对应原文算法图位置:
在这里插入图片描述
6、HPP:水平金字塔池化操作
①代码:

       self.HPP = HorizontalPoolingPyramid(bin_num=model_cfg['bin_num'])
  • 1

②对应原文算法图位置:
在这里插入图片描述

四、GaitSet 代码与算法流程对应关系

1、流程1
①代码

        outs = self.set_block1(sils)
        gl = self.set_pooling(outs, seqL, options={"dim": 2})[0]
        gl = self.gl_block2(gl)
  • 1
  • 2
  • 3

②流程对应关系:
在这里插入图片描述
③解释:sils经过set_block1输出为蓝色out,所有蓝色out经过set_pooling操作输出为绿色gl,绿色gl经过gl_block2输出为正方体绿色gl,接下来的流程参考该解释

2、流程2
①代码

        outs = self.set_block2(outs)
        gl = gl + self.set_pooling(outs, seqL, options={"dim": 2})[0]
        gl = self.gl_block3(gl)
  • 1
  • 2
  • 3

②流程对应关系:
在这里插入图片描述
3、流程3
①代码:

        outs = self.set_block3(outs)
        outs = self.set_pooling(outs, seqL, options={"dim": 2})[0]
        gl = gl + outs
  • 1
  • 2
  • 3

②流程对应关系:
在这里插入图片描述
4、流程4
①代码

        feature1 = self.HPP(outs)  # [n, c, p]
        feature2 = self.HPP(gl)  # [n, c, p]
        feature = torch.cat([feature1, feature2], -1)  # [n, c, p]
        embs = self.Head(feature)
  • 1
  • 2
  • 3
  • 4

②流程对应关系:
在这里插入图片描述


总结

欢迎使用OpenGait研究步态识别的伙伴进行交流

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/436960
推荐阅读
  

闽ICP备14008679号