Deep High Resolution Net(HRNet)代码分析及网络架构

2020/07/01

Hey,HRNet之前已经在论文层面做过介绍了,今天我从网络结构的角度和代码层面再给给大家分析一下。

1、网络架构图:

2、代码分析

2.1 ResNet模块

虽然很熟悉了,但是还是介绍一下resnet网络的基本模块。如下的左图对应于resnet-18/34使用的基本块,右图是50/101/152所使用的,由于他们都比较深,所以有图相比于左图使用了1x1卷积来降维。

  • (a) conv3x3: 没啥好解释的,将原有的pytorch函数固定卷积和尺寸为3重新封装了一次;
  • (b) BasicBlock: 搭建上图左边的模块。
  • (1) 每个卷积块后面接BN层进行归一化
  • (2) 残差接前的3x3卷之后只接入BN,不使用ReLU,避免加和之后的特征皆正,保持特征的多
  • (3) 跳层连接:两种情况,当模块输入和残差支路(3x3->3x3)的通道数一致,直接相加;当两者通道不一致(一般生在分辨率降低之后,同分辨率一般通道数一致),需要块输入特征使用1x1卷积进行升/降(步长为2,上面了分辨率会降低),之后同接BN,不用ReLU。
  • (c) Bottleneck: 搭建上图右边的模块。
  • (1) 使用1x1卷先降,再使用3x3卷积进行特征提取,最后再使用1x1卷度升回去;
  • (2) 每个卷积块后面接BN层进行归一化
  • (2) 残差接前的1x1卷之后只接入BN,不使用ReLU,避免加和之后的特征皆正,保持特征的多性。
  • (3) 跳层连接:两种情况,当模块输入和残差支路(1x1->3x3->1x1)的通道数一致,直接相加;当两者通道不一致(一般生在分辨率降低之后,同分辨率一般通道数一致),需要块输入特征使用1x1卷积进行升/降(步长为2,上面了分辨率会降低),之后同接BN,不用ReLU。

·       def conv3x3(in_planes, out_planes, stride=1):

·           """3x3 convolution with padding"""

·           return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,

·                            padding=1, bias=False)

·      

·      

·       class BasicBlock(nn.Module):

·           expansion = 1

·      

·           def __init__(self, inplanes, planes, stride=1, downsample=None):

·               super(BasicBlock, self).__init__()

·               self.conv1 = conv3x3(inplanes, planes, stride)

·               self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)

·               self.relu = nn.ReLU(inplace=True)

·               self.conv2 = conv3x3(planes, planes)

·               self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)

·               self.downsample = downsample

·               self.stride = stride

·      

·           def forward(self, x):

·               residual = x

·      

·               out = self.conv1(x)

·               out = self.bn1(out)

·               out = self.relu(out)

·      

·               out = self.conv2(out)

·               out = self.bn2(out)

·      

·               if self.downsample is not None:

·                   residual = self.downsample(x)

·      

·               out += residual

·               out = self.relu(out)

·      

·               return out

·      

·      

·       class Bottleneck(nn.Module):

·           expansion = 4

·      

·           def __init__(self, inplanes, planes, stride=1, downsample=None):

·               super(Bottleneck, self).__init__()

·               self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)

·               self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)

·               self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,

·                                      padding=1, bias=False)

·               self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)

·               self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1,

·                                      bias=False)

·               self.bn3 = nn.BatchNorm2d(planes * self.expansion,

·                                         momentum=BN_MOMENTUM)

·               self.relu = nn.ReLU(inplace=True)

·               self.downsample = downsample

·               self.stride = stride

·      

·           def forward(self, x):

·               residual = x

·      

·               out = self.conv1(x)

·               out = self.bn1(out)

·               out = self.relu(out)

·      

·               out = self.conv2(out)

·               out = self.bn2(out)

·               out = self.relu(out)

·      

·               out = self.conv3(out)

·               out = self.bn3(out)

·      

·               if self.downsample is not None:

·                   residual = self.downsample(x)

·      

·               out += residual

·               out = self.relu(out)

·      

·               return out

2.2 HighResolutionModule (高分辨率模块)

当仅包含一个分支时,生成该分支,没有融合模块,直接返回;当包含不仅一个分支时,先将对应分支的输入特征输入到对应分支,得到对应分支的输出特征;紧接着执行融合模块。

  • (a) _check_branches: 判断num_branches (int) 和 num_blocks, num_inchannels, num_channels (list) 三者的长度是否一致,否则报错;
  • (b) _make_one_branch: 搭建一个分支,单个分支内部分辨率相等,一个分支由num_blocks[branch_index]个block组成,block可以是两种ResNet模块中的一种;
  • (1) 首先判断是否降或者出的通道(num_inchannels[branch_index]和 num_channels[branch_index] * block.expansion(通道扩张率))是否一致,不一致使用1z1积进度升/降,后接BN,不使用ReLU
  • (2) 顺序搭建num_blocks[branch_index]block,第一个block需要考是否降的情况,所以独拿出来,后面1 到 num_blocks[branch_index]block完全一致,使用循搭建就行。此注意在行完第一个block后将num_inchannels[branch_index重新赋值为 num_channels[branch_index] * block.expansion
  • (c) _make_branches: 循环调用_make_one_branch函数创建多个分支;
  • (d) _make_fuse_layers:
  • (1) 如果分支数等于1,返回None,说明此事不需要使用融合模块;
  • (2) 双层循环:for i in range(num_branches if self.multi_scale_output else 1):的作用是,如果需要产生多分辨率的结果,就双层循环num_branches 次,如果只需要产生最高分辨率的表示,就将i确定为0

(2.1) 如果j > i,此时的目标是将所有分支上采样到和i分支相同的分辨率并融合,也就是说j所代表的分支分辨率比i分支低,2**(j-i)表示j分支上采样这么多倍才能和i分支分辨率相同。先使用1x1卷积将j分支的通道数变得和i分支一致,进而跟着BN,然后依据上采样因子将j分支分辨率上采样到和i分支分辨率相同,此处使用最近邻插值;

  • (2.2) 如果j = i,也就是自身与自身之不需要融合,nothing to do;
  • (2.3) 如果j < i,转换角色,此时最终目标是将所有分支采样到和i分支相同的分辨率并融合,注意,此时j所代表的分支分辨率比i分支高,正好和(2.1)相反。此时再次内嵌了一个循环,这层循环的作用是当i-j > 1时,也就是说两个分支的分辨率差了不止二倍,此时还是两倍两倍往上采样,例如i-j = 2时,j分支的分辨率比i分支大4倍,就需要上采样两次,循环次数就是2;
    • (2.3.1) 当k == i - j - 1时,举个例子,i = 2,j = 1, 此时仅一次,并采用当前模,此直接将j分支使用3x3的步长为2的卷下采(不使用bias),后接BN,不使用ReLU;

(2.3.2) 当k != i - j - 1时,举个例子i = 3,j = 1, 此两次,先采用当前模,将j分支使用3x3的步长为2的卷下采(不使用bias)两倍,后接BN和ReLU,跟着再使用(2.3.1)中的模了保最后一次二倍下采的卷操作不使用ReLU,猜也是了保融合后特征的多性;

  • (e) forward: 前向传播函数,利用以上函数的功能搭建一个HighResolutionModule;
  • (1) 当仅包含一个分支时,生成该分支,没有融合模块,直接返回;
  • (2) 当包含不仅一个分支时,先将对应分支的输入特征输入到对应分支,得到对应分支的输出特征;紧接着执行融合模块;
    • (2.1) 循对应分支的入特征入到对应分支模型中,得到对应分支的出特征;
    • (2.2) 融合模这张图看,很容易看懂。每次多尺度之的加法运算都是从最上面的尺度开始往下加,所以y = x[0] if i == 0 else self.fuse_layers[i][0](x[0]);加到他自己的候,不需要经过融合函数的理,直接加,所以if i == j: y = y + x[j];遇到不是最上面的尺度那个特征或者它本身相同分辨率的那个特征图时,需要经过融合函数理再加,所以y = y + self.fuse_layers[i][j](x[j])。最后将ReLU激活后的融合(加法)特征append到x_fusex_fuse度等于1尺度出)或者num_branches(多尺度出)。

class HighResolutionModule(nn.Module):

    def __init__(self, num_branches, blocks, num_blocks, num_inchannels,

                 num_channels, fuse_method, multi_scale_output=True):

        super(HighResolutionModule, self).__init__()

        self._check_branches(

            num_branches, blocks, num_blocks, num_inchannels, num_channels)

 

        self.num_inchannels = num_inchannels

        self.fuse_method = fuse_method

        self.num_branches = num_branches

 

        self.multi_scale_output = multi_scale_output

 

        self.branches = self._make_branches(

            num_branches, blocks, num_blocks, num_channels)

        self.fuse_layers = self._make_fuse_layers()

        self.relu = nn.ReLU(True)

 

    def _check_branches(self, num_branches, blocks, num_blocks,

                        num_inchannels, num_channels):

        if num_branches != len(num_blocks):

            error_msg = 'NUM_BRANCHES({}) <> NUM_BLOCKS({})'.format(

                num_branches, len(num_blocks))

            logger.error(error_msg)

            raise ValueError(error_msg)

 

        if num_branches != len(num_channels):

            error_msg = 'NUM_BRANCHES({}) <> NUM_CHANNELS({})'.format(

                num_branches, len(num_channels))

            logger.error(error_msg)

            raise ValueError(error_msg)

 

        if num_branches != len(num_inchannels):

            error_msg = 'NUM_BRANCHES({}) <> NUM_INCHANNELS({})'.format(

                num_branches, len(num_inchannels))

            logger.error(error_msg)

            raise ValueError(error_msg)

 

    def _make_one_branch(self, branch_index, block, num_blocks, num_channels,

                         stride=1):

        # ---------------------------(1) begin---------------------------- #         downsample = None

        if stride != 1 or \

           self.num_inchannels[branch_index] != num_channels[branch_index] * block.expansion:

            downsample = nn.Sequential(

                nn.Conv2d(

                    self.num_inchannels[branch_index],

                    num_channels[branch_index] * block.expansion,

                    kernel_size=1, stride=stride, bias=False

                ),

                nn.BatchNorm2d(

                    num_channels[branch_index] * block.expansion,

                    momentum=BN_MOMENTUM

                ),

            )

        # ---------------------------(1) end---------------------------- #       

        # ---------------------------(2) begin---------------------------- #         layers = []

        layers.append(

            block(

                self.num_inchannels[branch_index],

                num_channels[branch_index],

                stride,

                downsample

            )

        )

        # ---------------------------(2) middle---------------------------- #         self.num_inchannels[branch_index] = num_channels[branch_index] * block.expansion

        for i in range(1, num_blocks[branch_index]):

            layers.append(

                block(

                    self.num_inchannels[branch_index],

                    num_channels[branch_index]

                )

            )

        # ---------------------------(2) end---------------------------- #         return nn.Sequential(*layers)

 

    def _make_branches(self, num_branches, block, num_blocks, num_channels):

        branches = []

 

        for i in range(num_branches):

            branches.append(

                self._make_one_branch(i, block, num_blocks, num_channels)

            )

 

        return nn.ModuleList(branches)

 

    def _make_fuse_layers(self):

        # ---------------------------(1) begin---------------------------- #         if self.num_branches == 1:

            return None

        # ---------------------------(1) end---------------------------- # 

       

        num_branches = self.num_branches

        num_inchannels = self.num_inchannels

        # ---------------------------(2) begin---------------------------- #         fuse_layers = []

        for i in range(num_branches if self.multi_scale_output else 1):

            fuse_layer = []

            for j in range(num_branches):

                # ---------------------------(2.1) begin---------------------------- #                 if j > i:

                    fuse_layer.append(

                        nn.Sequential(

                            nn.Conv2d(

                                num_inchannels[j],

                                num_inchannels[i],

                                1, 1, 0, bias=False

                            ),

                            nn.BatchNorm2d(num_inchannels[i]),

                            nn.Upsample(scale_factor=2**(j-i), mode='nearest')

                        )

                    )

                # ---------------------------(2.1) end---------------------------- #                

                # ---------------------------(2.2) begin---------------------------- #                 elif j == i:

                    fuse_layer.append(None)

                # ---------------------------(2.2) end---------------------------- #                

                # ---------------------------(2.3) begin---------------------------- #                 else:

                    conv3x3s = []

                    for k in range(i-j):

                        # ---------------------------(2.3.1) begin---------------------------- #                         if k == i - j - 1:

                            num_outchannels_conv3x3 = num_inchannels[i]

                            conv3x3s.append(

                                nn.Sequential(

                                    nn.Conv2d(

                                        num_inchannels[j],

                                        num_outchannels_conv3x3,

                                        3, 2, 1, bias=False

                                    ),

                                    nn.BatchNorm2d(num_outchannels_conv3x3)

                                )

                            )

                        # ---------------------------(2.3.1) end---------------------------- #                        

                        # ---------------------------(2.3.1) begin---------------------------- #                         else:

                            num_outchannels_conv3x3 = num_inchannels[j]

                            conv3x3s.append(

                                nn.Sequential(

                                    nn.Conv2d(

                                        num_inchannels[j],

                                        num_outchannels_conv3x3,

                                        3, 2, 1, bias=False

                                    ),

                                    nn.BatchNorm2d(num_outchannels_conv3x3),

                                    nn.ReLU(True)

                                )

                            )

                        # ---------------------------(2.3.1) end---------------------------- #                     # ---------------------------(2.3) end---------------------------- #                     fuse_layer.append(nn.Sequential(*conv3x3s))

            fuse_layers.append(nn.ModuleList(fuse_layer))

            # ---------------------------(2) end---------------------------- # 

        return nn.ModuleList(fuse_layers)

 

    def get_num_inchannels(self):

        return self.num_inchannels

 

    def forward(self, x):

        # ---------------------------(1) begin---------------------------- #         if self.num_branches == 1:

            return [self.branches[0](x[0])]

        # ---------------------------(1) end---------------------------- # 

        # ---------------------------(2) begin---------------------------- #         # ---------------------------(2.1) begin---------------------------- #         for i in range(self.num_branches):

            x[i] = self.branches[i](x[i])

        # ---------------------------(2.1) end---------------------------- # 

        # ---------------------------(2.2) begin---------------------------- #         x_fuse = []

 

        for i in range(len(self.fuse_layers)):

            y = x[0] if i == 0 else self.fuse_layers[i][0](x[0])

            for j in range(1, self.num_branches):

                if i == j:

                    y = y + x[j]

                else:

                    y = y + self.fuse_layers[i][j](x[j])

            x_fuse.append(self.relu(y))

        # ---------------------------(2.2) end---------------------------- #         # ---------------------------(2) end---------------------------- # 

        return x_fuse

 

2.3 PoseHighResolutionNet (模型整体结构)

该模块主要包含5个阶段,第一阶段由stem模块构成,第2、3、4阶段由transition模块,HighResolutionModule模块构成,最后一个阶段就是final_layer,其中第一阶段包含两次下采样,剩余阶段的最终结果没有下采样,所以产生的热图为原始输入图像分辨率的1/4。第2、3、4阶段的主要超参数有:

POSE_HIGH_RESOLUTION_NET.STAGE2.NUM_MODULES = 1            # 当前段HighResolutionModule模的数目 POSE_HIGH_RESOLUTION_NET.STAGE2.NUM_BRANCHES = 2           # 当前段分支数目 POSE_HIGH_RESOLUTION_NET.STAGE2.NUM_BLOCKS = [4, 4]        # 当前段每个分支上使用BLOCK块结构的数目 POSE_HIGH_RESOLUTION_NET.STAGE2.NUM_CHANNELS = [32, 64]    # 当前段每个分支的通道数(*=expansion) POSE_HIGH_RESOLUTION_NET.STAGE2.BLOCK = 'BASIC'            # 使用4.1定块结构的哪一种 POSE_HIGH_RESOLUTION_NET.STAGE2.FUSE_METHOD = 'SUM'        # 融合方式,求和是串 

POSE_HIGH_RESOLUTION_NET.STAGE3.NUM_MODULES = 1

POSE_HIGH_RESOLUTION_NET.STAGE3.NUM_BRANCHES = 3

POSE_HIGH_RESOLUTION_NET.STAGE3.NUM_BLOCKS = [4, 4, 4]

POSE_HIGH_RESOLUTION_NET.STAGE3.NUM_CHANNELS = [32, 64, 128]

POSE_HIGH_RESOLUTION_NET.STAGE3.BLOCK = 'BASIC'

POSE_HIGH_RESOLUTION_NET.STAGE3.FUSE_METHOD = 'SUM'

 

POSE_HIGH_RESOLUTION_NET.STAGE4.NUM_MODULES = 1

POSE_HIGH_RESOLUTION_NET.STAGE4.NUM_BRANCHES = 4

POSE_HIGH_RESOLUTION_NET.STAGE4.NUM_BLOCKS = [4, 4, 4, 4]

POSE_HIGH_RESOLUTION_NET.STAGE4.NUM_CHANNELS = [32, 64, 128, 256]

POSE_HIGH_RESOLUTION_NET.STAGE4.BLOCK = 'BASIC'

POSE_HIGH_RESOLUTION_NET.STAGE4.FUSE_METHOD = 'SUM'

(a) __init__ & forward: 这两个模块一般都是对应的,所以放在一块;

  •  

 

(1) stem:

卷积(步长2)-> BN -> 卷积(步长2)-> BN -> ReLU -> Bottleneck x 4 (H/4, W/4, 256)

  • (2)stage2transition + HighResolutionModule BRANCHES = 2BASIC : [32, 64][4, 4]
  • (3)stage3transition + HighResolutionModule BRANCHES = 3BASIC : [32, 64, 128][4, 4, 4]
  • (4)stage4transition + HighResolutionModule BRANCHES = 4BASIC : [32, 64, 128, 256][4, 4, 4, 4]
  • (5)final_layer: 卷,no BN, no ReLU;
  • (b) _make_layer: 其在stem模块中调用,使用BasicBlock或者Bottleneck作为基本构造块,循环搭建,第一个块结构单独搭建,不包含在循环内部,主要是因为如果需要进行通道维度变换(64->256),只需要使用第一个块结构来执行,剩余1blocks的块循环搭建,这些块结构输入输出通道都一致(=256)
  • (c) _make_transition_layer: 从前一个stage的输出得到当前stage的不同分支,也就是不同分辨率的特征图。举例1:从stage1stage2,上一阶段输出特征图为单个分辨率(H/4, W/4, 256)stage2需要两个分辨率的分支,_make_transition_layer就需要产生(H/4, W/4)(H/8, W/8)两个特征图;
  • (1) 以当前stage生的最分支数最外,如果stage1存在(H/4, W/4)的特征,就判断特征的通道和所需要的通道数是否一致,一致的,直接拿来用,不一致的使用3x3卷变换(不解:什么使用了3x3卷,但是没有行padding?),后接BN和ReLU。此stage1不存在(H/8, W/8)的特征,就需要降采生3x3卷(步2),后接BN和ReLU,每次降采都将前一段最后一个分支(分辨率最小)的特征为输入;
  • (d) _make_stage: 依据参数文件定义的每个stageNUM_MODULES(都设定为1),调用HighResolutionModule模块进行多分支构建和分支之间的融合;此处代码中备注multi_scale_output is only used last module,只有当multi_scale_output = True并且是该阶段的最后一个模块时,才会设定reset_multi_scale_output = True,依据__init__函数中的设置,也就是说只有stage2、3中的那个HighResolutionModule模块是多尺度输出,stage4那个是单尺度输出;
  • x init_weights: 暂时还没看

·       blocks_dict = {

·           'BASIC': BasicBlock,

·           'BOTTLENECK': Bottleneck

·       }

·      

·      

·       class PoseHighResolutionNet(nn.Module):

·      

·           def __init__(self, cfg, **kwargs):

·               self.inplanes = 64

·               extra = cfg.MODEL.EXTRA

·               super(PoseHighResolutionNet, self).__init__()

·      

·           # ---------------------------(1) begin---------------------------- #         # stem net         self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1,

·                                      bias=False)

·               self.bn1 = nn.BatchNorm2d(64, momentum=BN_MOMENTUM)

·               self.conv2 = nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1,

·                                      bias=False)

·               self.bn2 = nn.BatchNorm2d(64, momentum=BN_MOMENTUM)

·               self.relu = nn.ReLU(inplace=True)

·               self.layer1 = self._make_layer(Bottleneck, 64, 4)

·               # ---------------------------(1) end---------------------------- # 

·               # ---------------------------(2) begin---------------------------- #         self.stage2_cfg = cfg['MODEL']['EXTRA']['STAGE2']

·               num_channels = self.stage2_cfg['NUM_CHANNELS']

·               block = blocks_dict[self.stage2_cfg['BLOCK']]

·               num_channels = [

·                   num_channels[i] * block.expansion for i in range(len(num_channels))

·               ]

·               self.transition1 = self._make_transition_layer([256], num_channels)

·               self.stage2, pre_stage_channels = self._make_stage(

·                   self.stage2_cfg, num_channels)

·               # ---------------------------(2) end---------------------------- # 

·               # ---------------------------(3) begin---------------------------- #         self.stage3_cfg = cfg['MODEL']['EXTRA']['STAGE3']

·               num_channels = self.stage3_cfg['NUM_CHANNELS']

·               block = blocks_dict[self.stage3_cfg['BLOCK']]

·               num_channels = [

·                   num_channels[i] * block.expansion for i in range(len(num_channels))

·               ]

·               self.transition2 = self._make_transition_layer(

·                   pre_stage_channels, num_channels)

·               self.stage3, pre_stage_channels = self._make_stage(

·                   self.stage3_cfg, num_channels)

·               # ---------------------------(3) end---------------------------- # 

·               # ---------------------------(4) begin---------------------------- #         self.stage4_cfg = cfg['MODEL']['EXTRA']['STAGE4']

·               num_channels = self.stage4_cfg['NUM_CHANNELS']

·               block = blocks_dict[self.stage4_cfg['BLOCK']]

·               num_channels = [

·                   num_channels[i] * block.expansion for i in range(len(num_channels))

·               ]

·               self.transition3 = self._make_transition_layer(

·                   pre_stage_channels, num_channels)

·               self.stage4, pre_stage_channels = self._make_stage(

·                   self.stage4_cfg, num_channels, multi_scale_output=False)

·               # ---------------------------(4) end---------------------------- # 

·               # ---------------------------(5) begin---------------------------- #         self.final_layer = nn.Conv2d(

·                   in_channels=pre_stage_channels[0],

·                   out_channels=cfg.MODEL.NUM_JOINTS,

·                   kernel_size=extra.FINAL_CONV_KERNEL,

·                   stride=1,

·                   padding=1 if extra.FINAL_CONV_KERNEL == 3 else 0

·               )

·               # ---------------------------(5) end---------------------------- # 

·               self.pretrained_layers = cfg['MODEL']['EXTRA']['PRETRAINED_LAYERS']

·      

·           def _make_transition_layer(

·                   self, num_channels_pre_layer, num_channels_cur_layer):

·               num_branches_cur = len(num_channels_cur_layer)

·               num_branches_pre = len(num_channels_pre_layer)

·      

·               # ---------------------------(1) begin---------------------------- #         transition_layers = []

·               for i in range(num_branches_cur):

·                   if i < num_branches_pre:

·                       if num_channels_cur_layer[i] != num_channels_pre_layer[i]:

·                           transition_layers.append(

·                               nn.Sequential(

·                                   nn.Conv2d(

·                                       num_channels_pre_layer[i],

·                                       num_channels_cur_layer[i],

·                                       3, 1, 1, bias=False

·                                   ),

·                                   nn.BatchNorm2d(num_channels_cur_layer[i]),

·                                   nn.ReLU(inplace=True)

·                               )

·                           )

·                       else:

·                           transition_layers.append(None)

·                   else:

·                       conv3x3s = []

·                       for j in range(i+1-num_branches_pre):

·                           inchannels = num_channels_pre_layer[-1]

·                           outchannels = num_channels_cur_layer[i] \

·                               if j == i-num_branches_pre else inchannels

·                           conv3x3s.append(

·                               nn.Sequential(

·                                   nn.Conv2d(

·                                       inchannels, outchannels, 3, 2, 1, bias=False

·                                   ),

·                                   nn.BatchNorm2d(outchannels),

·                                   nn.ReLU(inplace=True)

·                               )

·                           )

·                       transition_layers.append(nn.Sequential(*conv3x3s))

·               # ---------------------------(1) end---------------------------- # 

·               return nn.ModuleList(transition_layers)

·      

·           def _make_layer(self, block, planes, blocks, stride=1):

·               downsample = None

·               if stride != 1 or self.inplanes != planes * block.expansion:

·                   downsample = nn.Sequential(

·                       nn.Conv2d(

·                           self.inplanes, planes * block.expansion,

·                           kernel_size=1, stride=stride, bias=False

·                       ),

·                       nn.BatchNorm2d(planes * block.expansion, momentum=BN_MOMENTUM),

·                   )

·      

·               layers = []

·               layers.append(block(self.inplanes, planes, stride, downsample))

·               self.inplanes = planes * block.expansion

·               for i in range(1, blocks):

·                   layers.append(block(self.inplanes, planes))

·      

·               return nn.Sequential(*layers)

·      

·           def _make_stage(self, layer_config, num_inchannels,

·                           multi_scale_output=True):

·               num_modules = layer_config['NUM_MODULES']

·               num_branches = layer_config['NUM_BRANCHES']

·               num_blocks = layer_config['NUM_BLOCKS']

·               num_channels = layer_config['NUM_CHANNELS']

·               block = blocks_dict[layer_config['BLOCK']]

·               fuse_method = layer_config['FUSE_METHOD']

·      

·               modules = []

·               for i in range(num_modules):

·                   # multi_scale_output is only used last module             if not multi_scale_output and i == num_modules - 1:

·                       reset_multi_scale_output = False

·                   else:

·                       reset_multi_scale_output = True

·      

·                   modules.append(

·                       HighResolutionModule(

·                           num_branches,

·                           block,

·                           num_blocks,

·                           num_inchannels,

·                           num_channels,

·                           fuse_method,

·                           reset_multi_scale_output

·                       )

·                   )

·                   num_inchannels = modules[-1].get_num_inchannels()

·      

·               return nn.Sequential(*modules), num_inchannels

·      

·           def forward(self, x):

·               # ---------------------------(1) begin---------------------------- #         x = self.conv1(x)

·               x = self.bn1(x)

·               x = self.relu(x)

·               x = self.conv2(x)

·               x = self.bn2(x)

·               x = self.relu(x)

·               x = self.layer1(x)

·               # ---------------------------(1) end---------------------------- # 

·               # ---------------------------(2) begin---------------------------- #         x_list = []

·               for i in range(self.stage2_cfg['NUM_BRANCHES']):

·                   if self.transition1[i] is not None:

·                       x_list.append(self.transition1[i](x))

·                   else:

·                       x_list.append(x)

·               y_list = self.stage2(x_list)

·               # ---------------------------(2) end---------------------------- # 

·               # ---------------------------(3) begin---------------------------- #         x_list = []

·               for i in range(self.stage3_cfg['NUM_BRANCHES']):

·                   if self.transition2[i] is not None:

·                       x_list.append(self.transition2[i](y_list[-1]))

·                   else:

·                       x_list.append(y_list[i])

·               y_list = self.stage3(x_list)

·               # ---------------------------(3) end---------------------------- # 

·               # ---------------------------(4) begin---------------------------- #         x_list = []

·               for i in range(self.stage4_cfg['NUM_BRANCHES']):

·                   if self.transition3[i] is not None:

·                       x_list.append(self.transition3[i](y_list[-1]))

·                   else:

·                       x_list.append(y_list[i])

·               y_list = self.stage4(x_list)

·               # ---------------------------(4) end---------------------------- # 

·               # ---------------------------(5) begin---------------------------- #         x = self.final_layer(y_list[0])

·               # ---------------------------(5) end---------------------------- # 

·               return x

·      

·           def init_weights(self, pretrained=''):

·               logger.info('=> init weights from normal distribution')

·               for m in self.modules():

·                   if isinstance(m, nn.Conv2d):

·                       # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')                 nn.init.normal_(m.weight, std=0.001)

·                       for name, _ in m.named_parameters():

·                           if name in ['bias']:

·                               nn.init.constant_(m.bias, 0)

·                   elif isinstance(m, nn.BatchNorm2d):

·                       nn.init.constant_(m.weight, 1)

·                       nn.init.constant_(m.bias, 0)

·                   elif isinstance(m, nn.ConvTranspose2d):

·                       nn.init.normal_(m.weight, std=0.001)

·                       for name, _ in m.named_parameters():

·                           if name in ['bias']:

·                               nn.init.constant_(m.bias, 0)

·      

·               if os.path.isfile(pretrained):

·                   pretrained_state_dict = torch.load(pretrained)

·                   logger.info('=> loading pretrained model {}'.format(pretrained))

·      

·                   need_init_state_dict = {}

·                   for name, m in pretrained_state_dict.items():

·                       if name.split('.')[0] in self.pretrained_layers \

·                          or self.pretrained_layers[0] is '*':

·                           need_init_state_dict[name] = m

·                   self.load_state_dict(need_init_state_dict, strict=False)

·               elif pretrained:

·                   logger.error('=> please download pre-trained models first!')

·                   raise ValueError('{} is not exist!'.format(pretrained))

·      

·      

·       def get_pose_net(cfg, is_train, **kwargs):

·           model = PoseHighResolutionNet(cfg, **kwargs)

·      

·           if is_train and cfg.MODEL.INIT_WEIGHTS:

·               model.init_weights(cfg.MODEL.PRETRAINED)

·      

·           return model

 

 

今天内容有些枯燥,放了很多代码在这里,也是便于自己日后理解。最近还没法回实验室,所以在智星云租了GPU用来做实验。这家的价格还是很合理的,用起来也很方便,不用花精力在环境配置上,有同样需求的朋友可以参考,智星云官网: http://www.ai-galaxy.cn/,淘宝店:https://shop36573300.taobao.com/公众号: 智星AI,

今天是个值得纪念的日子,中国共产党成立99周年,作为一名中国共产党党员,在这样特别的日子里,祝我党生日快乐。

 

PEACE

 

 

参考资料:

https://arxiv.org/pdf/1902.09212.pdf

https://blog.csdn.net/yudw15/article/details/99600651

https://niecongchong.github.io/2019/05/13/HRNet%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0%E5%8F%8A%E4%BB%A3%E7%A0%81%E7%90%86%E8%A7%A3/

http://www.ai-galaxy.cn/

https://shop36573300.taobao.com/

  • 2
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值