学习使用paddle来构造hrnet网络模型

1、首先阅读了hrnet的网络结构分析,了解到了网络构造如下:

参考博文姿态估计之2D人体姿态估计 - (HRNet)Deep High-Resolution Representation Learning for Human Pose Estimation(多家综合)-CSDN博客

最重要的就是这个图了:

在这里主要是注释自己对这个图的认识和理解:

在RGB图片(256*192*3)输入主干网络之前先经过了两次conv卷积网络(包含3*3的卷积层和归一层,激活函数relu),然后就来到了layer1(主要是改变了通道数,通过重复堆叠Bottleneck来实现),然后进行两个层次的特征处理,一个是向下进行二倍采样,一个是直接过来,这就形成了所谓的不同维度的特征信息,然后进行融合,因为它们的通道数并不相同,所以就需要进行下采样(down),和上采样(up),具体这两个网络结构也已经放出来了。然后就是将前面得到的不同维度的特征信息融合·,输入到下一层里面。按照这个流程做下去,到最后,也就是stage4的时候,进行最后一次的多维度的特征信息融合,然后输入到最后一个卷积里面,这个卷积主要是输出17个关键点的预测信息,所以可以看到那里是C17(17个通道)也相当于17个卷积核(1*1的)。

然后图片里面的

k3, s2, p1, 和 c64 通常是卷积层的超参数,它们分别代表:

k3:这通常指的是卷积核(kernel)的大小。k3 表示卷积核的大小为 3x3,即宽度和高度都是3。

s2:这是步长(stride)的参数。s2 表示卷积操作的步长为2。步长决定了卷积核在输入特征图上滑动时,每次移动的像素数量。

p1:这是填充(padding)的参数。p1 表示在输入特征图的边界周围填充1个像素。填充通常用于控制输出特征图的大小,以及确保在特征图的边缘信息不会被丢失。

c64:这指的是输出通道数(number of output channels)。c64 表示该卷积层有64个输出通道,即卷积操作会产生64个不同的特征图。

其中输出通道数C64是和卷积核相对应的,有多少个卷积核就有多少个输出通道。

我去学习,看了一哈paddledetection里面的,发现有使用paddle实现HRNet网络,于是我就打算进行复现,训练出自己想要的模型效果,

值得一提的是这个hrnetpostprocess的代码的实现,运用了中心点+尺度因子+热力图的关系,来改变固定预测关键点是整数值。

class HRNetPostProcess(object):
    def __init__(self, use_dark=True):
        self.use_dark = use_dark

    def get_max_preds(self, heatmaps):
        '''get predictions from score maps
该类主要用于从热图(heatmaps)中获取预测的关键点坐标和对应的最大置信度
        Args:
            heatmaps: numpy.ndarray([batch_size, num_joints, height, width])
            heatmaps是一个四维数组  batch_size是批处理大小,num_joints是关键点的数量,height和width是热图的高度和宽度
        Returns:
            preds: numpy.ndarray([batch_size, num_joints, 2]), keypoints coords
            maxvals: numpy.ndarray([batch_size, num_joints, 2]), the maximum confidence of the keypoints
            输出:两个numpy数组,preds和maxvals。preds的形状为[batch_size, num_joints, 2],表示每个关键点的坐标;
            maxvals的形状也为[batch_size, num_joints, 1],表示每个关键点的最大置信度。
        '''
        assert isinstance(heatmaps,
                          np.ndarray), 'heatmaps should be numpy.ndarray'
        assert heatmaps.ndim == 4, 'batch_images should be 4-ndim'#检查heatmaps是否是4维的

        batch_size = heatmaps.shape[0]
        num_joints = heatmaps.shape[1]
        width = heatmaps.shape[3]
        heatmaps_reshaped = heatmaps.reshape((batch_size, num_joints, -1))#代码重新整形heatmaps,使其从[batch_size, num_joints, height, width]变为[batch_size, num_joints, height*width]
        idx = np.argmax(heatmaps_reshaped, 2)#使用np.argmax获取每个位置的最大值的索引,这对应于每个关键点在热图中的位置。
        maxvals = np.amax(heatmaps_reshaped, 2)#使用np.amax获取每个位置的最大值,这对应于每个关键点的置信度。

        # 将maxvals和idx重新整形为[batch_size, num_joints, 1]
        maxvals = maxvals.reshape((batch_size, num_joints, 1))
        idx = idx.reshape((batch_size, num_joints, 1))

        preds = np.tile(idx, (1, 1, 2)).astype(np.float32)#使用np.tile复制idx的每一行和每一列,生成一个新的三维数组

        preds[:, :, 0] = (preds[:, :, 0]) % width #对这个新数组的第三列(即每个关键点的x坐标)进行模运算,以确保其值在[0, width)范围内
        preds[:, :, 1] = np.floor((preds[:, :, 1]) / width)#对新数组的第二列(即每个关键点的y坐标)进行整除运算,然后取整,以获取每个关键点的y坐标。

        pred_mask = np.tile(np.greater(maxvals, 0.0), (1, 1, 2))#创建一个掩码pred_mask,其中最大置信度大于0的位置为1,否则为0。
        pred_mask = pred_mask.astype(np.float32)#使用pred_mask将preds中置信度不为0的位置设置为0。

        preds *= pred_mask#preds *= pred_mask这一行,实际上是将那些置信度不大于0的关键点坐标设置为0。这可能是为了确保只返回那些有足够置信度的预测结果。

        return preds, maxvals

    def gaussian_blur(self, heatmap, kernel):#对热力图进行高斯模糊
        border = (kernel - 1) // 2#根据核大小计算边界大小,用于扩展热图以处理边界效应
        batch_size = heatmap.shape[0]
        num_joints = heatmap.shape[1]
        height = heatmap.shape[2]
        width = heatmap.shape[3]
        for i in range(batch_size):#遍历批处理中的每个热图:对于每个热图,遍历每个关键点。
            for j in range(num_joints):
                origin_max = np.max(heatmap[i, j])
                dr = np.zeros((height + 2 * border, width + 2 * border))
                dr[border:-border, border:-border] = heatmap[i, j].copy()#将原始热图扩展,以便在应用高斯模糊时不会丢失边界信息
                dr = cv2.GaussianBlur(dr, (kernel, kernel), 0)#使用OpenCV的GaussianBlur函数对扩展的热图进行高斯模糊
                heatmap[i, j] = dr[border:-border, border:-border].copy()#还原热图:将模糊后的热图裁剪回原始大小。
                heatmap[i, j] *= origin_max / np.max(heatmap[i, j])#确保模糊后的热图的最大值与原始热图的最大值相同。
        return heatmap

    def dark_parse(self, hm, coord):#两个参数:hm(一个二维numpy数组,表示一个关键点的热图)和coord(一个包含x和y坐标的列表或元组)
        heatmap_height = hm.shape[0]
        heatmap_width = hm.shape[1]
        px = int(coord[0])
        py = int(coord[1])
        if 1 < px < heatmap_width - 2 and 1 < py < heatmap_height - 2:#确保提供的坐标位于热图的有效范围内
            dx = 0.5 * (hm[py][px + 1] - hm[py][px - 1])#计算梯度和Hessian矩阵:基于热图在给定坐标周围的像素值,计算梯度(dx, dy)和Hessian矩阵(dxx, dxy, dyy)。
            dy = 0.5 * (hm[py + 1][px] - hm[py - 1][px])
            dxx = 0.25 * (hm[py][px + 2] - 2 * hm[py][px] + hm[py][px - 2])
            dxy = 0.25 * (hm[py + 1][px + 1] - hm[py - 1][px + 1] - hm[py + 1][px - 1] \
                          + hm[py - 1][px - 1])
            dyy = 0.25 * (
                    hm[py + 2 * 1][px] - 2 * hm[py][px] + hm[py - 2 * 1][px])
            derivative = np.matrix([[dx], [dy]])
            hessian = np.matrix([[dxx, dxy], [dxy, dyy]])
            if dxx * dyy - dxy ** 2 != 0:#如果Hessian矩阵的行列式不为零(确保Hessian矩阵非奇异),则使用计算出的偏移量更新原始坐标。
                hessianinv = hessian.I
                offset = -hessianinv * derivative
                offset = np.squeeze(np.array(offset.T), axis=0)
                coord += offset
        return coord

    def dark_postprocess(self, hm, coords, kernelsize):#hm(热图),coords(关键点的初步坐标),和kernelsize(高斯模糊核的大小)
        '''DARK postpocessing, Zhang et al. Distribution-Aware Coordinate
        Representation for Human Pose Estimation (CVPR 2020).
        '''

        hm = self.gaussian_blur(hm, kernelsize)#进行高斯模糊
        hm = np.maximum(hm, 1e-10)#为了确保数值稳定性,热图中的值被限制为最小为 1e-10
        hm = np.log(hm)#对热图应用对数变换
        for n in range(coords.shape[0]):
            for p in range(coords.shape[1]):
                coords[n, p] = self.dark_parse(hm[n][p], coords[n][p])#对于每一个初步坐标,使用 dark_parse 函数来修正坐标
        return coords

    def get_final_preds(self, heatmaps, center, scale, kernelsize=3):
        """the highest heatvalue location with a quarter offset in the
        direction from the highest response to the second highest response.

        Args:
            heatmaps (numpy.ndarray): The predicted heatmaps
            center (numpy.ndarray): The boxes center
            scale (numpy.ndarray): The scale factor

        Returns:
            preds: numpy.ndarray([batch_size, num_joints, 2]), keypoints coords
            maxvals: numpy.ndarray([batch_size, num_joints, 1]), the maximum confidence of the keypoints
        """
        coords, maxvals = self.get_max_preds(heatmaps)#使用 get_max_preds 函数从热图中获取初步的关键点坐标和最大置信度

        heatmap_height = heatmaps.shape[2]#获取热图的高度和宽度
        heatmap_width = heatmaps.shape[3]#

        if self.use_dark:#如果启用了 use_dark,则使用 dark_postprocess 函数对坐标进行后处理。否则,对于每个初步坐标,如果它不在热图的边界内,则根据热图在该点的梯度进行简单的偏移
            coords = self.dark_postprocess(heatmaps, coords, kernelsize)
        else:
            for n in range(coords.shape[0]):#将修正后的坐标复制到 preds 变量中。
                for p in range(coords.shape[1]):
                    hm = heatmaps[n][p]
                    px = int(math.floor(coords[n][p][0] + 0.5))
                    py = int(math.floor(coords[n][p][1] + 0.5))
                    if 1 < px < heatmap_width - 1 and 1 < py < heatmap_height - 1:
                        diff = np.array([
                            hm[py][px + 1] - hm[py][px - 1],
                            hm[py + 1][px] - hm[py - 1][px]
                        ])
                        coords[n][p] += np.sign(diff) * .25
        preds = coords.copy()

        # Transform back    将关键点坐标从热图的空间转换回原始图像的空间
        for i in range(coords.shape[0]):
            preds[i] = transform_preds(coords[i], center[i], scale[i],
                                       [heatmap_width, heatmap_height])
        #根据每个图像的中心点(center)、尺度因子(scale)以及热图的尺寸(heatmap_width 和 heatmap_height)来调整坐标
        return preds, maxvals

    def __call__(self, output, center, scale):
        preds, maxvals = self.get_final_preds(output.numpy(), center, scale)#获得最终的预测结果
        """
        将 preds 和 maxvals 沿着最后一个维度(axis=-1)进行连接。这意味着如果 preds 的形状是 (batch_size, num_joints, 2)(每个关键点的二维坐标),
        而 maxvals 的形状是 (batch_size, num_joints, 1)(每个关键点的最大置信度),那么连接后的结果将具有形状 (batch_size, num_joints, 3),其中最后一列是每个关键点的最大置信度。
        np.mean(maxvals, axis=1) 计算 maxvals 沿着第二个维度(axis=1)的均值。这通常用于获取每个图像(或批次中的每个样本)上所有关键点置信度的平均值。
        """
        outputs = [[
            np.concatenate(
                (preds, maxvals), axis=-1), np.mean(
                maxvals, axis=1)
        ]]
        return outputs
    #连接后的 preds 和 maxvals 可以直接用于可视化,而 maxvals 的均值则可以用于评估模型的整体性能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/427203.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python的With...As 语句:优雅管理资源的技术探索【第116篇—With...As 语句】

Python的With…As 语句&#xff1a;优雅管理资源的技术探索 在Python编程中&#xff0c;with...as语句是一项强大而优雅的功能&#xff0c;用于管理资源&#xff0c;如文件、网络连接、数据库连接等。本文将深入介绍with...as语句的用法、其工作原理&#xff0c;并通过代码示例…

光子嫩肤仪面罩控制器PCB电路中升压恒流芯片FP7208的应用

护肤已经成为现代人日常生活中不可或缺的一部分&#xff0c;尤其对于追求美丽肌肤的人来说&#xff0c;寻找一款适合自己的护肤利器至关重要。 光子嫩肤仪作为一种高科技美容仪器&#xff0c;受到越来越多人的追捧。其中&#xff0c;FP7208LED升压驱动IC作为其核心部件之一&am…

TQ15EG开发板教程:创建运行petalinux2019.1

工程网盘链接&#xff1a;https://pan.baidu.com/s/1vFRpzmbifXt7GypU9aKjeg 提取码&#xff1a;0ylh 首先需要使用与petalinux相同版本的vivado创建工程&#xff0c;与之前不同的是在创建硬件设计时需要勾选上添加bit文件&#xff0c;所以要在生成bit文件之后再创建硬件设计…

谷粒商城【成神路】-【8】——商品上架

目录 1.数据模型封装 1.es数据模型 2.将es数据模型封装为JAVA bean 3.根据前端发送请求,编写controller 2.模型实现 2.1服务controller 2.2服务service 2.3服务远程调用接口 2.4检索服务controller 2.5检索服务保存到es 2.6库存查询服务 1.数据模型封装 1.es数据模…

银河麒麟之Workstation安装

一、VMware Workstation简介 VMware Workstation是一款由VMware公司开发的虚拟化软件&#xff0c;它允许用户在一台物理计算机上运行多个操作系统&#xff0c;并在每个操作系统中运行多个虚拟机。VMware Workstation提供了一个可视化的用户界面&#xff0c;使用户可以轻松创建、…

纵行科技荣登“中国物联网企业投资价值50强”、“中国物联网行业创新产品榜”

近日&#xff0c;由深圳市物联传媒有限公司、AIoT星图研究院、IOTE组委会、深圳市物联网产业协会主办的“2023‘物联之星’中国物联网行业年度榜单”评选结果正式公布。厦门纵行信息科技有限公司&#xff08;以下简称“纵行科技”&#xff09;最终从500多家参评企业中脱颖而出&…

数据库-ODBC操作

一、ODBC 数据源配置 打开ODBC数据源管理器&#xff1a; 在Windows搜索栏中键入“ODBC数据源”并选择“ODBC数据源(64位)”&#xff08;如果你的系统是64位的&#xff09;。如果你的系统是32位的&#xff0c;你可以选择“ODBC数据源(32位)”。或者&#xff0c;你可以在控制面…

使用DockerFile构建Tomcat镜像

1、准备镜像文件tomcat压缩包&#xff0c;jdk的压缩包 tomcat链接&#xff1a;https://pan.baidu.com/s/1Xpecb-BSGR2sdxSL7FDtBw?pwd1234 提取码&#xff1a;1234 jdk链接&#xff1a;https://pan.baidu.com/s/1mQHInn27j1I9uuuicBsyAA?pwd1234 提取码&#xff1a;1234 …

网工学习 DHCP配置-接口模式

网工学习 DHCP配置-接口模式 学习DHCP总是看到&#xff0c;接口模式、全局模式、中继模式。理解起来也不困难&#xff0c;但是自己动手操作起来全是问号。跟着老师视频配置啥问题没有&#xff0c;自己组建网络环境配置就是不通&#xff0c;悲催。今天总结一下我学习接口模式的…

信息系统安全与对抗-作业2

目录 1、使用自己姓名拼音创建一个账户&#xff0c; 并使用命令和图形化查看 2、使用自己拼音打头字母创建一个隐藏账户 &#xff0c;并使用命令和图形化查看 3、使用命令启动 telnet 服务 4、使用命令打开防火墙 23 端口 5、熟悉LINUX系统&#xff0c;使用命令行创建用户…

docker基线安全修复和容器逃逸修复

一、docker安全基线存在的问题和修复建议 1、将容器的根文件系统挂载为只读 修复建议&#xff1a; 添加“ --read-only”标志&#xff0c;以允许将容器的根文件系统挂载为只读。 可以将其与卷结合使用&#xff0c;以强制容器的过程仅写入要保留的位置。 可以使用命令&#x…

不同控制方式下的无人机二维码识别降落对比

无人机技术的快速发展正在推动众多行业的革新&#xff0c;从农业监测、灾害响应到城市规划和物流配送&#xff0c;无人机的应用前景无限广阔。随着应用场景的多样化&#xff0c;无人机精准降落成为一大挑战。基于PX4飞控固件和ROS系统的开源自主无人机平台Prometheus应运而生。…

【Linux】进程间通信之共享内存

文章目录 引入共享内存的原理共享内存的相关接口shmget()shmat()shmdt()shmctl() 共享内存的简单使用共享内存的特点 引入 进程间通信&#xff0c;顾名思义就是一个进程和另一个进程之间进行对话&#xff0c;以此完成数据传输、资源共享、通知事件或进程控制等。 众所周知&am…

Vscode安装,ssh插件与配置

原因 发现很多新人在练习linux&#xff0c;可是只有windows机的时候&#xff0c;一般都是下载虚拟机&#xff0c;然后在虚拟机上安装ubuntu等linux平台。每次需要在linux中写代码&#xff0c;就打开ubuntu&#xff0c;然后在终端上用vim写代码&#xff0c;或者先编辑代码文本&…

hook函数——useReducer

目录 1.useReducer定义2.useReducer用法3.useState和useReducer区别 1.useReducer定义 const [state, dispatch] useReducer(reducer, initialArg, init?) reducer&#xff1a;用于更新 state 的纯函数。参数为 state 和 action&#xff0c;返回值是更新后的 state。state …

JVM相关问题

JVM相关问题 一、Java继承时父子类的初始化顺序是怎样的&#xff1f;二、JVM类加载的双亲委派模型&#xff1f;三、JDK为什么要设计双亲委派模型&#xff0c;有什么好处&#xff1f;四、可以打破JVM双亲委派模型吗&#xff1f;如何打破JVM双亲委派模型&#xff1f;五、什么是内…

Matlab|基于Logistic函数负荷需求响应

目录 1 基于Logistic函数的负荷转移率模型 2 程序示例 3 效果图 4 下载链接 负荷需求响应模型种类较多&#xff0c;有电价型和激励型等类型&#xff0c;本次和大家分享一个基于Logistic函数的负荷转移率模型&#xff0c;该模型属于电价型&#xff0c;由于该方法使用的较少&a…

C++ //练习 10.24 给定一个string,使用bind和check_size在一个int的vector中查找第一个大于string长度的值。

C Primer&#xff08;第5版&#xff09; 练习 10.24 练习 10.24 给定一个string&#xff0c;使用bind和check_size在一个int的vector中查找第一个大于string长度的值。。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /*****…

云母带(耐火云母带)市场空间不断扩展 电力系统领域为其最大需求端

云母带&#xff08;耐火云母带&#xff09;市场空间不断扩展 电力系统领域为其最大需求端 云母带又称耐火云母带&#xff0c;指以云母片为原材料&#xff0c;经过一系列加工工艺制成的带状材料。云母带具有耐燃烧、耐高温、绝缘性好、耐酸碱等特性&#xff0c;在航空航天、石油…

复现nerfstudio并训练自己制作的数据集

网站&#xff1a;安装 - nerfstudio GitHub - nerfstudio-project/nerfstudio&#xff1a;NeRF 的协作友好工作室 安装之前要确保电脑上已经有CUDA11.8或以上版本&#xff08;更高版本的可以安装11.8的toolkit&#xff09; 创建环境 conda create --name nerfstudio -y pyt…