前言
本次分享将带领大家从 0 到 1 完成一个人体姿态估计任务,覆盖数据准备、模型训练、推理部署和应用开发的全流程,项目将采用以PaddlePaddle为核心的飞桨深度学习框架进行开发,并总结开发过程中踩过的一些坑,希望能为有类似项目需求的同学提供一点帮助。
项目背景和目标
背景:
人体姿态估计,通常也称为人体关键点检测,方法通常可以分成两类:
- 一种是用坐标回归的方式来解决,直接输出各个关键点的位置坐标
- 另一种是将关键点建模成热力图,通过像素分类任务,回归热力图分布得到关键点位置。
与人脸关键点检测不同,人体的躯干部位更为灵活,变化更为难以预测,基于坐标回归的方法难以胜任,通常使用热力图回归的关键点检测方法。
为此,本次实验将将采用“热力图回归”的方式进行模型搭建: 将关键点建模成热力图,通过像素分类任务,回归热力图分布得到关键点位置。每一类坐标用一个概率图来表示,对图片中的每个像素位置都给一个概率,表示该点属于对应类别关键点的概率。距离关键点位置越近的像素点的概率越接近于1,距离关键点越远的像素点的概率越接近于0。
目标:
- 掌握如何用paddlepaddle深度学习框架搭建一个人体关键点检测模型;
- 掌握关键点检测卷积神经网络的架构的设计原理以及构建流程;
- 掌握如何完成模型的训练、评估、保存、预测等深度学习工作过程;
数据集介绍
本次实验使用的数据集来自 COCO,目前 COCO keypoint track是人体关键点检测的权威公开比赛之一,COCO数据集中把人体关键点表示为17个关节,分别是鼻子,左右眼,左右耳,左右肩,左右肘,左右腕,左右臀,左右膝,左右脚踝。人体关键点检测的任务就是从输入的图片中检测到人体及对应的关键点位置。
百度AI Studio平台
本次实验将采用AI Studio实训平台中的免费GPU资源,在平台注册账号后,点击创建项目-选择NoteBook任务,然后添加数据集,如下图所示,完成项目创建。启动环境可以自行选择CPU资源 or GPU资源,创建任务每天有8点免费算力,推荐大家使用GPU资源进行模型训练,这样会大幅减少模型训练时长。
创建项目的方式有两种:
- 一是在AI Studio实训平台参考如下方式,新建项目。
- 二是直接 fork 一个平台上的已有项目,比如本次实验,可以选择【飞桨AI实战】实验5-人体关键点检测的最新版本,然后点击 fork,成功后会在自己账户下新建一个项目副本,其中已经挂载了源项目自带的数据集和本次项目用到的核心代码。
为了快速跑通项目流程,建议直接 fork 源项目。
从零开始实战
1 基础:动手跑通人体关键点检测任务全流程
核心代码在:
core/
文件夹下
1.1 数据准备
本案例中使用了两个数据集,分别是:
- COCO2017完整数据集,对应项目中的 data/data7122,用于训练得到更好的模型
- COCO2017抽取的子集,对应项目中的 data/data9663,用于快速验证,跑通流程
step 1:解压缩数据
# 打开终端
# 解压子集 -d 指定解压缩的路径,会在data0文件夹下生成
unzip data/data9663/coco.zip -d data0/
## 解压完成后,目录结构如下:
data0/
`-- coco
|-- annotations
`-- images
# 如果想解压完整数据集 -- 会很慢
mkdir -p data1/coco
cd data1/coco
unzip ../../data/data7122/train2017.zip -d images/
unzip ../../data/data7122/annotations_trainval2017.zip -d ./
step 2: 准备数据部分代码
# 为了读取 coco 数据, 需要安装COCO API,用于加载、解析和可视化COCO数据集
pip install pycocotools
# 自定义Dataset,核心代码见:
reader.py
step 3: 数据可视化
# 打开一个 notebook 比如在main.ipynb中,输入:
from core.reader import COCOPose
debug_data = COCOPose('data0/coco', mode='train', shuffle=True, debug=True)
img, heatmaps, heatmaps_weight = debug_data[0]
COCOPose 中定义了可视化函数,指定 debug=True,就会打印出数据的可视化结果,如下图所示:
- 左:原始图像
- 中:crop 出的人物图像 及其身上的关键点
- 右:关键点对应的 HeatMap,也即模型要预测的目标
1.2 模型构建
本次实验我们将采用最简单的网络架构,定义为 PoseNet ,backbone模型采用去掉最后池化层和全连接层的ResNet模型,然后通过反卷积和上采样,生成热力图。训练和推理阶段的流程是:输入一张图片,模型生成热力图,通过像素分类任务,回归热力图分布得到关键点位置。
step 1: 搭建 PoseNet
# 定义模型类
net.py
step 2: 定义损失函数
# 定义 HeatMap loss, 位于 net.py
class HMLoss(paddle.nn.Layer):
def __init__(self, kps_num):
super(HMLoss, self).__init__()
self.k = kps_num
def forward(self, heatmap, target, target_weight):
_, c, h, w = heatmap.shape
x = heatmap.reshape((-1, self.k, h*w))
y = t