使用 MATLAB 和 Simulink 的嵌入式 AI
从概念到生产,在任意嵌入式硬件上部署 AI。
为什么使用 MATLAB 和 Simulink 实现嵌入式 AI?
借助系统级仿真和自动代码生成,将训练好的 AI 模型部署到 MCU、GPU、FPGA 和 NPU 等资源受限的硬件上。
- 系统级仿真:在接入实际硬件之前,先测试 AI 与控制器、传感器和被控对象模型协同工作时的行为。
- 代码生成:直接从您的 Simulink 模型(包括 AI 组件)生成优化的 C/C++、CUDA 或 HDL 代码,无需手动迁移。
- 导入灵活性:导入 PyTorch、ONNX 或 TensorFlow 模型,并通过相同的管道进行部署。
- 全程验证。使用形式化方法、对抗稳健性测试以及软件在环 (SIL)、处理器在环 (PIL) 和硬件在环 (HIL) 测试,在每个阶段验证您的 AI 组件。
- 标准合规性:生成符合 MISRA C 并具有可追溯性的代码,以支持 DO-178C、ISO 26262 和 IEC 61508 认证。
端到端嵌入式 AI 工作流
数据
AI 模型
模型
AI 模型
Simulink
验证
本质上是迭代的:
此工作流并非严格线性的。根据项目的内存限制、延迟要求、目标硬件和标准合规需求,某些步骤可能会重复、重新排序或完全跳过。
训练/导入 AI 模型
从外部框架导入
% 从 PyTorch 导入(导出的程序格式) net = importNetworkFromPyTorch("exported_pytorch_model.pt2") net = dlnetwork with properties: Layers: [9×1 nnet.cnn.layer.Layer] Connections: [11×2 table] Learnables: [86×3 table] State: [42×3 table] InputNames: {'InputLayer1'} OutputNames: {'ResidualNetSmall:fc'} Initialized: 1
| 源 | 函数 |
|---|---|
| PyTorch (.pt2/.pt) | importNetworkFromPyTorch |
| ONNX | importNetworkFromONNX |
| TensorFlow 2 | importNetworkFromTensorFlow |
| Keras 3 | importNetworkFromKeras |
| XGBoost (.json) | importModelFromXGBoost |
压缩模型
%% 步骤 1:剪枝(例如,删除 60% 的可学习参数) netPruned = compressNetworkUsingTaylorPruning(net, dsTrain, "crossentropy", ... options, LearnablesReductionGoal=0.6); %% 步骤 2:投影(例如,保留 80% 的方差) npca = neuronPCA(netPruned, dsTrain); netProjected = compressNetworkUsingProjection(netPruned, npca, ... ExplainedVarianceGoal=0.8); netProjected = trainnet(data, netProjected, "crossentropy", optionsFT); %% 步骤 3:量化 (INT8) quantObj = dlquantizer(netProjected, ExecutionEnvironment="CPU"); calibrate(quantObj, dsCal); netQuantized = quantize(quantObj);
| 方法 | 模型大小的潜在缩减幅度 | 何时使用 |
|---|---|---|
| 剪枝 | 50–70% | 过度参数化的 CNN,具有冗余滤波器 |
| 投影 | 20–85% | 激活相关性强的全连接密集型网络或循环网络 |
| 量化 | 75%(4 倍) | 定点处理器的最终步骤 |
提示:
推荐顺序:剪枝 → 投影 → 量化(每步后进行微调)。使用 estimateNetworkMetrics(net) 在每步前后测量可学习参数、激活内存和 MAC 数。另请参阅 Deep Learning Toolbox 模型压缩库。
验证 AI 模型
在部署之前,使用 AI 验证库和 Deep Learning Toolbox 的 alpha-beta-CROWN 验证器接口来证明安全属性或评估稳健性。与对采样输入进行测试不同,形式化验证在连续输入区域上提供数学保证。
| 方法 | 功能说明 | 关键函数 |
|---|---|---|
| 稳健性验证 | 证明网络分类在有界输入区域内保持不变 | verifyNetworkRobustness |
| 形式化输出边界 | 针对有界输入区域,计算网络输出的保证上下界 | estimateNetworkOutputBounds |
| 对抗稳健性 | 查找在有界输入区域内导致误分类的对抗样本 | findAdversarialExamples |
| 分布外检测 | 标记与训练数据分布不同的输入,防止运行时出现静默失败 | networkDistributionDiscriminator |
第一个参量可以是 dlnetwork 对象(在 MATLAB 中训练或导入),也可以是模型文件路径:ONNX 文件 (.onnx) 或完整的 PyTorch 模型(使用 torch.save() 保存)。相同的函数,相同的语法。
% 证明分类对输入 X0 周围的传感器噪声具有稳健性 XLower = X0 - epsilon; XUpper = X0 + epsilon; [result, cex] = verifyNetworkRobustness(net, XLower, XUpper, trueLabel); % 计算输入区域上的保证输出边界 [YLower, YUpper] = estimateNetworkOutputBounds(net, XLower, XUpper); % 在有界区域内查找对抗样本 [adversarials, success] = findAdversarialExamples(net, XLower, XUpper, trueLabel);
集成在 Simulink 中
将 AI 模型嵌入到系统仿真中,以在生成代码之前验证其与控制器、传感器和被控对象模型的协作行为。
| 模块 | 代码 | 用例 |
|---|---|---|
| 联合执行 |
|
直接在 Simulink 中仿真 PyTorch、TensorFlow、ONNX 或自定义 Python 模型,无需转换;在完整集成之前评估第三方 AI 在更大系统中的表现 |
| 预测 |
|
将 dlnetwork 作为单个推断模块(分类或回归)运行 |
| PyTorch 导出程序 |
|
直接在 Simulink 中运行 PyTorch .pt2 模型,并支持 C/C++ 和 CUDA 代码生成 |
| 层模块 | exportNetworkToSimulink |
将网络导出为单独的 Simulink 模块,以便进行逐层定点控制和检查 |
部署和验证
生成无需 MATLAB 即可运行的独立源代码,然后在目标硬件上逐步验证。
代码生成
| 产品 | 输出 | 主要目标 | 目标库 |
|---|---|---|---|
| MATLAB Coder | C/C++ | ARM Cortex-A、x86、任何 POSIX/RTOS | 独立*、Intel oneDNN |
| Embedded Coder | 产品级 C/C++ | NXP、Infineon、STMicro、Renesas MCU 等 | 独立*、CMSIS、CMSIS-NN |
| GPU Coder | CUDA C++ | NVIDIA Jetson Thor、Orin、Xavier、TX2 | 独立*、TensorRT |
| Embedded Coder + HSP | 针对 NPU 的优化 C/C++ | Qualcomm Hexagon、Infineon PPU (AURIX TC4x) | 供应商 NPU 运行时 |
| HDL Coder | VHDL/Verilog | AMD (Xilinx) FPGA、Intel FPGA | Deep Learning HDL Toolbox IP |
*将目标深度学习库设置为 'none',以便为任何处理器生成不依赖第三方库的独立 ANSI/ISO C/C++ 代码。
入口函数模式
% 使用 MATLAB dlnetwork
function out = myPredict(in) %#codegen
persistent net
if isempty(net)
net = coder.loadDeepLearningNetwork('myNet.mat');
end
out = predict(net, in);
end
% 使用 PyTorch 模型 function out = myPredict(in) %#codegen persistent pytorchNet if isempty(pytorchNet) pytorchNet = loadPyTorchExportedProgram('myPyTorchNet.pt2'); end out = invoke(pytorchNet, in); end
配置和生成
% 为任何处理器生成 C++ cfg = coder.config('lib'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig('none'); codegen -config cfg myPredict -args {ones(224,224,3,'single')} % 为 NVIDIA Jetson 生成 CUDA gpuCfg = coder.gpuConfig('lib'); gpuCfg.DeepLearningConfig = coder.DeepLearningConfig('tensorrt'); codegen -config gpuCfg myPredict -args {ones(224,224,3,'single')}
| 目标库 | 硬件 |
|---|---|
'none' |
任何(无库) |
'mkldnn' |
x86-64 (Intel oneDNN) |
'cudnn' |
NVIDIA GPU |
'tensorrt' |
NVIDIA GPU/Jetson |
系统级验证 (MIL/SIL/PIL/HIL)
逐步验证:模型 (MIL) → 在主机上运行的生成代码 (SIL) → 在目标处理器上运行 (PIL) → 具有真实 I/O 的完整系统 (HIL)。
| 阶段 | 运行内容 | 位置 | 验证内容 |
|---|---|---|---|
| MIL(模型在环) | Simulink 模型(解释执行) | 主机 PC | 算法正确性:建立黄金参考 |
| SIL(软件在环) | 生成的 C/C++/CUDA 代码 | 主机 PC(编译后) | 行为正确性:在主机处理器上运行的生成代码的数值等效性 |
| PIL(处理器在环) | 生成的 C/C++/CUDA 代码 | 目标硬件 | 目标特定影响:编译器、FPU、在目标处理器上运行的生成代码的数值等效性 |
| HIL(硬件在环) | 具有真实 I/O 的完整系统 | 实时目标 | 实时影响:集成、时序和 I/O 行为 |
% 处理器在环验证 set_param("myModel/AI_Subsystem", "SimulationMode", "Processor-in-the-loop"); out = sim("myModel"); % 将 PIL 输出与 MIL 基线进行比较以检测数值漂移