1. 在完成基础的测试后就可以详细分析一下这个具体实现的程序和逻辑。如下附件, main.c (7.89 KB, 下载次数: 0)
中间用到的库是CMSIS-NN,如下截图
2. 主要代码分析- // conv1 img_buffer2 -> img_buffer1
- arm_convolve_HWC_q7_RGB(img_buffer2, CONV1_IM_DIM, CONV1_IM_CH, conv1_wt, CONV1_OUT_CH, CONV1_KER_DIM, CONV1_PADDING,
- CONV1_STRIDE, conv1_bias, CONV1_BIAS_LSHIFT, CONV1_OUT_RSHIFT, img_buffer1, CONV1_OUT_DIM, (q15_t *) col_buffer, NULL);
- arm_relu_q7(img_buffer1, CONV1_OUT_DIM * CONV1_OUT_DIM * CONV1_OUT_CH);
- // pool1 img_buffer1 -> img_buffer2
- arm_maxpool_q7_HWC(img_buffer1, CONV1_OUT_DIM, CONV1_OUT_CH, POOL1_KER_DIM, POOL1_PADDING, POOL1_STRIDE, POOL1_OUT_DIM, NULL, img_buffer2);
- // 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);
- // conv3 img_buffer2 -> img_buffer1
- arm_convolve_HWC_q7_fast(img_buffer2, CONV3_IM_DIM, CONV3_IM_CH, conv3_wt, CONV3_OUT_CH, CONV3_KER_DIM, CONV3_PADDING, CONV3_STRIDE, conv3_bias, CONV3_BIAS_LSHIFT, CONV3_OUT_RSHIFT, img_buffer1, CONV3_OUT_DIM, (q15_t *) col_buffer, NULL);
- arm_relu_q7(img_buffer1, CONV3_OUT_DIM * CONV3_OUT_DIM * CONV3_OUT_CH);
- // pool3 img_buffer-> img_buffer2
- arm_maxpool_q7_HWC(img_buffer1, CONV3_OUT_DIM, CONV3_OUT_CH, POOL3_KER_DIM, POOL3_PADDING, POOL3_STRIDE, POOL3_OUT_DIM, col_buffer, img_buffer2);
- arm_fully_connected_q7_opt(img_buffer2, ip1_wt, IP1_DIM, IP1_OUT, IP1_BIAS_LSHIFT, IP1_OUT_RSHIFT, ip1_bias, output_data, (q15_t *) img_buffer1);
- arm_softmax_q7(output_data, 10, output_data);
复制代码
3. 这个程序是标准的数字识别模型,通过一个手写的数字图片32x32pixal,识别从0-9是哪个数据。
一幅图如输入,从最左边开始,分为3层卷积计算,每个层都包括一个卷积层,一个池化层,最后经过全连层,最后经过softmax分类函数直接输出解析的数据结果。这个过程直接对应了上面的代码。
第一层,
卷积函数 arm_convolve_HWC_q7_RGB(); 采用了专门的RGB转换,在彩色图形上更有效率,
激活函数arm_relu_q7();
池化层函数arm_maxpool_q7_HWC();
第二层,同第一层,但是卷积函数采用了_fast模式,因为已经在第一层进行了彩色转换,
卷积函数 arm_convolve_HWC_q7_fast();
激活函数arm_relu_q7();
池化层函数arm_maxpool_q7_HWC();
第三层,同第二层,
卷积函数 arm_convolve_HWC_q7_fast();
激活函数arm_relu_q7();
池化层函数arm_maxpool_q7_HWC();
最后输出层
全连层,arm_fully_connected_q7_opt();
softmax分类函数arm_softmax_q7(output_data, 10, output_data);
其中的output_data就是一个1x10阶数组,当该位为1时,是对应识别出来的数字。
根据模型,这里面的识别精度在92%左右,也就是有一部分识别是不准确的。
4、从直观理解来看,并没有非常难以实现的地方。但是,这里面每层的参数和层数其实是自己定义和训练train后的。这个train的过程要在深度学习的模型中训练,可以用python也可以C++来实现,最终需要把训练的模型输出,记录重要的参数save到另外的程序中,转换到输入的数组参数,以便于使用。
需要如下定义,
#define CONV2_BIAS {55,50,34,43,-37,35,-21,10,35,-53,-76,7,14,-1,92,20}
#define CONV3_WT{ ... ...}
... ...
详见附件, arm_nnexamples_cifar10_weights.h (99.29 KB, 下载次数: 0)
5、具体使用哪种深度学习模型,根据熟悉程度来使用。这个范例程序使用的是UCB的caffe,这个和后来升级的caffe2有很大的不同,如果需要安装使用,需要的版本和开发环境是受限制的。安装的过程最终没有成功,所以不能分享。
不过,这个模型是一个开放模型,其实用tensorflow和pytorch也是可以train训练处这样的weight的,训练模型导出后就可以使用了。
所以,简单总结一下使用边缘计算的过程:
- 用tensorflow等创建一个计算图graph,这里包括了NN的层数和参数配置,
- 然后,采集训练数据集,输入到图中,进行训练,
- 训练后的结果,导出各层的权重和数据。
- 按照cmsis-nn的函数和定义,对应建立层数和激活函数,构成图,导入训练输出的模型数据。
最后,调试并运行。
如果开发板具有摄像头,可以把摄像头的截图及时裁剪并输入到计算图中,就可以得出对应数据。
|