物联网已经深入到我们生活的方方面面,例如穿戴式医疗设备、智能家居。大部分的物联网设备会将采集到的数据上传至云端,由后台进行数据处理和分析,再将结果返回给微处理器。然而这种云端处理数据的方式不适用于一些对实时性要求高的物联网边缘设备,通过ARM Cortex-M系列处理器内核进行Machine Learning成为了技术发展的需要,CMSIS-NN就是解决方法之一。机器学习运用到嵌入式系统中有以下的优点[1]:
CMSIS-NN库分为了两个部分,NNFuctions和NNSupportFunctions,图片摘自CMSIS-NN Block Diagram。
NNFuctions运用了卷积神经网络Convolutional Neural Network(CNN),包括了:
要掌握CMSIS-NN,首先得理解CNN,所以先说一说卷积神经网络。
首先贴上卷积的公式,一个是连续性的,一个是离散型的:
( f ∗ g ) ( n ) = ∫ − ∞ ∞ f ( τ ) g ( n − τ ) d τ (f * g)(n) = \int_{-{\infty}}^{\infty}f(\tau)g(n-\tau)d\tau (f∗g)(n)=∫−∞∞f(τ)g(n−τ)dτ
( f ∗ g ) ( n ) = ∑ τ = − ∞ ∞ f ( τ ) g ( n − τ ) (f * g)(n) = \sum_{\tau = -\infty}^{\infty}f(\tau)g(n - \tau) (f∗g)(n)=τ=−∞∑∞f(τ)g(n−τ)
卷积是怎么卷的?
卷积的核心在于降维。我们令 x = τ , y = n − τ x = \tau, y = n - \tau x=τ,y=n−τ,那么 x + y = n x + y = n x+y=n,也就是二维平面上一条可移动的直线(图1)。当我们遍历这条直线,也就是做积分或者是求和,像是把二维平面从45°斜线卷起来,就形成了一个一维的直线函数,每个点的函数值等于卷起来后重合的点的函数值之和。这样就从一个二维函数降到了一维函数。此处参考于 荆哲:卷积为什么叫「卷」积?,非常形象地解释了“卷”的含义。
图1 二维平面 x + y = n 图2 一维函数
对于灰色图像的卷积,我们只需要将图像看成 m × n m × n m×n的矩形,而彩色RGB图像的卷积,我们可以将其分为Red、Green、Blue三个map,也就是深度为3,是个 m × n × 3 m × n × 3 m×n×3的长方体。我们首先讨论 m × n m × n m×n的2-D卷积:kernel卷积核 p × q p × q p×q在x,y方向上滑动。
kernel一般选取 3 × 3 3 × 3 3×3或 5 × 5 5 × 5 5×5的大小, A i j A_{ij} Aij表示权重 w w w,原图像的 B i j B_{ij} Bij表示图像亮度值 v v v:
g = [ A 11 A 12 A 13 A 21 A 22 A 23 A 31 A 32 A 33 ] g = \left[ \begin{matrix} A_{11}& A_{12} & A_{13} \\ A_{21} & A_{22} & A_{23} \\ A_{31} & A_{32} & A_{33} \end{matrix} \right] g=⎣⎡A11A21A31A12A22A32A13A23A33⎦⎤
卷积的过程可以表示为:
c o n v x , y = ∑ i p ∗ q w i v i conv_{x,y} = \sum_{i}^{p*q}w_iv_i convx,y=i∑p∗qwivi
如果所示,Image Matrix和Kernel Matrix进行矩阵相乘,即0 × (-1) + 0 × (-2) + 75 × (-1) + 0 × 0 + 75 ×0 + 80 × 0 + 0 × 1 + 75 × 2 + 80 × 1 = 155 ,将该值写入Output Matrix对应的位上,这样计算出了第一个值。以下图片均来自Convolutional Neural Networks - Basics。
随后将kernel沿着 ( x , y ) (x,y) (x,y)方向平移扫描,即可得出整个Output matrix的值。
一个 m × n m × n m×n,在不考虑边界零填充(zero padding)的情况下,输出是一个 ( m − 2 ) × ( n − 2 ) (m-2) × (n-2) (m−2)×(n−2)的矩阵。当考虑zero padding,即在 m × n m × n m×n的图像四周添加2行2列的0,输出可以得到一个和原图像大小相同的 m × n m × n m×n的矩阵。例如下图。
考虑zero padding的原因:一是对图像边缘只扫描一次的话可能会忽略边缘的信息;二是保持图像大小,不然卷积次数多了之后图像会越来越小。
kernel的个数、大小、平移步长都可以根据实际情况进行调整。
若将RGB图像分为3层进行卷积,就需要一个立体的深度为3的kernel,在x,y,z三个方向上进行扫描,此处不再论述。
激活函数的作用是给函数加入偏置:
Z ( x , y ) = h ( ∑ i p ∗ q w i v i + b ) Z(x,y) = h(\sum_{i}^{p*q}w_iv_i+b) Z(x,y)=h(i∑p∗qwivi+b)
常用的激活函数有 S i g m o i d Sigmoid Sigmoid、 t a n h tanh tanh以及 R e L u ReLu ReLu。 S i g m o i d Sigmoid Sigmoid和 t a n h tanh tanh函数常用于全连接层, R e L u ReLu ReLu函数常用语卷积层。
在CMSIS-NN中用到的激活函数是 R e L u ReLu ReLu Function(Rectified Linear Units Function),作用是输出非负数,可表示为:
R e L u = m a x ( 0 , T ) ReLu = max(0,T) ReLu=max(0,T)
池化函数的主要作用是通过特征降维对图像进行压缩,降低feature maps的分辨率,以此减少计算量,同时提高容错率。
池化一般选取 2 × 2 2 × 2 2×2的滑动窗口作为池化区域,通过相应的池化函数将4个像素转换为1个像素。常用的池化函数有 M a x Max Max $ Pooling 和 和 和Average$ $ Pooling$。
下图中采用了 M a x Max Max P o o l i n g Pooling Pooling F u n c t i o n Function Function,在四个像素中选取了最大的数值 m a x ( 0.11 , 0.33 , − 0.11 , 0.33 ) = 0.33 max(0.11,0.33,-0.11,0.33) = 0.33 max(0.11,0.33,−0.11,0.33)=0.33作为结果。例如下图。以下两张图摘自[大话卷积神经网络(CNN)][pooling and fully]。
不过并不是所有情况下,进行池化后的效果会更好,因为池化的过程中可能丢失了信息。
全连接层首先将多个map经过Convolution、Activation、Pooling后的结果合并到一起,即将每个 n × n n × n n×n的矩阵都拆开转成 ( n 2 ) × 1 (n^2) × 1 (n2)×1的列矩阵,再将 N N N个列矩阵合并成 ( n 2 × N ) × 1 (n^2 × N) × 1 (n2×N)×1的列矩阵。例如下图。
其次,根据已训练好的监督学习模型得到全连接层每一个特征值的权重,将列矩阵与权重加权求和,通过Softmax函数对数值进行分类匹配,最贴近的就是识别结果。
CNN算法可以分为两个部分:
CMSIS-NN采用的是框架如下图。
使用了以下函数:
[1] ARM Developer, Image recognition on ARM Cortex-M with CMSIS-NN, https://developer.arm.com/solutions/machine-learning-on-arm/developer-material/how-to-guides/image-recognition-on-arm-cortex-m-with-cmsis-nn/single-page. 01 April 2019, Accessed 2020-08-19