AI-ANNE: 将神经网络迁移到微控制器的深度探索——论文阅读
AI-ANNE: 将神经网络迁移到微控制器的深度探索
Klinkhammer D. AI-ANNE:(A)(N) eural (N) et for (E) xploration: Transferring Deep Learning Models onto Microcontrollers and Embedded Systems[J]. arXiv preprint arXiv:2501.03256, 2025.
引言:嵌入式系统中的人工智能革命
机器学习和深度学习正在推动各个领域的创新发展,从计算机视觉到自然语言处理,从医疗诊断到工业自动化。近年来,这种创新浪潮正逐渐扩展到嵌入式系统领域,将智能计算能力直接带到数据源头。这种被称为TinyML的趋势,特别在微控制器和物联网(IoT)设备中展现出巨大潜力。
TinyML相比传统的基于云的人工智能解决方案,具有诸多独特优势。首先,数据隐私得到更好保护,因为敏感数据无需传输到云端即可在本地处理。其次,处理延迟大幅降低,从云端往返的网络延迟被消除,实现真正的实时响应。第三,能源效率显著提升,避免了数据传输的能耗开销。最后,系统对网络连接的依赖性降低,即使在网络不稳定或完全离线的环境中也能正常工作。
本研究提出的AI-ANNE(A Neural Net for Exploration)框架,旨在解决将预训练神经网络模型迁移到资源受限微控制器的挑战。通过在MicroPython中重新实现神经网络的核心组件,包括神经元、层、密度和激活函数,使得在TensorFlow和Keras等高性能框架上训练的模型能够在Raspberry Pi Pico等微控制器上运行,同时保持相同的推理能力。
硬件平台与开发环境
Raspberry Pi Pico系列微控制器
Raspberry Pi Pico采用RP2040微控制器,配备双核ARM Cortex-M0+处理器,运行频率133 MHz,具有264 KB片上SRAM和2 MB板载闪存。这款微控制器提供了丰富的连接选项:USB接口用于供电和数据传输,最多两个I2C、SPI和UART接口用于通信,16个PWM通道用于精确控制外部设备。板载还包括三个12位ADC通道用于模拟输入,支持实时时钟(RTC)、定时器和通过嵌套向量中断控制器(NVIC)进行中断处理等外设。
2024年推出的升级版Raspberry Pi Pico 2搭载RP2350微控制器,配备双核ARM Cortex-M33处理器,运行频率提升至150 MHz,片上SRAM增加到520 KB,板载闪存扩展到4 MB。性能的提升使Pico 2能够处理更大的数据集和更复杂的神经网络。对于实际应用,建议使用Raspberry Pi Pico 2;而对于教育目的,原版Raspberry Pi Pico已经足够。
MicroPython编程语言
MicroPython是Python编程语言的精简高效实现,专门设计用于在资源受限的微控制器和嵌入式系统上运行。与完整的Python环境不同,MicroPython经过优化,能够在小型设备典型的内存和处理限制内运行,提供精简的解释器和Python标准库的子集。
MicroPython保留了Python的大部分高级语法和易用性,使熟悉Python的开发者能够快速上手。在神经网络应用的背景下,MicroPython特别适合边缘计算场景,其中深度学习模型需要直接部署到基于微控制器的系统上进行实时、本地化推理。虽然MicroPython不原生支持完整Python中的大量数值库(如TensorFlow和Keras),但通过AI-ANNE框架,可以从零开始在MicroPython中重现神经网络的基本架构。
神经网络架构的数学基础
神经元:计算的基本单元
神经网络中的神经元是一个计算单元,其数学模型可以描述为接收多个输入信号,对每个输入应用特定权重,将加权输入求和,加上偏置项,最后通过激活函数产生输出。这个过程的数学表达式为:
其中,是神经元的输出,是激活函数,是第个输入,是对应的权重,是偏置项,是输入的数量。
在MicroPython实现中,这个计算过程分解为几个步骤。首先初始化一个零向量来存储累加结果,然后遍历所有输入,计算每个输入与其权重的乘积并累加。最后,加上偏置项并应用激活函数。这种实现方式虽然在大规模网络中可能不如矩阵运算高效,但在微控制器的资源限制下是可行的。
层的组织结构
神经网络通过层的方式组织神经元,形成信息处理的层次结构。每一层包含多个神经元,这些神经元并行处理来自前一层的输入。网络的深度(层数)和每层的宽度(神经元数)共同决定了网络的表达能力。
输入层是网络的第一层,直接接收原始数据。在AI-ANNE的实现中,输入层的每个神经元对应输入数据的一个特征。例如,在处理传感器数据时,每个传感器读数对应输入层的一个神经元。
隐藏层位于输入层和输出层之间,负责提取和学习数据的抽象特征。隐藏层的数量和每层神经元的数量是网络架构设计的关键参数。深度网络(多个隐藏层)能够学习更复杂的特征层次,但也需要更多的计算资源。
输出层产生最终的预测结果。对于二分类问题,输出层通常只有一个神经元,输出一个介于0和1之间的概率值。对于多分类问题,输出层的神经元数量等于类别数,每个神经元输出对应类别的概率。
全连接层的密度概念
在全连接(密集)层中,当前层的每个神经元都与前一层的所有神经元相连接。这种连接模式的数学表示可以用矩阵乘法来高效实现:
其中,是输入向量,是权重矩阵,是偏置向量,是逐元素应用的激活函数,是输出向量。
权重矩阵的维度为,其中是输入层的神经元数量,是当前层的神经元数量。这意味着一个密集层需要存储个权重参数加上个偏置参数。
激活函数的深入分析
激活函数是神经网络中引入非线性的关键组件,使网络能够学习和表示复杂的非线性关系。不同的激活函数具有不同的数学特性和应用场景。
Sigmoid函数
Sigmoid函数将任意实数映射到区间:
Sigmoid函数的导数具有优美的形式:
这个特性在反向传播算法中非常有用。然而,Sigmoid函数存在梯度消失问题:当输入值很大或很小时,梯度接近于零,导致深层网络训练困难。
ReLU函数族
标准ReLU(Rectified Linear Unit):
ReLU的导数:
Leaky ReLU解决了ReLU的"死亡神经元"问题:
其中是一个小的正数(通常为0.01或0.1)。Leaky ReLU的导数:
Tanh函数
双曲正切函数输出范围为:
Tanh函数的导数:
Softmax函数
Softmax函数用于多分类问题的输出层,将实数向量转换为概率分布:
为了数值稳定性,实际实现中通常使用:
IRIS数据集上的实验验证
数据集描述与问题定义
IRIS数据集包含150个鸢尾花样本,每个样本具有四个连续型特征:萼片长度(sepal length)、萼片宽度(sepal width)、花瓣长度(petal length)和花瓣宽度(petal width),所有测量单位为厘米。数据集包含三个类别,每类50个样本:Iris-setosa、Iris-versicolor和Iris-virginica。
在本研究中,我们专注于区分Versicolor和Virginica两个类别的二分类问题。这两个类别在特征空间中有部分重叠,使得分类任务具有一定挑战性,适合用于验证神经网络的性能。
实验一:8神经元网络架构
第一个实验网络包含8个神经元,分布在4层中:
- 输入层:2个神经元
- 第一隐藏层:3个神经元
- 第二隐藏层:2个神经元
- 输出层:1个神经元
网络的前向传播过程可以表示为:
其中,,,,。
这个网络达到了90%的准确率,混淆矩阵显示模型在某些边界案例上存在分类困难。
实验二:6神经元网络架构
第二个实验采用更简单的网络结构,包含6个神经元,分布在3层中:
- 输入层:3个神经元
- 隐藏层:2个神经元
- 输出层:1个神经元
前向传播过程:
令人意外的是,这个更简单的网络达到了95%的准确率。混淆矩阵显示:
- 真阳性(TP):9个样本
- 真阴性(TN):10个样本
- 假阳性(FP):0个样本
- 假阴性(FN):1个样本
这表明对于这个特定问题,简单的网络架构可能更适合,避免了过拟合。
性能评估指标
混淆矩阵分析
混淆矩阵提供了分类性能的详细视图。对于二分类问题,混淆矩阵是一个的表格:
基于混淆矩阵,可以计算多个性能指标:
准确率(Accuracy):
精确率(Precision):
召回率(Recall):
F1分数:
MicroPython实现细节
矩阵运算的底层实现
由于MicroPython没有NumPy等科学计算库,需要从零实现基本的矩阵运算。矩阵转置函数的实现展示了这种方法:
def transpose(M):
if not isinstance(M[0], list):
M = [M]
rows = len(M)
cols = len(M[0])
MT = zeros(cols, rows)
for i in range(rows):
for j in range(cols):
MT[j][i] = M[i][j]
return MT
这种逐元素的操作虽然不如优化的BLAS库高效,但在微控制器的小规模网络中是可行的。
神经元的完整实现
单个神经元的计算涉及多个步骤:加权求和、添加偏置和应用激活函数。MicroPython实现必须处理不同的激活函数类型:
def neuron(x, w, b, activation):
tmp = zero_dim(x[0])
for i in range(len(x)):
tmp = add_dim(tmp, [(float(w[i]) * float(x[i][j]))
for j in range(len(x[0]))])
if activation == "sigmoid":
yp = sigmoid([tmp[i] + b for i in range(len(tmp))])
elif activation == "relu":
yp = relu([tmp[i] + b for i in range(len(tmp))])
# ... 其他激活函数
return yp
与现有方法的比较
AIfES框架
Fraunhofer开发的AIfES(Artificial Intelligence for Embedded Systems)是一个灵活的软件框架,专门设计用于在微控制器等小型低功耗设备上运行深度学习模型。AIfES可以直接在设备上构建、训练和运行模型,无需强大的外部系统。用户可以通过选择不同的模型组件(如层类型或数据处理方式)来定制框架。
AI-ANNE的独特优势
相比AIfES,AI-ANNE具有以下特点:
- 教育透明性:完全开放的MicroPython源代码,便于理解神经网络的内部工作原理
- 灵活性:可以轻松修改激活函数、调整网络架构,甚至在微控制器上进行微调
- 轻量级:最小化的依赖和内存占用,适合资源极度受限的环境
- 可扩展性:用户可以根据需要添加新的激活函数或网络组件
实际应用场景
状态监测与预测性维护
在工业环境中,AI-ANNE可以部署在传感器节点上,实时监测设备状态。通过分析振动、温度、压力等传感器数据,神经网络可以检测异常模式,预测潜在故障,实现预测性维护。
医疗诊断辅助
在医疗设备中,特别是便携式诊断设备,AI-ANNE可以实现实时的信号处理和模式识别。例如,在心电图(ECG)监测中,神经网络可以识别异常心律模式。
智能农业
在精准农业应用中,部署在田间的微控制器可以分析土壤湿度、温度、光照等数据,通过神经网络模型预测作物生长状态和灌溉需求。
未来发展方向
AI-ANNE框架的未来发展可以从多个方向展开:
- 模型压缩技术:研究量化、剪枝等技术,进一步减少模型大小和计算需求
- 在线学习能力:开发增量学习算法,使模型能够在部署后继续适应新数据
- 硬件加速:利用微控制器的特殊硬件功能,如DSP指令,加速神经网络计算
- 自动化工具:开发自动将TensorFlow/Keras模型转换为AI-ANNE格式的工具
结论
本研究成功展示了如何将神经网络迁移到资源受限的微控制器上。通过AI-ANNE框架,我们证明了即使在Raspberry Pi Pico这样的低成本微控制器上,也能运行有效的神经网络模型。实验结果表明,经过精心设计的小型网络可以达到与大型网络相当的性能,同时显著降低资源消耗。
附录:数学推导
附录A:反向传播算法
虽然AI-ANNE主要用于推理而非训练,理解反向传播算法对于理解预训练权重的来源至关重要。
损失函数
对于二分类问题,使用二元交叉熵损失函数:
其中是样本数量,是真实标签,是预测概率。
梯度计算
对于输出层权重的梯度:
定义误差项,则:
对于隐藏层的误差项,使用链式法则:
权重更新规则
使用梯度下降法更新权重:
其中是学习率。
附录B:激活函数的数值稳定性分析
Sigmoid函数的数值问题
当很大时,可能导致数值溢出或下溢。改进的实现:
Softmax的数值稳定实现
标准Softmax在输入值很大时会溢出。稳定版本:
其中。证明这与原始定义等价:
附录C:矩阵运算的计算复杂度分析
前向传播的复杂度
对于一个全连接层,输入维度为,输出维度为:
- 矩阵乘法:次乘法和次加法
- 偏置加法:次加法
- 激活函数:次函数调用
总复杂度:
内存需求分析
对于层网络,第层有个神经元:
- 权重存储:个浮点数
- 偏置存储:个浮点数
- 激活值缓存:个浮点数(可以重用)
对于8神经元网络:
- 权重:个参数
- 偏置:个参数
- 总计:30个参数
附录D:梯度消失和梯度爆炸问题
Sigmoid函数的梯度消失
Sigmoid函数的导数最大值为0.25(当时):
在深层网络中,梯度通过多层反向传播时会连续相乘:
当很大时,梯度趋近于零。
ReLU的优势
ReLU的导数在正区间恒为1:
这避免了梯度消失问题,但可能导致"死亡ReLU"现象。
附录E:信息论视角下的激活函数
熵与信息增益
Sigmoid函数输出的熵:
其中。熵最大值出现在(即)时。
Softmax与最大熵原理
Softmax函数是在约束条件和下,最大化熵的解。
使用拉格朗日乘数法:
求导并令其为零:
解得,归一化后即得Softmax形式。
附录F:微控制器上的定点数实现
虽然本文使用浮点数,但在某些微控制器上,定点数运算可能更高效。
定点数表示
使用Q格式,例如Q15.16表示16位整数部分和16位小数部分:
定点数乘法
两个Q15.16数相乘:
定点数激活函数
Sigmoid函数的查找表实现:
- 预计算区间内的Sigmoid值
- 量化到256个值
- 使用线性插值提高精度
这种方法可以将Sigmoid计算时间从几百个时钟周期减少到几十个。
- 点赞
- 收藏
- 关注作者
评论(0)