68f036d452f5c5ff6b39959579e2a17d.png

STM32运算速度提升从何而来?

没错!加速STM32图像分类处理速度的就是数字信号处理器(DSP)。

目前Arm的Cortex-M4, Cortex-M7, Cortex-M33和Cortex-M35P微控制器内核均带有DSP。

相对CPU(擅长调度)来说,DSP非常擅长做运算,神经网络中的卷积、池化等复杂的运算操作都可以交由DSP来处理,从而加快处理速度。

054fec64b70c82e24eb0ffb66f5b6794.png

在Thumb指令集和可选浮点单元(FPU)上增加了DSP扩展,提高数值运算的性能。不仅使得在Cortex-M4、Cortex-M7、Cortex-M33和Cortex-M35P处理器上能够直接执行信号处理操作,而且还保持了Cortex-M编程模型的易用性。

查看项目源码中的arm_convolve_HWC_q7_RGB.c文件,你就会发现,STM32使用__SIMD32和__SXTB16等DSP指令以提高运算速度。

arm_status
arm_convolve_HWC_q7_RGB(const q7_t * Im_in,
                        const uint16_t dim_im_in,
                        ...
                        q7_t * Im_out, const uint16_t dim_im_out, q15_t * bufferA, q7_t * bufferB)
{
​
#if defined (ARM_MATH_DSP)
    /* Run the following code for Cortex-M4 and Cortex-M7 */
    // 源码省略...
    const q7_t *pPixel = Im_in + (i_ker_y * dim_im_in + i_ker_x) * 3;
    q31_t     buf = *__SIMD32(pPixel);
​
    union arm_nnword top;
    union arm_nnword bottom;
​
    top.word = __SXTB16(buf);
    bottom.word = __SXTB16(__ROR(buf, 8));
    // 源码省略...
#else
    /* Run the following code as reference implementation 
    for Cortex-M0 and Cortex-M3 */
    // 源码省略...
    
#endif                          /* ARM_MATH_DSP */
​
    /* Return to application */
    return (ARM_MATH_SUCCESS);
}

你也可以在Keil模拟器中体验一下在有无DSP的情况下,图像分类应用的执行速度。

b85ee50b666da63ca70b62f1cc0073a2.png

选择ARMCM3执行的时候将不会有DSP参与运算。

处理内存约束

STM32的内存是非常有限的,比如STM32F427AG只有256KB内存,在项目源文件arm_nnexamples_cifar10.cpp中,创建了col_buffer和scratch_buffer两个缓冲区,在神经网络的各层之间重用,从而实现减少内存用量。

  • col_buffer 中存储的是卷积层的输出
  • scratch_buffer 中存储的是中间层输出
// typedef int8_t q7_t; 
// typedef int16_t q15_t;
q7_t      col_buffer[2 * 5 * 5 * 32 * 2];
q7_t      scratch_buffer[32 * 32 * 10 * 4];
// Cut the scratch buffer to two buffers.
q7_t     *img_buffer1 = scratch_buffer;
q7_t     *img_buffer2 = img_buffer1 + 32 * 32 * 32;
​
// conv2 img_buffer2 -> img_buffer1
arm_convolve_HWC_q7_fast(img_buffer2, CONV2_IM_DIM, CONV2_IM_CH, conv2_wt, CONV2_OUT_CH, CONV2_KER_DIM,
                       CONV2_PADDING, CONV2_STRIDE, conv2_bias, CONV2_BIAS_LSHIFT, CONV2_OUT_RSHIFT, img_buffer1,
                       CONV2_OUT_DIM, (q15_t *) col_buffer, NULL);
​
arm_relu_q7(img_buffer1, CONV2_OUT_DIM * CONV2_OUT_DIM * CONV2_OUT_CH);
​
// pool2 img_buffer1 -> img_buffer2
arm_maxpool_q7_HWC(img_buffer1, CONV2_OUT_DIM, CONV2_OUT_CH, POOL2_KER_DIM,
                 POOL2_PADDING, POOL2_STRIDE, POOL2_OUT_DIM, col_buffer, img_buffer2);

arm_convolve_HWC_q7_fast函数创建了一个卷积层,在本例中卷积层以img_buffer2作为输入,以img_buffer1作为输出,以col_buffer作为内部卷积运算过程中的数据存储区。

然后激活函数层(arm_relu_q7函数)直接在img_buffer1 上进行ReLu操作,处理后数据依然放在 img_buffer1中。

再然后img_buffer1将作为最大池化层(arm_maxpool_q7_HWC函数)的输入,进行池化操作后,将数据输出到img_buffer2,如此反复的使用这2个内存区域,直到网络计算完成。

由于STM32上 内存非常有限,我们不能随意的给这2个内存区域分配很大的空间,我们需要精打细算。

其中col_buffer的大小的计算方法如下:

# 2*2*过滤器(卷积核)数量*卷积核宽度*卷积核高度
2*2*(conv # of filters)*(kernel width)*(kernel height)

这些参数可以在Caffe模型中查看到,如下图所示:

2b077e8de53f0b4590d2e262d8e7ba24.png

在本例中,我们一共有3个卷积层,其中一个卷积层(conv1)所需的内存空间最大(2*2*32*5*5=3200字节),所以col_buffer的大小就是3200字节。col_buffer将在所有的卷积层中使用。

scratch_buffer 分为两个部分img_buffer1和img_buffer2,对于某个特定的层来说,一个作为输入,则另一个作为输出。其大小可通过遍历各层的使用情况来确定。

86763c3d2963af184045cac1d071f858.png

从上图可以看出scratch_buffer的大小为:

max(img_buffer1)+max(img_buffer2) = 32*32*40

选择合适的卷积层函数

在CMSIS-NN库中,有多个卷积层函数:

  • arm_convolve_HWC_q7_basic
  • arm_convolve_HWC_q7_fast
  • arm_convolve_HWC_q7_RGB
  • arm_convolve_HWC_q7_fast_nonsquare

它们中的每一个都在不同程度上针对速度和大小进行了优化,但也有不同的针对性。

arm_ve_HWC_q7_basic函数是最基本的版本,设计用于任何二阶张量和任何维度的权重。

arm_ve_HWC_q7_fast函数正如它的名字所暗示的那样,运行速度比前一个函数快,但是要求输入张量通道是4的倍数,而输出张量通道(过滤器的数量)是2的倍数。

arm_ve_HWC_q7_rgb是专门为输入张量通道数等于3的卷积而构建的,它通常应用于第一个卷积层以RGB图像数据为输入的网络。

arm_convolve_HWC_q7_fast_nonsquare类似于arm_convolve_HWC_q7_fast,但是可以取非二阶的输入张量。

对于全连接层,两个最不同的选项是:

  • arm_fully_connected_q7
  • arm_fully_connected_q7_opt

第一个使用常规的权值矩阵,另一个使用后缀"_opt"来优化速度,但是层的权值矩阵必须预先以交错的方式排序。

总结

本期我们对STM32图像分类应用内部的3个关键点:DSP加速、内存使用和卷积层函数的选择进行了说明。希望对你的CMSISI-NN应用开发能够有所帮助。

可能有些同学对卷积、ReLu激活函数、最大池化等机器学习概念不熟悉,没关系,下期我们将着重介绍这些内容,欢迎持续关注!

更多精彩资讯,请扫码关注!

65938c53b603abbd74580a137df331ec.png
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐