目录

  • 前言
  • 文献
      • 文献名字:Simple Baselines for Human Pose Estimation and Tracking
      • 作者:Bin Xiao, Haiping Wu, and Yichen Wei
    • 创新点
  • 模型
    • 模型图
      • BasicBlock
      • Bottleneck
      • stem层
      • Layers层
      • deconv层
      • final_layer层
    • 模型代码
    • 输出结果
  • 总结

前言

本周主要看了人体姿态估计的一个简单模型,了解到模型构建过程,以及如何根据论文代码自己画出模型图,从而进行复现。

文献

文献名字:Simple Baselines for Human Pose Estimation and Tracking

作者:Bin Xiao, Haiping Wu, and Yichen Wei

创新点

作者在文中提出的姿态检测方法是一种简单的baseline,相比于Hourglass与CPN,论文中构建的模型是在ResNet中插入了几层反卷积,将低分辨率的特征图扩张为原图大小,以此生成预测关键点需要的Heatmap。没有任何的特征融合,网络结构非常简单,相较于Hourglass和CPN,唯一较为新颖的点是引入了Deconvolution来替换Upsampling与convolution组成的结构主要方法只是在ResNet的最后一个卷积阶段添加一些反褶积层。我们采用这种结构是因为它可以说是从deep和low分辨率特征生成热图的最简单方法

默认情况下,使用三个具有批处理规范化和ReLU激活的反褶积层。每层有256个4×4内核的filter。步幅是2。最后加入1×1的卷积层,生成 个关键点的预测热图 。比较图1中的三种结构,很明显,我们的方法在生成高分辨率特征图方面与另外两种有所不同。两个工作都使用上采样来提高特征映射的分辨率,并将卷积参数放入其他块中。相反,我们的方法将上采样和卷积参数以更简单的方式组合到反褶积层中,而不使用跳层连接。

模型

模型图

BasicBlock

Bottleneck

stem层

stem层将输入进来的图片进行初始特征提取,输入3x256x192的图片,经过conv1后变成64x128x96的feature map,再经过Bn1,Relu,maxpool后变成64x64x48的feature map

Layers层

将stem层处理好的特征图进行输入,Layers层进行深度图像特征提取。Layers里分四层,所用的模块的BasicBlock和Bottleneck,这里以BasicBlock作为例子。BasicBlock中conv1是k=3,s=s,p=1的卷积(其中步长是根据传入参数来决定的),经过bn1,relu后conv2是k=3,s=1,p=1的卷积。第一层时,没有传入stride,经过三次k=3,s=1,p=1的卷积核后,输出为64x64x48。layer2时传入步长为2,在layer2层,输出通道变为128,经过三次BasicBlock后输出特征图为128x32x24。layer3传入步长为2,输出通道为256,最后输出为256x16x14。layer4传入步长为2,输出通道为512,最后输出为512x8x6。

deconv层

插入了几层反卷积,将低分辨率的特征图扩张为原图大小,以此生成预测关键点需要的Heatmap
deconv中包含三层反卷积层每一层都有一个conv,bn和relu,conv1 in_plane = 512,out_plane=256,k=4,s=2,p=1.最后输出为256x16x14。经过三层后,最终输出为256x64x48

final_layer层

final_layer根据使用的数据集将经过反卷积后的特征图变成我们需要的大小,coco数据集17个关键点,所以要把最后输出的特征图通道变为17.其中final_layer卷积为in_plane = 256,out_plane = 17,k=3,s=2,p = 1.追踪输出的特征图为17x64x48

模型代码

自己写的简洁的模型代码,理解了整个模型构建的过程

import torch
from torch import nn
#定义3x3卷积核
def Conv3x3(inplane,outplane,stride = 1):return nn.Conv2d(inplane,outplane,kernel_size=3,stride=stride,padding=1,bias=False)class BasicBlock(nn.Module):expansion = 1def __init__(self,inplane,outplane,stride=1,downsanple = None):#conv1,步长可以传进来,conv2步长不传,就是1super(BasicBlock, self).__init__()self.conv1 = Conv3x3(inplane,outplane,stride)self.bn1 = nn.BatchNorm2d(outplane)self.relu = nn.ReLU()self.conv2 = Conv3x3(outplane,outplane)  #!!!!!!!self.bn2 = nn.BatchNorm2d(outplane)self.downsample = downsanpleself.stride =stridedef forward(self,x):residual = xout = 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 += residualout = self.relu(out)return outclass Bottleneck(nn.Module):expansion = 4def __init__(self,inplane,outplane,stride = 1,downsample = None):super(Bottleneck, self).__init__()self.conv1 = nn.Conv2d(inplane,outplane,kernel_size=1,stride=stride,bias=False)self.bn1 = nn.BatchNorm2d(outplane)self.conv2 = nn.Conv2d(outplane,outplane,kernel_size=3,stride=1,padding=1,bias=False)self.bn2 = nn.BatchNorm2d(outplane)self.conv3 = nn.Conv2d(outplane,outplane*self.expansion,kernel_size=1,bias=False)self.bn3 = nn.BatchNorm2d(outplane*self.expansion)self.relu = nn.ReLU()self.downsample = downsampledef forward(self,x):residual = xout = self.conv1(x)out = self.bn1(out)out = self.conv2(out)out = self.bn2(out)out = self.conv3(out)out = self.bn3(out)if self.downsample is not None:residual = self.downsample(x)out += residualout = self.relu(out)return  outclass SampplePose(nn.Module):def __init__(self,block,layers,**kwargs):super(SampplePose, self).__init__()# extra = cfg.MODEL.EXTRAself.inplanes =64self.conv1 = nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,stride=2,padding=3,bias=False)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU()self.maxpool = nn.MaxPool2d(kernel_size=3,stride=2,padding=1)#层self.layer1 = self._make_layer(block,64,layers[0])self.layer2 = self._make_layer(block,128,layers[1],stride=2)self.layer3 = self._make_layer(block,256,layers[2],stride=2)self.layer4 = self._make_layer(block,512,layers[3],stride=2)self.deconv = self._deconv_make_layer_(3,256,4)self.final_layer = self._final_layer_()def forward(self,x):residual = xout = self.conv1(x)print(f'conv1后的特征图大小:{out.shape}')out = self.bn1(out)out = self.relu(out)out = self.maxpool(out)print(f'maxpool后的特征图大小:{out.shape}')out = self.layer1(out)print(f'第一层卷积后:{out.shape}')out = self.layer2(out)print(f'第二层卷积后:{out.shape}')out = self.layer3(out)print(f'第三层卷积后:{out.shape}')out = self.layer4(out)print(f'第四层卷积后:{out.shape}')out = self.deconv(out)print(f'反卷积后:{out.shape}')out = self.final_layer(out)return outdef _make_layer(self,block,outplane,blocks,stride = 1):downsample = Noneif stride != 1 or self.inplanes != outplane * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.inplanes, outplane * block.expansion,kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(outplane * block.expansion),)# print(f'shurru{self.inplanes}')# print(outplane)layers = []layers.append(block(self.inplanes,outplane,stride,downsample))self.inplanes = outplane*block.expansionfor i in range(1,blocks):layers.append(block(self.inplanes,outplane))return nn.Sequential(*layers)#反卷积层def _deconv_make_layer_(self,num_layers,num_filters,num_kernels):layers = []for i in range(num_layers):outplane = num_filterslayers.append(nn.ConvTranspose2d(in_channels=self.inplanes,out_channels=outplane,kernel_size=4,stride=2,padding=1))layers.append(nn.BatchNorm2d(outplane))layers.append(nn.ReLU())self.inplanes = outplanereturn nn.Sequential(*layers)def _final_layer_(self):return nn.Conv2d(in_channels=256,out_channels=17,kernel_size=1,stride=1,padding=0)if __name__ == '__main__':x = torch.randn(1,3,256,192)SampplePose18 = SampplePose(BasicBlock,[2,2,2,2])out18 = SampplePose18(x)print(f'ResNet18最终结果:{out18.shape}')SampplePose34 = SampplePose(BasicBlock,[3,4,6,3])out34 = SampplePose34(x)print(f'ResNet34最终结果:{out34.shape}')SampplePose50 = SampplePose(Bottleneck, [3, 4, 6, 3])out50 = SampplePose50(x)print(f'ResNet50最终结果:{out50.shape}')SampplePose101 = SampplePose(Bottleneck, [3, 4, 6, 3])out101 = SampplePose101(x)print(f'ResNet101最终结果:{out101.shape}')SampplePose152 = SampplePose(Bottleneck, [3, 4, 6, 3])out152 = SampplePose152(x)print(f'ResNet152最终结果:{out152.shape}')

输出结果

conv1后的特征图大小:torch.Size([1, 64, 128, 96])
maxpool后的特征图大小:torch.Size([1, 64, 64, 48])
第一层卷积后:torch.Size([1, 64, 64, 48])
第二层卷积后:torch.Size([1, 128, 32, 24])
第三层卷积后:torch.Size([1, 256, 16, 12])
第四层卷积后:torch.Size([1, 512, 8, 6])
反卷积后:torch.Size([1, 256, 64, 48])
ResNet18最终结果:torch.Size([1, 17, 64, 48])
conv1后的特征图大小:torch.Size([1, 64, 128, 96])
maxpool后的特征图大小:torch.Size([1, 64, 64, 48])
第一层卷积后:torch.Size([1, 64, 64, 48])
第二层卷积后:torch.Size([1, 128, 32, 24])
第三层卷积后:torch.Size([1, 256, 16, 12])
第四层卷积后:torch.Size([1, 512, 8, 6])
反卷积后:torch.Size([1, 256, 64, 48])
ResNet34最终结果:torch.Size([1, 17, 64, 48])
conv1后的特征图大小:torch.Size([1, 64, 128, 96])
maxpool后的特征图大小:torch.Size([1, 64, 64, 48])
第一层卷积后:torch.Size([1, 256, 64, 48])
第二层卷积后:torch.Size([1, 512, 32, 24])
第三层卷积后:torch.Size([1, 1024, 16, 12])
第四层卷积后:torch.Size([1, 2048, 8, 6])
反卷积后:torch.Size([1, 256, 64, 48])
ResNet50最终结果:torch.Size([1, 17, 64, 48])
conv1后的特征图大小:torch.Size([1, 64, 128, 96])
maxpool后的特征图大小:torch.Size([1, 64, 64, 48])
第一层卷积后:torch.Size([1, 256, 64, 48])
第二层卷积后:torch.Size([1, 512, 32, 24])
第三层卷积后:torch.Size([1, 1024, 16, 12])
第四层卷积后:torch.Size([1, 2048, 8, 6])
反卷积后:torch.Size([1, 256, 64, 48])
ResNet101最终结果:torch.Size([1, 17, 64, 48])
conv1后的特征图大小:torch.Size([1, 64, 128, 96])
maxpool后的特征图大小:torch.Size([1, 64, 64, 48])
第一层卷积后:torch.Size([1, 256, 64, 48])
第二层卷积后:torch.Size([1, 512, 32, 24])
第三层卷积后:torch.Size([1, 1024, 16, 12])
第四层卷积后:torch.Size([1, 2048, 8, 6])
反卷积后:torch.Size([1, 256, 64, 48])
ResNet152最终结果:torch.Size([1, 17, 64, 48])Process finished with exit code 0

总结

第一次看论文里模型的具体实现,才开始看的时候没有太多头绪。师兄给我讲解了很多,说可以结合论文和代码来自己画出模型图结构,这样自己实现代码的时候就可以看着自己的模型图来实现。跟着这种方法学习,感觉进展很快。知道了代码从哪开始看起,卷积,反卷积的作用以及最后模型输出的是什么。自己在写代码的过程中也更进一步的了解到了每个参数的传入输出到底是怎样的。在写BasicBlock模块的时候,我第二次卷积时参数还写的时in_plane,out_palne.导致最后运行成功,通道数有问题。找了很久的错误才发现在这,最主要的原因就是对于参数的传递当时还没有理解很透彻。希望自己后面可以在此基础上可以将训练过程也进行实现。

10.23周报Simple Baselines for Human Pose Estimation and Tracking研读相关推荐

  1. 【Simple Baselines】《Simple Baselines for Human Pose Estimation and Tracking》

    ECCV-2018 文章目录 1 Background and Motivation 2 Advantages / Contributions 3 Method 3.1 Pose Estimation ...

  2. 论文分享 Simple Baselines for Human Pose Estimation and Tracking

    Bin Xiao1∗, Haiping Wu2∗†, and Yichen Wei1 1Microsoft Research Asia ECCV2018 https://github.com/micr ...

  3. Simple Baselines for Human Pose Estimation 阅读笔记

    SimpleBaseline姿态估计阅读笔记 ECCV2018 论文链接 代码链接 摘要: 近年来,姿态估计在取得重大进展的同时,总体算法和系统复杂性也日益增加,加剧了算法分析和比较的难度,本项工作提 ...

  4. 人体姿势估计论文:Simple and Lightweight Human Pose Estimation及其PyTorch实现

    Simple and Lightweight Human Pose Estimation PDF: https://arxiv.org/pdf/1911.10346v1.pdf PyTorch代码: ...

  5. 【论文阅读笔记】Simple and Lightweight Human Pose Estimation

    论文地址:https://arxiv.org/abs/1911.10346 代码地址:https://github.com/zhang943/lpn-pytorch 论文总结   本文网络名叫LPN. ...

  6. 姿态估计入门-2020综述《The Progress of Human Pose Estimation: A Survey and Taxonomy of Models Applied in 2D》

    <The Progress of Human Pose Estimation: A Survey and Taxonomy of Models Applied in 2D Human Pose ...

  7. 【HRNet】《Deep High-Resolution Representation Learning for Human Pose Estimation》

    CVPR-2019 代码:https://github.com/leoxiaobin/deep-high-resolution-net.pytorch 文章目录 1 Background and Mo ...

  8. 人体姿态估计(Human Pose Estimation)技巧方法汇总

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 作者:Poeroz https://zhuanlan.zhihu.com/p/10 ...

  9. 重新思考人体姿态估计 Rethinking Human Pose Estimation

    Newly updated by 2019-11-19 ----------------------------------------------------- 浅谈:2D人体姿态估计基本任务.研究 ...

最新文章

  1. java.io.IOException: No FileSystem for scheme: hdfs
  2. Skyline 扩展模块简介
  3. 三步解决C语言中struct字节对齐问题,Python进阶篇-struct字节对齐问题
  4. 关于li标签之间的间隔如何消除!
  5. UE4材质:只在石头缝中刷草
  6. hexo部署云服务器的全过程
  7. parameter与define 区别
  8. sublime text html乱码,Sublime Text 2中文显示乱码的解决方法
  9. 面向对象三个特征总结
  10. 河南科技学院去年对口计算机分数线,河南科技学院录取分数线2021是多少分(附历年录取分数线)...
  11. 004-Python内置数据结构-七种数据结构一览
  12. 在‘句子迷’爬取网友总结的方文山歌词并作词频统计
  13. 使用python爬取百度今日热点事件排行榜
  14. 电视SMB方式连接电脑共享文件
  15. 关注家庭教育-父母对子女的期望
  16. 高空核爆与雷电电磁脉冲特征及能量吸收技术(摘要)
  17. 机器学习中的数学原理——过拟合、正则化与惩罚函数
  18. 拥有ISO26262认证的软件工具清单
  19. 北京买房的10点建议
  20. 基于kettle的数据集成平台(三)

热门文章

  1. android5.1默认输入法,讯飞输入法Android5.1.1930 说得更轻松
  2. catia里画铰链_汽车门铰链三维造型
  3. 在Hexo+APlayer博客中添加TTS语音朗读
  4. Java I/O 相关面试题
  5. 什么是 Android 组件化
  6. 2018数字转型,2019深耕细作,转型大数据全套开发教程都在这儿!
  7. 【网络安全】考试试卷十二
  8. 农村土地确权之成果展示 —— 三个调查表
  9. SOLIDWORKS如何选择圆角及倒角的虚拟交点
  10. Tomochain是如何改变Defi市场现状?Tomo.Finance的挑战