OpenPose MobileNet V1 作为Backbone的模型结构(3)

OpenPose MobileNet V1 作为Backbone的模型结构(3)

Branch的合并

论文地址
论文中提到的源码地址
深度可分离卷积是如何减少计算量的
OpenPose MobileNet V1 作为Backbone的模型结构(1) MobileNet V1 的改造
OpenPose MobileNet V1 作为Backbone的模型结构(2) Initial Stage和Refinement Stage的优化
OpenPose MobileNet V1 作为Backbone的模型结构(3) Branch的合并
flyfish
在这里插入图片描述论文原文
To produce new estimation of keypoint heatmaps and pafs the refinement stage takes features from backbone concatenated with previous estimation of keypoint heatmaps and pafs. Motivated by this fact we decided to share the most of computations between heatmaps and pafs and use single prediction branch in initial and refinement stage. We share all layers except the two last, which directly produce keypoint heatmaps and pafs.

1、上图左:VGG的OpenPose有两个prediction 分支,两个branch的结构是一样的,一个用来预测keypoint heatmap,一个用来预测PAFs。
2、上图右:MobileNet的OpenPose将两个branch合并成一个,只输出阶段使用1*1的卷积分出两个branch出来。一个用来预测keypoint heatmap,一个用来预测PAFs。

Initiate stage和Refinement stage这两个Stage各自都有合并
对于卷积通常封装成各种类型的卷积
例如
conv后面是否带BatchNorm2d,是否带ReLU
conv_dw深度可分离卷积后面是否BatchNorm2d,带ReLU还是带ELU

Initiate stage的branch的合并,下面的trunk是共享的

class InitialStage(nn.Module):
    def __init__(self, num_channels, num_heatmaps, num_pafs):
        super().__init__()
        self.trunk = nn.Sequential(
            conv(num_channels, num_channels, bn=False),
            conv(num_channels, num_channels, bn=False),
            conv(num_channels, num_channels, bn=False)
        )
        self.heatmaps = nn.Sequential(
            conv(num_channels, 512, kernel_size=1, padding=0, bn=False),
            conv(512, num_heatmaps, kernel_size=1, padding=0, bn=False, relu=False)
        )
        self.pafs = nn.Sequential(
            conv(num_channels, 512, kernel_size=1, padding=0, bn=False),
            conv(512, num_pafs, kernel_size=1, padding=0, bn=False, relu=False)
        )

    def forward(self, x):
        trunk_features = self.trunk(x)
        heatmaps = self.heatmaps(trunk_features)
        pafs = self.pafs(trunk_features)
        return [heatmaps, pafs]

Refinement stage的branch的合并,下面的trunk是共享的

对于Refinement stage先有Refinement stage block,多个这样的block组成Refinement stage

class RefinementStageBlock(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.initial = conv(in_channels, out_channels, kernel_size=1, padding=0, bn=False)
        self.trunk = nn.Sequential(
            conv(out_channels, out_channels),
            conv(out_channels, out_channels, dilation=2, padding=2)
        )

    def forward(self, x):
        initial_features = self.initial(x)
        trunk_features = self.trunk(initial_features)
        return initial_features + trunk_features


class RefinementStage(nn.Module):
    def __init__(self, in_channels, out_channels, num_heatmaps, num_pafs):
        super().__init__()
        self.trunk = nn.Sequential(
            RefinementStageBlock(in_channels, out_channels),
            RefinementStageBlock(out_channels, out_channels),
            RefinementStageBlock(out_channels, out_channels),
            RefinementStageBlock(out_channels, out_channels),
            RefinementStageBlock(out_channels, out_channels)
        )
        self.heatmaps = nn.Sequential(
            conv(out_channels, out_channels, kernel_size=1, padding=0, bn=False),
            conv(out_channels, num_heatmaps, kernel_size=1, padding=0, bn=False, relu=False)
        )
        self.pafs = nn.Sequential(
            conv(out_channels, out_channels, kernel_size=1, padding=0, bn=False),
            conv(out_channels, num_pafs, kernel_size=1, padding=0, bn=False, relu=False)
        )

    def forward(self, x):
        trunk_features = self.trunk(x)
        heatmaps = self.heatmaps(trunk_features)
        pafs = self.pafs(trunk_features)
        return [heatmaps, pafs]
### MobileNet V1 模型架构及其实现 #### 一、模型架构概述 MobileNet V1 是一种轻量级神经网络结构,专为移动设备设计。其核心创新在于引入了 **Depthwise Separable Convolutions** 技术[^2]。这种技术将传统的卷积分解为两个更简单的操作:深度可分离卷积(depthwise convolution)和逐点卷积(pointwise convolution)。这种方法显著减少了计算复杂度和参数数量。 具体来说,传统卷积的操作可以表示为 \(C_{in} \times C_{out} \times K_h \times K_w\) 参数数目的形式,而 Depthwise Separable Convolution 将这一过程分解为两步: 1. **Depthwise Convolution**: 对每个输入通道单独应用卷积核。 2. **Pointwise Convolution**: 使用 \(1 \times 1\) 卷积来组合特征图。 通过这种方式,MobileNet V1 能够大幅降低计算成本并保持较高的精度[^4]。 --- #### 二、模型结构细节 MobileNet V1 的标准层数为 28 层,主要由一系列 Depthwise Separable Convolution 堆叠而成。以下是其关键组成部分: 1. **Input Layer**: 输入图像大小通常为 \(224 \times 224 \times 3\)。 2. **Initial Convolution Layer**: 初始层是一个普通的 \(3 \times 3\) 卷积层,用于提取基础特征。 3. **Depthwise Separable Blocks**: 主干部分由多个 Depthwise Separable Convolution 组成,每组包含一个 depthwise 和 pointwise 卷积。这些模块通过 stride 进行下采样,而非采用 Max Pooling。 4. **Fully Connected Layer (FC)**: 输出前的最后一层全连接层负责分类任务。 5. **Softmax Activation**: 最终输出经过 Softmax 函数处理得到概率分布。 此外,为了进一步优化性能,MobileNet 提出了宽度乘子 (\(width multiplier\)) 和分辨率乘子 (\(resolution multiplier\))。这两个超参数允许开发者灵活调整模型规模以适应不同硬件资源需求。 --- #### 三、实现方式 以下是基于 TensorFlow 实现的一个简化版 MobileNet V1 结构代码示例: ```python import tensorflow as tf def depthwise_separable_conv(inputs, filters, kernel_size=3, strides=1): """定义单个 Depthwise Separable Convolution""" x = tf.keras.layers.DepthwiseConv2D(kernel_size=kernel_size, strides=strides, padding='same', activation=None)(inputs) x = tf.keras.layers.BatchNormalization()(x) x = tf.keras.layers.ReLU()(x) x = tf.keras.layers.Conv2D(filters=filters, kernel_size=(1, 1), strides=1, padding='same')(x) x = tf.keras.layers.BatchNormalization()(x) x = tf.keras.layers.ReLU()(x) return x def mobilenet_v1(input_shape=(224, 224, 3), num_classes=1000): """构建完整的 MobileNet V1 模型""" inputs = tf.keras.Input(shape=input_shape) # Initial Convolution Layer x = tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), strides=2, padding='same', activation=None)(inputs) x = tf.keras.layers.BatchNormalization()(x) x = tf.keras.layers.ReLU()(x) # Stack of Depthwise Separable Layers config = [ (64, 1), (128, 2), (128, 1), (256, 2), (256, 1), (512, 2), *[ (512, 1) for _ in range(5)], (1024, 2), (1024, 1) ] for filters, stride in config: x = depthwise_separable_conv(x, filters=filters, strides=stride) # Global Average Pooling and Fully Connected Layer x = tf.keras.layers.GlobalAveragePooling2D()(x) outputs = tf.keras.layers.Dense(num_classes, activation='softmax')(x) model = tf.keras.Model(inputs, outputs) return model model = mobilenet_v1() model.summary() ``` 上述代码展示了如何利用 `tf.keras` 构建 MobileNet V1,并实现了 Depthwise Separable Convolution 的堆叠逻辑[^3]。 --- #### 四、使用方法 在实际应用场景中,MobileNet V1 可被用作多种视觉任务的基础骨干网络,例如目标检测、语义分割等。以下是一些常见用途及其配置建议: 1. **Image Classification**: 设置合适的类别数目 (`num_classes`) 并微调最后一层权重。 2. **Object Detection**: 配合 SSD 或 Faster R-CNN 等框架,将 MobileNet V1 替代原有 Backbone3. **Transfer Learning**: 在预训练模型基础上针对特定数据集进行迁移学习,减少标注样本的需求。 需要注意的是,在部署到嵌入式平台之前,应考虑量化策略以进一步压缩模型体积。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二分掌柜的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值