查看原文
其他

你知道吗?MCU也能做Machine Learning

Frank 边缘智能实验室 2021-01-31

刚刚过去的2018年被称为“人工智能元年”,2019年人工智能将会有更大的发展,将会有更多的AI项目落地。随着单芯片计算力的不断增长,机器学习(ML)不再是云计算和高性能处理器的专利,边缘计算正在崛起!

边缘计算为AI提供了新的可能性,比如实时智能语音识别和实时人脸检测,边缘计算的实时性、可靠性和隐私安全性是云计算无法相比的。

先通过视频直观的感受一下吧!


实战开始:使用CMSIS-NN在STM32F746G实现图像识别

1.准备工作

工欲善其事必先利其器,首先你需要相关的软件和硬件。

硬件

  • STM32F746G-DISCO开发板

  • STM32F4DIS-摄像头模块

注意:本教程所有步骤都能非常容易的在其他开发板上实现。

软件

  • Ubuntu 16.04

  • Python 2.7.12

  • Caffe

  • GNU Arm嵌入式工具链 推荐版本: gcc-arm-none-eabi-7-2017-q4-major

2.定义问题和模型

为了让你的边缘设备拥有更快的响应,更高的可靠性、安全性和更低的功耗,图像识别程序必须直接运行在你的设备上,而不是云端。

神经网络(NN)是机器学习(ML)算法中的一类,它在图像分类、目标识别、语音识别和自然语言处理应用中有着非常出色的表现。现在最流行的神经网络是多层感知机(MLP),卷积神经网络(CNN)和递归神经网络(RNN)。

在本教程中我们选择使用卷积神经网络(CNN),它来自于Caffe官方的一个示例,该示例对CIFAR-10图像数据集进行分类任务,在这个示例中图像数据被输进卷积神经网络(CNN)进行分类,最后输出图像所属的类别。卷积神经网络(CNN)有不同的实现方式,下面是本教程选择的卷积神经网络:

模型的输入是一个32*32像素的彩色图片,它将被卷积神经网络(CNN)分为10类物体(猫、鹿、狗、马...)中的一类。分类任务的完成,依赖于神经网络的各个层:

  • 卷积层

  • 池化层

  • 激活函数

  • 全连接层

  • Softmax

提示:CIFAR-10是一个图像数据集,一共包含10类图像(飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车),其中每类图像包含60000幅32*32的彩色图像。

如果有同学对卷积神经网络不了解,请在文末扫码关注小编,并在后台发送“计算机视觉”,即可获取参考资料。

在本教程中,我们将使用事先训练好的卷积神经网络模型,你可以到我们的GitHub仓库下载,如果你想训练自己的模型,请参考教程《基于Caffe的深度学习》。下面就是本教程使用的卷积神经网络(CNN)模型的拓扑结构。

上面的拓扑图是使用Netscope工具生成的。

提示:由于微信不支持外部链接,所以将文中相关链接集中放到了公众号的自动回复中,扫码关注小编,在后台发送“CMSIS-NN”(大写哦),即可获取本文相关链接。

3.开发环境设置

  • 安装ARM Mbed CLI

  1. sudo pip install mbed-cli

  • 创建工作空间

  1. # In your <home> directory (cd ~)

  2. mkdir CMSISNN_Webinar

  3. cd CMSISNN_Webinar

  4. # Create new Mbed project

  5. # The --mbedlib flag picks Mbed-os version 2.0

  6. mbed new cmsisnn_demo --mbedlib

假如你是第一次使用Mbed工具,请安装相关依赖

  1. cd cmsisnn_demo/.temp/tools/

  2. sudo pip install -r requirements.txt


  3. # 也许你还需要安装这些

  4. sudo pip install jsonschema

  5. sudo pip install pyelftools

  6. sudo apt-get install mercurial

4.构建基本的相机应用

  • 执行如下操作

  1. cd ~/CMSISNN_Webinar/cmsisnn_demo

  2. mbed add http://os.mbed.com/teams/ST/code/BSP_DISCO_F746NG/

  3. mbed add http://os.mbed.com/teams/ST/code/LCD_DISCO_F746NG

  • 获取Mbed稳定版本

  1. # 打开mbed.bld文件,使用下面的链接替换文件中第一行的内容

  2. https://mbed.org/users/mbed_official/code/mbed/builds/e95d10626187

  • 获取依赖库

  1. mbed deploy

  • 获取相机应用示例

  1. cd ~/CMSISNN_Webinar/

  2. git clone https://github.com/ARM-software/ML-examples.git

  • 编译

  1. cd cmsisnn_demo/

  2. mbed compile -m DISCO_F746NG -t GCC_ARM --source . --source ../ML-examples/cmsisnn-cifar10/camera_demo/camera_app/

  • 图像采集测试

将生成的.bin文件直接拖拽到你的开发板存储中。

提示:

Mbed开发板通过USB连接到PC后,会生成一个盘符,将固件复制进去即可更新程序,不了解Mbed的同学请自行百度。

如果以上步骤成功执行,那么你将看到如下画面:

5.转化预训练的Caffe模型

为了使卷积神经网络模型能够在ARM Cortex-M微控制器上运行,我们必须要对Caffe模型进行优化。

5.1模型量化(Quantize the model)

使用nn_quantizer.py脚本(此文件存在于之前从GitHub下载的ML-examples项目中)将Caffe模型的权重和激活函数从32位浮点型数据转换为8位定点格式。这不会减小神经网络的大小,但是可以避免复杂的浮点运算。此脚本文件将会找出最优的8位定点数的表示方式,以确保在测试数据集上的最小精度损失。此脚本的执行输出是一个序列化的Python pickle(.pkl)文件,它包含神经网络模型,量化的权重和激活函数,以及每一层的量化格式。

执行如下命令即可生成量化模型:

  1. # Run command in the ML-examples/cmsisnn-cifar10 directory

  2. cd ~/CMSISNN_Webinar/ML-examples/cmsisnn-cifar10

  3. # Note: To enable GPU for quantization sweeps, use '--gpu' argument

  4. python nn_quantizer.py --model models/cifar10_m7_train_test.prototxt --weights models/cifar10_m7_iter_300000.caffemodel.h5 --save models/cifar10_m7.pkl

5.2转换模型

现在你已经拥有了一个优化的模型,下面我们将这个模型转换为一个C++文件,然后你可以将这个C++程序集成到你的相机应用项目中。

  1. # Run command in the ML-examples/cmsisnn-cifar10 directory

  2. python code_gen.py --model models/cifar10_m7.pkl --out_dir code/m7

这个脚本的执行将获取到量化参数和网络连接图,并且将生成由NN函数调用组成的代码。

6.构建图像识别应用

最后一步,我们将在图像采集应用中集成神经网络。

6.1包含nn.h

为了实现这一步,我们需要对文件ML-examples/cmsisnn-cifar10/camerademo/cameraapp/camera_app.cpp做一些修改。

  1. # In ML-examples/cmsisnn-cifar10/camera_demo/camera_app/

  2. # Rename the camera application

  3. mv camera_app.cpp camera_with_nn.cpp

  • 首先,我们将之前通过codegen.py脚本生成的代码包含进camerawith_nn.cpp文件

  1. #include "nn.h"

6.2添加分类能力

在开始之前我们需要定义一些变量。

  1. 标签变量-用字符串标识最终的输出结果

  2. 输出数据数组-用于存储神经网络的输出

  1. const char* cifar10_label[] = {"Plane", "Car", "Bird", "Cat", "Deer", "Dog", "Frog", "Horse", "Ship", "Truck"};

  2. q7_t output_data[10]; //10-classes

我们还需要一个函数去获取softmax输出的最优预测值:

  1. int get_top_prediction(q7_t* predictions)

  2. {

  3. int max_ind = 0;

  4. int max_val = -128;

  5. for(int i=0;i<10;i++) {

  6. if(max_val < predictions[i]) {

  7. max_val = predictions[i];

  8. max_ind = i;

  9. }

  10. }

  11. return max_ind;

  12. }

6.3修改camerawithnn.cpp文件中的main函数

现在是时候添加神经网络函数调用了,此函数是之前我们通过code_gen.py脚本生成的。

  1. // run neural network

  2. run_nn((q7_t*)resized_buffer, output_data);

  3. // Softmax: to get predictions

  4. arm_softmax_q7(output_data,IP1_OUT_DIM,output_data);

我们还需要标识出图片属于哪个类别的可能性最大,通过下面的函数实现:

  1. int top_ind = get_top_prediction(output_data);

最后,添加以下代码测试输出,打印预测结果和可信度。

  1. sprintf(lcd_output_string," Prediction: %s ",cifar10_label[top_ind]);

  2. lcd.DisplayStringAt(0, LINE(8), (uint8_t *)lcd_output_string, LEFT_MODE);

  3. sprintf(lcd_output_string," Confidence: %.1f%% ",(output_data[top_ind]/127.0)*100.0);

  4. lcd.DisplayStringAt(0, LINE(9), (uint8_t *)lcd_output_string, LEFT_MODE);

7.CMSIS-NN

为了充分利用微控制器的能力,接下来我们将使用CMSIS-NN优化库。CMSIS-NN是专门为ARM Cortex-M处理器内核设计的一套高效的神经网络库,它将Cortex-M处理器内核的性能发挥到极致。基于CMSIS-NN的神经网络接口,在运行时实现了4.6倍的性能提升,在能量充足的情况下实现了4.9倍的性能提升。

获取CMSIS-NN库:

  1. cd ~/CMSISNN_Webinar

  2. git clone https://github.com/ARM-software/CMSIS_5.git

下面的这些函数将被nn.cpp文件中的run_nn(input, output)函数调用,它们被定义在 CMSIS-NN 库中, 示例如下:

  1. arm_convolve_HWC_q7_RGB(input_data, CONV1_IN_DIM, CONV1_IN_CH, conv1_wt, CONV1_OUT_CH, CONV1_KER_DIM, CONV1_PAD, CONV1_STRIDE, conv1_bias, CONV1_BIAS_LSHIFT, CONV1_OUT_RSHIFT, buffer1, CONV1_OUT_DIM, (q15_t*)col_buffer, NULL);

  2. arm_maxpool_q7_HWC(buffer1, POOL1_IN_DIM, POOL1_IN_CH, POOL1_KER_DIM, POOL1_PAD, POOL1_STRIDE, POOL1_OUT_DIM, col_buffer, buffer2);

  3. arm_relu_q7(buffer2, RELU1_OUT_DIM*RELU1_OUT_DIM*RELU1_OUT_CH);

现在我们已经优化了模型,并且完整构建了图像识别应用,是时候进行最后一步了!

8.将图像识别程序部署到开发板上

  • 编译我们创建的图像识别程序

  1. cd cmsisnn_demo/

  2. mbed compile -m DISCO_F746NG -t GCC_ARM --source . --source ../ML-examples/cmsisnn-cifar10/code/m7 --source ../ML-examples/cmsisnn-cifar10/camera_demo/camera_app/ --source ../CMSIS_5/CMSIS/NN/Include --source ../CMSIS_5/CMSIS/NN/Source --source ../CMSIS_5/CMSIS/DSP/Include --source ../CMSIS_5/CMSIS/DSP/Source --source ../CMSIS_5/CMSIS/Core/Include -j8

将生成的.bin文件,放进你的开发板中运行。

运行结果如下:

提示:由于微信不支持外部链接,所以将文中相关链接集中放到了公众号的自动回复中,扫码关注小编,在后台发送“CMSIS-NN”(大写哦),即可获取本文相关链接。

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


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存