华为开源自研AI框架昇思MindSpore应用案例:人体关键点检测模型Lite-HRNet

server/2024/11/18 6:02:30/

如果你对MindSpore感兴趣,可以关注昇思MindSpore社区

在这里插入图片描述

在这里插入图片描述

一、环境准备

1.进入ModelArts官网

云平台帮助用户快速创建和部署模型,管理全周期AI工作流,选择下面的云平台以开始使用昇思MindSpore,获取安装命令,安装MindSpore2.0.0-alpha版本,可以在昇思教程中进入ModelArts官网

在这里插入图片描述

选择下方CodeLab立即体验

在这里插入图片描述

等待环境搭建完成

在这里插入图片描述

2.使用CodeLab体验Notebook实例

下载NoteBook样例代码Mask-RCNN实现实例分割.ipynb为样例代码

在这里插入图片描述

选择ModelArts Upload Files上传.ipynb文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

选择Kernel环境

在这里插入图片描述

切换至GPU环境,切换成第一个限时免费

在这里插入图片描述

进入昇思MindSpore官网,点击上方的安装

在这里插入图片描述

获取安装命令

在这里插入图片描述

回到Notebook中,在第一块代码前加入命令
在这里插入图片描述

conda update -n base -c defaults conda

在这里插入图片描述

安装MindSpore 2.0 GPU版本

conda install mindspore=2.0.0a0 -c mindspore -c conda-forge

在这里插入图片描述

安装mindvision

pip install mindvision

在这里插入图片描述

安装下载download

pip install download

人体关键点检测模型Lite-HRNet

人体关键点检测是计算机视觉的基本任务之一,在许多应用场景诸如自动驾驶、安防等有着重要的地位。可以发现,在这些应用场景下,深度学习模型可能需要部署在IoT设备上,这些设备算力较低,存储空间有限,无法支撑太大的模型,因此轻量但不失高性能的人体关键点检测级模型将极大降低模型部署难度。Lite-HRNet便提供了一轻量级神经网络骨干,通过接上不同的后续模型可以完成不同的任务,其中便包括人体关键点检测,在配置合理的情况下,Lite-HRNet可以以大型神经网络数十分之一的参数量及计算量达到相近的性能。

模型简介

Lite-HRNet由HRNet(High-Resolution Network)改进而来,HRNet的主要思路是在前向传播过程中通过维持不同分辨率的特征,使得最后生成的高阶特征既可以保留低分辨率高阶特征中的图像语义信息,也可以保留高分辨率高阶特征中的物体位置信息,进而提高在分辨率敏感的任务如语义分割、姿态检测中的表现。Lite-HRNet是HRNet的轻量化改进,改进了HRNet中的卷积模块,将HRNet中的参数量从28.5M降低至1.1M,计算量从7.1GFLOPS降低至0.2GFLOPS,但AP75仅下降了7%。
综上,Lite-HRNet具有计算量、参数量低,精度可观的优点,有利于部署在物联网低算力设备上服务于各个应用场景。

数据准备

本案例使用COCO2017数据集作为训练、验证数据集,请首先安装Mindspore Vision套件,并确保安装的Mindspore是GPU版本,随后请在https://cocodataset.org/ 上下载好2017 Train Images、2017 Val Images以及对应的标记2017 Train/Val Annotations,并解压至当前文件夹,文件夹结构下表所示

Lite-HRNet/├── imgs├── src├── annotations├──person_keypoints_train2017.json└──person_keypoints_train2017.json├── train2017└── val2017

训练、测试原始图片如下所示,图片中可能包含多个人体,且包含的人体不一定包含COCO2017中定义的17个关键点,标注中有每个人体的边框、关键点信息,以便处理图像后供模型训练。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据预处理

src/mindspore_coco.py中定义了供mindspore模型训练、测试的COCO数据集接口,在加载训练数据集时只需指定所用数据集文件夹位置、输入图像的尺寸、目标热力图的尺寸、以及手动设置对训练图像采用的变换即可
import mindspore as ms
import mindspore.dataset as dataset
import mindspore.dataset.vision.py_transforms as py_vision
import mindspore.nn as nn
from mindspore.dataset.transforms.py_transforms import Compose

from src.configs.dataset_config import COCOConfig
from src.dataset.mindspore_coco import COCODataset

cfg = COCOConfig(root=“./”, output_dir=“outputs/”, image_size=[192, 256], heatmap_size=[48, 64])
trans = Compose([py_vision.ToTensor(),
py_vision.Normalize(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])
train_ds = COCODataset(cfg, “…/”, “train2017”, True, transform=trans)
train_loader = dataset.GeneratorDataset(train_ds, [“data”, “target”, “weight”])

构建网络

Lite-HRNet网络骨干大体结构如下图所示:\

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

网络中存在不同的分辨率分支,网络主干上维持着较高分辨率、较少通道数的输出特征,网络分支上延展出较低分辨率、较多通道数的输出特征,且这些不同分辨率的特征之间通过上采样、下采样的卷积层进行交互、融合。Stage内的Cross Channel Weighting(CCW)则是网络实现轻量化的精髓,它将原HRNet中复杂度较高的1*1卷积以更低复杂度的Spatial Weighting等方法替代,从而实现降低网络参数、计算量的效果。CCW的结构如下图所示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先Channel Split将输入特征通道分为两份,一份不作改动,另一份经过一次Cross Resolution Weighting、一次Spatial Weighting 后与前一份未作改动的特征进行沿通道方向的拼接,最后对拼接后的特征进行通道方向的重排以得到输出结果。Cross Resolution Weighting与Spatial Weighting的流程如下:
Cross Resolutional Weighting:

( X 1 , X 2 , . . . , X s ) − > A v g P o o l i n g − > C o n v . − > R e L U . − > C o n v . − > S i g m o i d − > U p s a m p l i n g − > ( W 1 , W 2 , . . . , W s ) (X_1,X_2,...,X_s) -> AvgPooling -> Conv. -> ReLU. -> Conv. -> Sigmoid -> Upsampling -> (W_1,W_2,...,W_s) (X1,X2,...,Xs)>AvgPooling>Conv.>ReLU.>Conv.>Sigmoid>Upsampling>(W1,W2,...,Ws)

Y i = X i ⨀ W i Y_i=X_i \bigodot W_i Yi=XiWi

Spatial Weighting:

X i − > A v g P o o l i n g − > F C . − > R e L U . − > F C . − > S i g m o i d − > W i X_i -> AvgPooling -> FC. -> ReLU. -> FC. -> Sigmoid -> W_i Xi>AvgPooling>FC.>ReLU.>FC.>Sigmoid>Wi

Y i = X i ⨀ W i Y_i=X_i \bigodot W_i Yi=XiWi

上述公式中的 X i X_i Xi为第i个分辨率下的特征矩阵, W i W_i Wi为由 X i X_i Xi生成的、与 X i X_i Xi同形状的权重矩阵,由 X i X_i Xi生成 W i W_i Wi的过程分别对应图中的 H H H F F F函数,生成后的 W i W_i Wi与对应分辨率的 X i X_i Xi作哈马达积(即逐元素相乘)得到 Y i Y_i Yi对应图中的Channel Weighting部分,其中Cross Resolutional Weighting的各个 W i W_i Wi ( X 1 , X 2 , . . . , X s ) (X_1,X_2,...,X_s) (X1,X2,...,Xs)综合生成,所以会涉及上采样等操作。
而每个Stage后端存在Fusion Blocks以进行不同分辨率特征间交互融合,并产生更低分辨率的分支。下表列出了网络的具体结构参数。网络实际结构较复杂,具体细节请参考src/backbone.py中代码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

值得注意的是,除了骨干网络,作者在论文中同时也给出了所使用的检测头即SimpleBaseline,为了简洁起见,在本次的Lite-HRNet的Mindspore实现中,检测头(代码中包括IterativeHeads和LiteTopDownSimpleHeatMap)已集成至骨干网络之后,作为整体模型的一部分,直接调用模型即可得到热力图预测输出。

损失函数

此处使用损失函数为JointMSELoss,即关节点的均方差误差损失函数,其源码如下所示,总体流程即计算每个关节点预测热力图与实际热力图的均方差,其中target是根据关节点的人工标注坐标,通过二维高斯分布生成的热力图,target_weight用于指定参与计算的关节点,若某关节点对应target_weight取值为0,则表明该关节点在输入图像中未出现,不参与计算。
“”“JointMSELoss”“”
import mindspore.nn as nn
import mindspore.ops as ops

class JointsMSELoss(nn.Cell):
“”“Joint MSELoss”“”
def init(self, use_target_weight):
“”“JointMSELoss”“”
super(JointsMSELoss, self).init()
self.criterion = nn.MSELoss(reduction=‘mean’)
self.use_target_weight = use_target_weight

def construct(self, output, target, weight):"""construct"""target = targettarget_weight = weightbatch_size = output.shape[0]num_joints = output.shape[1]spliter = ops.Split(axis=1, output_num=num_joints)mul = ops.Mul()heatmaps_pred = spliter(output.reshape((batch_size, num_joints, -1)))heatmaps_gt = spliter(target.reshape((batch_size, num_joints, -1)))loss = 0for idx in range(num_joints):heatmap_pred = heatmaps_pred[idx].squeeze()heatmap_gt = heatmaps_gt[idx].squeeze()if self.use_target_weight:heatmap_pred = mul(heatmap_pred, target_weight[:, idx])heatmap_gt = mul(heatmap_gt, target_weight[:, idx])loss += 0.5 * self.criterion(heatmap_pred,heatmap_gt)else:loss += 0.5 * self.criterion(heatmap_pred, heatmap_gt)return loss/num_joints

模型实现与训练

在实现模型时,需指定模型内部结构,在src/net_configs中已指定原论文中10种结构配置,在训练样例种取Lite_18_coco作为模型结构,此处作为案例,仅设置epoch数量为1,在实际训练中可以设置为200,并且可以加入warmup。由于mindspore的训练接口默认数据集中每条数据只有两列(即训练数据和标签),所以这里需自定义Loss Cell。值得注意的是loss在训练前后变化并不会十分大,训练好的模型的loss为0.0004左右
class CustomWithLossCell(nn.Cell):

def __init__(self,net: nn.Cell,loss_fn: nn.Cell):super(CustomWithLossCell, self).__init__()self.net = netself._loss_fn = loss_fndef construct(self, img, target, weight):""" build network """heatmap_pred = self.net(img)return self._loss_fn(heatmap_pred,target,weight)

from src.configs.net_configs import get_netconfig
from mindspore.train.callback import LossMonitor
from src.backbone import LiteHRNet

ext = get_netconfig(“extra_lite_18_coco”)
net = LiteHRNet(ext)
criterion = JointsMSELoss(use_target_weight=True)

train_loader = train_loader.batch(64)
optim = nn.Adam(net.trainable_params(), learning_rate=2e-3)
loss = JointsMSELoss(use_target_weight=True)
net_with_loss = CustomWithLossCell(net, loss)

model = ms.Model(network=net_with_loss, optimizer=optim)
epochs = 1
#Start Training
model.train(epochs, train_loader, callbacks=[LossMonitor(100)], dataset_sink_mode=False)

模型评估

模型评估过程中使用AP、AP50、AP75以及AR50、AR75作为评价指标,val2017作为评价数据集,pycocotool包中已实现根据评价函数,且src/mindspore_coco.py中的evaluate函数也实现了调用该评价函数的接口,只需提供预测关键点坐标等信息即可获得评价指标。此处载入Lite_18_coco的预训练模型进行评价。
from mindspore import load_checkpoint
from mindspore import load_param_into_net

from src.utils.utils import get_final_preds
import numpy as np

def evaluate_model(model, dataset, output_path):
“”“Evaluate”“”
num_samples = len(dataset)
all_preds = np.zeros(
(num_samples, 17, 3),
dtype=np.float32
)

all_boxes = np.zeros((num_samples, 6))
image_path = []for i, data in enumerate(dataset):input_data, target, meta = data[0], data[1], data[3]input_data = ms.Tensor(input_data[0], ms.float32).reshape(1, 3, 256, 192)shit = model(input_data).asnumpy()target = target.reshape(shit.shape)c = meta['center'].reshape(1, 2)s = meta['scale'].reshape(1, 2)score = meta['score']preds, maxvals = get_final_preds(shit, c, s)all_preds[i:i + 1, :, 0:2] = preds[:, :, 0:2]all_preds[i:i + 1, :, 2:3] = maxvals# double check this all_boxes partsall_boxes[i:i + 1, 0:2] = c[:, 0:2]all_boxes[i:i + 1, 2:4] = s[:, 0:2]all_boxes[i:i + 1, 4] = np.prod(s*200, 1)all_boxes[i:i + 1, 5] = scoreimage_path.append(meta['image'])dataset.evaluate(0, all_preds, output_path, all_boxes, image_path)

net_dict = load_checkpoint(“./ckpt/litehrnet_18_coco_256x192.ckpt”)
load_param_into_net(net, net_dict)

eval_ds = COCODataset(cfg, “./”, “val2017”, False, transform=trans)
evaluate_model(net, eval_ds, “./result”)

模型推理

  1. Lite-HRNet是关键点检测模型,所以输入待推理图像应为包含单个人体的图像,作者在论文中提及在coco test 2017测试前已使用SimpleBaseline生成的目标检测Bounding Box处理图像,所以待推理图像应仅包含单个人体。
  2. 网络的输入为(1,3,256,192),所以在输入图像前应先将其变换成网络可处理的形式。
    import cv2
    from src.utils.utils import get_max_preds
    origin_img = cv2.imread(“./imgs/man.jpg”)
    origin_h, origin_w, _ = origin_img.shape
    scale_factor = [origin_w/192, origin_h/256]

resize to (112 112 3) and convert to tensor

img = cv2.resize(origin_img, (192, 256))
print(img.shape)
img = trans(img)

img = np.expand_dims(img, axis=0)

img = ms.Tensor(img)
print(img.shape)

Infer

heatmap_pred = net(img).asnumpy()
pred, _ = get_max_preds(heatmap_pred)

Postprocess

pred = pred.reshape(pred.shape[0], -1, 2)
print(pred[0])
pre_landmark = pred[0] * 4 * scale_factor

Draw points

for (x, y) in pre_landmark.astype(np.int32):
cv2.circle(origin_img, (x, y), 3, (255, 255, 255), -1)

Save image

cv2.imwrite(“./imgs/man_infer.jpg”, origin_img)
可以看到模型基本正确标注出了关键点的位置
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

算法基本流程

  1. 获取原始数据
  2. 从数据集的标注json文件中得到各个图像bbox以及关键点坐标信息
  3. 根据bbox裁剪图像,并放缩至指定尺寸,如果是训练还可以作适当数据增强,生成指定尺寸的目标热力图
  4. 指定尺寸的输入经过网络前向传播后得到预测的关键点热力图
  5. 经过处理后取热力图中的最大值坐标作为关键点的预测坐标

http://www.ppmy.cn/server/142828.html

相关文章

HarmonyOs DevEco Studio小技巧31--卡片的生命周期与卡片的开发

Form Kit简介 Form Kit(卡片开发服务)提供一种界面展示形式,可以将应用的重要信息或操作前置到服务卡片(以下简称“卡片”),以达到服务直达、减少跳转层级的体验效果。卡片常用于嵌入到其他应用&#xff0…

每日小练:Day4

1.数据统计 题目链接:D-[NOIP2010]数字统计_NOIP2010普及组复赛 统计2出现的次数,把这个数的每一位都取模出来,判断它是否是2,如果是2,则count import java.util.*; public class Main{public static void main(St…

MuMu模拟器安卓12安装Xposed 框架

MuMu模拟器安卓12安装Xposed 框架 当开启代理后,客户端会对代理服务器证书与自身内置证书展开检测,只要检测出两者存在不一致的情况,客户端就会拒绝连接。正是这个原因,才致使我们既没有网络,又抓不到数据包。 解决方式: 通过xposed框架和trustmealready禁掉app里面校验…

UE5 设置Sequence播完后返回起始位置

UE5 的sequence中,播放完毕,动画会停到最后一帧, 需要播放完毕后,设置sequence为起始位置 蓝图中控制方法: 链接:UE5 设置Sequence播完后返回起始位置 posted by anonymous | blueprintUE | PasteBin F…

PsiNanopore

PsiNanopore 您可以使用此包通过比较直接文件与IVT文件来计算基因组上位置的p值。p值越低,该位置为假尿苷酸化的可能性越高。我们工具的主要输入文件是对齐的读取(bam文件,请阅读“DNA/RNA测序分析的计算管道”部分中的逐步指南,了解如何从bam文件生成bam文件)。 系统要…

k8s搭建1.23版本

文章目录 1、前期准备1、关闭防火墙和selinux2、关闭交换分区3、修改主机名和免密登录4、内核参数5、安装docker6、安装k8s源 2、安装1、安装k8s软件包2、初始化k8s3、安装calico网络插件4、检查 1、前期准备 以下操作所有主机都要运行的 1、关闭防火墙和selinux systemctl …

set的特点

package test_27case class Book(var bookName:String, var author: String, var price: Double){}object caseclass{def main(args: Array[String]): Unit {val set1 scala.collection.mutable.Set[Book]()val book1 new Book("西游记","吴承恩",100)va…

分享一个mysql-sql优化经验 in (xxx)的优化【 in(集合)改成not in(反集合) 】

一、优化前 如下sql,直接执行时间需要18.341秒 二、优化后 将 in(集合) 改成 not in(反集合),如下图,执行性能提升至少4倍,需要4.643秒,并且查询结果不变 三、原因分析 为什么速度会变快那么多? in (集…