你知道吗?MCU也能做Machine Learning
刚刚过去的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
sudo pip install mbed-cli
创建工作空间
# In your <home> directory (cd ~)
mkdir CMSISNN_Webinar
cd CMSISNN_Webinar
# Create new Mbed project
# The --mbedlib flag picks Mbed-os version 2.0
mbed new cmsisnn_demo --mbedlib
假如你是第一次使用Mbed工具,请安装相关依赖
cd cmsisnn_demo/.temp/tools/
sudo pip install -r requirements.txt
# 也许你还需要安装这些
sudo pip install jsonschema
sudo pip install pyelftools
sudo apt-get install mercurial
4.构建基本的相机应用
执行如下操作
cd ~/CMSISNN_Webinar/cmsisnn_demo
mbed add http://os.mbed.com/teams/ST/code/BSP_DISCO_F746NG/
mbed add http://os.mbed.com/teams/ST/code/LCD_DISCO_F746NG
获取Mbed稳定版本
# 打开mbed.bld文件,使用下面的链接替换文件中第一行的内容
https://mbed.org/users/mbed_official/code/mbed/builds/e95d10626187
获取依赖库
mbed deploy
获取相机应用示例
cd ~/CMSISNN_Webinar/
git clone https://github.com/ARM-software/ML-examples.git
编译
cd cmsisnn_demo/
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)文件,它包含神经网络模型,量化的权重和激活函数,以及每一层的量化格式。
执行如下命令即可生成量化模型:
# Run command in the ML-examples/cmsisnn-cifar10 directory
cd ~/CMSISNN_Webinar/ML-examples/cmsisnn-cifar10
# Note: To enable GPU for quantization sweeps, use '--gpu' argument
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++程序集成到你的相机应用项目中。
# Run command in the ML-examples/cmsisnn-cifar10 directory
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做一些修改。
# In ML-examples/cmsisnn-cifar10/camera_demo/camera_app/
# Rename the camera application
mv camera_app.cpp camera_with_nn.cpp
首先,我们将之前通过codegen.py脚本生成的代码包含进camerawith_nn.cpp文件
#include "nn.h"
6.2添加分类能力
在开始之前我们需要定义一些变量。
标签变量-用字符串标识最终的输出结果
输出数据数组-用于存储神经网络的输出
const char* cifar10_label[] = {"Plane", "Car", "Bird", "Cat", "Deer", "Dog", "Frog", "Horse", "Ship", "Truck"};
q7_t output_data[10]; //10-classes
我们还需要一个函数去获取softmax输出的最优预测值:
int get_top_prediction(q7_t* predictions)
{
int max_ind = 0;
int max_val = -128;
for(int i=0;i<10;i++) {
if(max_val < predictions[i]) {
max_val = predictions[i];
max_ind = i;
}
}
return max_ind;
}
6.3修改camerawithnn.cpp文件中的main函数
现在是时候添加神经网络函数调用了,此函数是之前我们通过code_gen.py脚本生成的。
// run neural network
run_nn((q7_t*)resized_buffer, output_data);
// Softmax: to get predictions
arm_softmax_q7(output_data,IP1_OUT_DIM,output_data);
我们还需要标识出图片属于哪个类别的可能性最大,通过下面的函数实现:
int top_ind = get_top_prediction(output_data);
最后,添加以下代码测试输出,打印预测结果和可信度。
sprintf(lcd_output_string," Prediction: %s ",cifar10_label[top_ind]);
lcd.DisplayStringAt(0, LINE(8), (uint8_t *)lcd_output_string, LEFT_MODE);
sprintf(lcd_output_string," Confidence: %.1f%% ",(output_data[top_ind]/127.0)*100.0);
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库:
cd ~/CMSISNN_Webinar
git clone https://github.com/ARM-software/CMSIS_5.git
下面的这些函数将被nn.cpp文件中的run_nn(input, output)函数调用,它们被定义在 CMSIS-NN 库中, 示例如下:
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);
arm_maxpool_q7_HWC(buffer1, POOL1_IN_DIM, POOL1_IN_CH, POOL1_KER_DIM, POOL1_PAD, POOL1_STRIDE, POOL1_OUT_DIM, col_buffer, buffer2);
arm_relu_q7(buffer2, RELU1_OUT_DIM*RELU1_OUT_DIM*RELU1_OUT_CH);
现在我们已经优化了模型,并且完整构建了图像识别应用,是时候进行最后一步了!
8.将图像识别程序部署到开发板上
编译我们创建的图像识别程序
cd cmsisnn_demo/
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”(大写哦),即可获取本文相关链接。