news 2026/10/26 13:31:13

嵌入式转端侧AI:从CNN部署到MCU落地全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式转端侧AI:从CNN部署到MCU落地全攻略

在嵌入式这行干了五年之后,我终于对自己承认了一件事:接下来三年再不碰AI,可能就要被行业落下了。车载、安防、工业控制、可穿戴设备,客户的需求从"能跑就行"变成了"要带端侧智能",而这个转变最直接的信号就是——招聘JD上开始写"熟悉CNN部署"这种以前只有算法工程师才看的词。

我决定重新从CNN开始,不是跟风,而是被实际项目逼的。嵌入式从业者的底子在这里,C语言、寄存器、总线协议、内存管理,这些经验在端侧AI时代不但没过时,反而是把模型塞进MCU和SoC的核心能力。这篇文章就把我最近几个月的转型过程和实操笔记整理出来,包括为什么从CNN切入、怎么理解卷积神经网络、怎么把模型从PyTorch一路跑到板子上,以及中间踩过的各种坑。如果你是嵌入式转端侧AI、或者想搞懂CNN到底怎么落地到硬件的人,这篇应该能帮你少走不少弯路。

1. 为什么从嵌入式转向端侧 AI

1.1 端侧AI对嵌入式工程师意味着什么

端侧AI,就是让AI模型直接在设备本地完成推理,而不是把数据传上云端再等结果回来。摄像头本地做目标检测、手表上跑动作识别、工厂设备本地做异常声音判断,这些都是典型场景。它解决的问题很明确:低延迟、断网可用、数据不出本地。而"嵌入式"在这里不再是底层驱动和外设控制的代名词,它变成了AI模型的最终宿主。

在端侧AI的链路里,嵌入式工程师干的事情,其实就是给AI模型找一个能落地的家。模型在服务器上训练完,那只是第一步,后面的转换、量化、算子映射、内存排布、编译优化,每一步都落在嵌入式的老本行上。也正是因为这样,嵌入式转AI的门槛,并没有想象中那么高:你不需要变成数学家,但你需要知道模型的张量长什么样、卷积在哪一层占了多少算力、模型权重放在Flash还是RAM里——这些全是嵌入式思路能直接迁移过来的东西。

1.2 最容易踩的误区:一上来就想搞大模型

我调研了一圈,发现很多嵌入式同行转AI的第一反应是"直接上Transformer""研究大模型微调",或者"能不能直接用ChatGPT那套API"。这些方向当然有价值,但从落地端侧的这个目标来看,它们是错的。

端侧设备,尤其是MCU级别,Flash和RAM往往只有几百KB到几MB。一个Transformer的参数量动辄几百万甚至上亿,完全放不进MCU。而CNN(卷积神经网络)经过几十年的发展,模型量级从几十KB到几MB都有,配合量化之后,在Cortex-M系列上跑都是成熟方案。更重要的是,CNN的卷积操作和池化操作都有非常成熟的硬件加速方案,NPU、DSP、甚至SIMD指令集都优先支持它。

所以我选择重新从CNN开始,核心原因就两个字:能落地。就算你最终的目标是搞更复杂的模型,CNN打底也完全不吃亏,因为部署链路里所有的坑——量化掉精度、算子不支持、内存碎片化——你在CNN上踩一遍,以后处理其他模型就是翻版。

1.3 端侧AI的交付物到底是什么

大部分嵌入式工程师第一次接触"端侧AI"这个概念时,会下意识以为要像算法工程师一样调loss、写网络结构。其实一个典型的端侧AI项目,交付物通常就三样:

  • 一个能跑的推理程序:输入是传感器/图像/音频数据,输出是类别、坐标或置信度。
  • 一套离线转换脚本:把训练好的模型转换成嵌入式推理框架能吃的格式(如ONNX、TFLite、NCNN)。
  • 一份性能报告:在目标板子上的推理时延、RAM峰值、Flash占用、精度损失数据。

这三样东西,没有一样是纯算法的工作。嵌入式工程师最擅长的就是"让程序在一个资源受限的硬件上稳定高效地跑起来",这恰恰是端侧AI落地时最稀缺的技能。所以别觉得自己学CNN是在跨行,本质上你还是在做嵌入式,只是把"裸机程序"换成了"AI推理程序"。

2. 为什么从 CNN 开始,而不是直接上 Transformer

2.1 CNN 的硬件亲和力极强

CNN的核心操作就三种:卷积(Convolution)、池化(Pooling)、全连接(Fully Connected,或者用全局平均池化替代)。卷积本质上是乘加运算的密集重复,池化是窗口内取最大值或平均值,全连接是矩阵乘法。这些运算在单片机、DSP、FPGA上都有高度优化的实现。现在的MCU厂商,比如ST、NXP、瑞萨,都在推自己的AI库,底层支持的大概率也是CNN算子。

而Transformer里最主要的Self-Attention操作,矩阵规模大、访存模式不规则,在MCU级别的硬件上几乎没办法做极致优化。你可以理解为:CNN是"流水线作业",数据是一块一块流过各个处理单元,硬件设计好流水就能高效跑;而Attention是"随机查表",数据之间的依赖关系太复杂,在小内存设备上非常容易卡住。

2.2 学习成本低、问题容易定位

CNN的训练和调参也比Transformer友好得多。一个简单的CNN分类模型,用PyTorch可能只需要上百行代码,在普通CPU上几分钟就能训练一个入门模型出来。而Transformer的训练动不动就需要GPU、分布式、学习率调度策略,对刚转行的嵌入式工程师来说,调试成本不是一个量级的。

更重要的是,CNN的问题更容易定位。训练不收敛、过拟合、梯度消失,这些在CNN上都有相对成熟的排查套路。而且部署时如果某个算子跑不起来,CNN的算子种类就几个,翻一下算子支持列表就能找到替代方案;Transformer模型里算子类型多、自定义算子也多,嵌入式推理引擎根本来不及全部支持。

2.3 一张表看懂 CNN 和 Transformer 在端侧上的差异

对比项CNNTransformer
典型参数量几十KB ~ 几MB几MB ~ 几百MB
核心算子Conv、Pool、FCMatMul、Softmax、LayerNorm
MCU部署难度成熟方案多,甚至能跑INT8量化极难,基本不现实
NPU支持力度极强,几乎所有NPU都优先适配NPU支持零散,各厂家差异大
调试门槛相对低,可解释性强高,模型行为不容易分析
典型模型MobileNet、LeNet、ResNetViT、BERT、GPT系列

所以结论很清晰:在端侧AI这个赛道上,CNN不是"过时的技术",反而是目前工程落地的主力。Transformer当然在云侧很厉害,但端侧不是它发挥的主场。先把CNN用得炉火纯青,之后再去看NPU怎么加速Attention、怎么部署大模型,那是进阶的事情,不是起步的事情。

3. CNN 核心概念速成:写给嵌入式工程师的版本

3.1 卷积到底在算什么

我见过很多嵌入式工程师第一次看CNN时,被"卷积"这个词吓住。其实完全不用。卷积做的事情,简单来说就是一个窗口在输入数据上滑动,窗口里的数据和一个"滤波器"逐元素相乘再求和。这个滤波器就是卷积核(Kernel),它里面存的是一堆数字,这些数字是训练过程中学出来的参数。

举个最直观的例子:一张32×32的灰度图,等价于一个32×32×1的二维数组;如果用10个3×3的卷积核去卷积它,输出就是30×30×10的三维数组(尺寸变小的原因是没有做padding)。每个卷积核就相当于一个"特征探测器",有的核学会了检测边缘,有的核学会了检测纹理,有的核学会了检测特定的形状。层数越深,检测到的特征越抽象。

在嵌入式工程师的视角里,卷积运算的本质就是一个"滑窗乘加循环"。你在C语言里写过滑动平均滤波、写过FIR滤波器,那你就已经具备理解卷积的硬件直觉了:

// 伪代码:一个最朴素的3x3卷积 for (int c_out = 0; c_out < C_OUT; c_out++) { for (int y = 0; y < H_OUT; y++) { for (int x = 0; x < W_OUT; x++) { float sum = 0.0f; for (int c_in = 0; c_in < C_IN; c_in++) { for (int ky = 0; ky < 3; ky++) { for (int kx = 0; kx < 3; kx++) { sum += input[c_in][y+ky][x+kx] * kernel[c_out][c_in][ky][kx]; } } } output[c_out][y][x] = sum + bias[c_out]; } } }

你可以把它理解为:我们在输入图像上不断滑动一个小窗口,每次窗口停下来,就把窗口内的像素值和卷积核做点积,得到的数填到输出特征图对应的位置。

3.2 池化和全连接各自管什么

池化层做的是"降采样"。最大池化的意思就是在窗口里取最大值,平均池化就是在窗口里取平均值。它一方面缩小了特征图的尺寸,减少了后续计算量,另一方面也提供了一定的平移不变性——目标稍微动几个像素,池化结果基本不变。嵌入式工程师可以类比为"降低采样率但仍然保留主要信息",和你在做传感器数据压缩时的思路一模一样。

全连接层则是把特征图展平成一维向量,然后经过矩阵乘法映射到类别得分。现在许多轻量级网络(比如MobileNet)用全局平均池化替代全连接,就是把整个特征图每个通道的值全部平均成一个数,再直接接分类层。这种方式参数更少,过拟合风险更低,更重要的是部署到MCU上能省一大片Flash。

3.3 感受野和参数量计算

感受野就是输出特征图上每个像素对应回输入图像上多大的区域。3×3卷积的感受野是3×3,再来一个3×3卷积,感受野就变成5×5。感受野越大,说明网络能看到输入图像的范围越大,提取特征时上下文信息越多。

参数量计算也很有用,这直接影响你评估模型能不能塞进Flash。一个卷积层的参数量公式是:

参数量 = (K_h × K_w × C_in + 1) × C_out

其中K_h和K_w是卷积核高宽,C_in是输入通道数,C_out是输出通道数,+1是偏置。举个例子:3×3卷积、输入16通道、输出32通道,参数量就是(3×3×16+1)×32 = 4640,约4.6K。模型一共多少层,加起来乘以2(权重的存储一般用INT8或FP16,按你实际使用的格式算字节)就能估算Flash。这套计算能力在嵌入式项目里非常实用,因为你在选型MCU时就要判断Flash和RAM够不够放模型。

4. 实操过程:从零写一个CNN并跑通训练

4.1 环境准备

我本人是纯嵌入式背景转过来的,所以选择了最容易上手的路径:直接用PyTorch,跑在CPU上。不需要GPU也能学明白CNN训练是怎么回事。环境就三样:

  • Python 3.9+,建议直接用Anaconda管理虚拟环境
  • PyTorch CPU版本:pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
  • 一个Jupyter Notebook或者VS Code + Python插件

我的建议是不要一上来就配CUDA、GPU环境。嵌入式学习阶段,一张256×256的灰度图数据集,在CPU上完全够用。GPU除了把训练速度加快几十倍之外,对理解CNN的训练过程没有任何帮助——你连循环里每步在干什么都还没搞清楚,跑那么快反而学不到东西。

4.2 数据准备:用MNIST当"嵌入式板卡"

学CNN最经典的数据集是MNIST,手写数字识别,10类,28×28灰度图。为什么选它?因为这个数据集足够小,整个训练集6万张图,放在任何一台电脑上都能秒载;同时它的结构非常完整——单通道输入、多分类输出、有标准的训练集和测试集划分,和嵌入式项目里"传感器输入→决策输出"的模型完全是一个套路。

import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_set = datasets.MNIST(root='./data', train=True, download=True, transform=transform) test_set = datasets.MNIST(root='./data', train=False, download=True, transform=transform) train_loader = DataLoader(train_set, batch_size=64, shuffle=True) test_loader = DataLoader(test_set, batch_size=256, shuffle=False)

ToTensor()是把PIL图像变成PyTorch张量,值域从0~255缩放到0~1。Normalize((0.1307,), (0.3081,))里的两个数分别是MNIST数据集的全局均值和标准差,把数据标准化到均值为0、方差为1的分布,可以让训练过程更稳定。这两个数值是MNIST官方推荐的固定值,不需要自己算。

4.3 构建网络结构

我选了LeNet-5的简化版本,就是最早用于手写数字识别的经典网络结构。它不是最强的,但它是最好的"教学板"。它的结构就像一条流水线:卷积提取特征→池化压缩尺寸→再卷积再池化→展平→全连接分类。

class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.features = nn.Sequential( nn.Conv2d(1, 32, kernel_size=3, padding=1), # 28x28 -> 28x28 nn.ReLU(), nn.MaxPool2d(2), # 28x28 -> 14x14 nn.Conv2d(32, 64, kernel_size=3, padding=1), # 14x14 -> 14x14 nn.ReLU(), nn.MaxPool2d(2) # 14x14 -> 7x7 ) self.classifier = nn.Sequential( nn.Flatten(), nn.Linear(64 * 7 * 7, 128), nn.ReLU(), nn.Linear(128, 10) ) def forward(self, x): x = self.features(x) x = self.classifier(x) return x

nn.Conv2d(1, 32, kernel_size=3, padding=1)的关键参数,对于嵌入式工程师来说要拆开看:输入通道1(灰度图)、输出通道32(用32个不同的卷积核去提取特征)、kernel_size=3(卷积核是3×3)、padding=1(边缘填充一圈0,让输出尺寸和输入保持一致)。如果不padding,28×28的图做3×3卷积后变成26×26,尺寸会逐层缩小,不方便设计网络层数。

nn.MaxPool2d(2)是2×2的最大池化,把14×14直接减半到7×7。你可以把这一步理解为"降维但不丢主要信息"——每2×2的区域只保留最大值,等于告诉你只要保留局部最强烈的响应。对硬件来说,这一层没有需要学习的参数,只做纯计算,部署时非常省事。

4.4 训练主循环:嵌入式工程师眼里的"状态机"

训练过程其实就是一个在数据集上反复迭代的状态机,分四步:前向传播算损失→反向传播算梯度→更新权重→回读指标。用嵌入式的话说:这就像你在调一个PID环,每次读传感器、算误差、更新控制量,然后看输出。

model = SimpleCNN() criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) def train_one_epoch(): model.train() total_loss = 0.0 correct = 0 total = 0 for images, labels in train_loader: optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() total_loss += loss.item() _, predicted = torch.max(outputs, 1) total += labels.size(0) correct += (predicted == labels).sum().item() return total_loss / len(train_loader), 100.0 * correct / total for epoch in range(5): loss, acc = train_one_epoch() print(f"Epoch {epoch+1}, Loss: {loss:.4f}, Accuracy: {acc:.2f}%")

这里有个细节一定要讲透:loss.backward()的机制,其实就是在链式求导法则下把最终的误差信号逐层往前传。以电子工程师的视角,你可以把它想象成"误差电流"反向流过每一层电路,每经过一层就根据局部电阻(梯度)算出修正量,然后optimizer.step()相当于"根据修正量调节权重电阻的阻值"。训练就是反复进行这个过程,直到模型在训练集上的损失降下来。

交叉熵损失CrossEntropyLoss()对分类任务来说是最常用的损失函数。它的底层逻辑是:把网络输出的10个得分变成概率分布(softmax),再计算预测分布和真实标签的"距离"(交叉熵)。预测得越离谱,损失越大;预测越接近真实,损失越小。

我自己在CPU上跑了5个epoch,一个epoch大概30秒,最终测试集准确率大约97.5%。这个数字已经足以说明模型学会做分类了。之后你再换更复杂的网络架构,比如ResNet和MobileNet,训练流程完全是同一个模板,变的只是网络内部的结构定义。这也是为什么我建议先跑通手写CNN再说部署——训练流程是通用的,不通用的是网络结构。

5. 把模型搬到设备上:部署的关键路径

5.1 导出和格式转换

模型训练完之后,想要部署到嵌入式设备上,第一步必须摆脱PyTorch运行时。最主流的方式是先把模型导出成ONNX(开放神经网络交换格式),然后让部署框架去消费ONNX文件。

dummy_input = torch.randn(1, 1, 28, 28) torch.onnx.export( model, dummy_input, "mnist_cnn.onnx", input_names=["input"], output_names=["output"], opset_version=11 )

ONNX在这里起的作用,可以理解为"模型的通用编译中间表示",就像嵌入式开发里你把C代码编译成目标文件再链接。PyTorch训练好的网络结构是Python对象,不导出ONNX的话,部署端完全没法和它对接。dummy_input就是给模型一个假输入,让它按照这张假图的张量形状走一遍计算图,以确定每一层的输入输出尺寸。这个输入张量的尺寸必须和部署时的实际输入完全一致,否则后面转换和部署必然报错。

要注意的是,你训练时模型是用FP32精度跑的,导出到ONNX之后默认也是FP32。对于Cortex-M级别的MCU,FP32权重和中间特征图的存储开销是非常大的,接下来就要做量化。

5.2 量化:从FP32到INT8

量化就是把模型里的浮点数(FP32)用整数(INT8)替代。FP32占4字节,INT8占1字节,权重和特征图直接缩小到原来的1/4,内存占用大幅下降。运算方面,浮点乘加换成整数乘加,在DSP和NPU上能获得数倍速度提升。

量化又分两种:训练后量化(PTQ)和量化感知训练(QAT)。PTQ最简单:把训练好的模型跑一遍校准数据,统计每一层激活值的分布范围,然后把浮点scale映射到整数。QAT则要在训练过程中就让模型"适应"整数量化带来的误差,精度通常比PTQ更高,但需要修改训练代码。

我不建议新手一上来就搞QAT。先用PTQ跑通流程,看精度损失多少。如果精度损失小于1~2%,直接用PTQ就行;小于5%,也还能接受;超过5%,再考虑QAT或者调整模型结构。

# 以PyTorch的量化工具为例做PTQ model_fp32 = SimpleCNN().eval() # 加载训练好的权重... model_fp32.qconfig = torch.ao.quantization.get_default_qconfig('qnnpack') model_fp32_prepared = torch.ao.quantization.prepare(model_fp32) # 用200张训练图片做校准 for _ in range(5): for images, _ in train_loader: model_fp32_prepared(images) model_int8 = torch.ao.quantization.convert(model_fp32_prepared)

PTQ校准的本质,是通过让模型正常推理一批数据,收集每一层的真实激活值分布,然后为每个张量找到最合适的scale和zero_point。校准数据最好和真实部署数据分布一致,数量不用太多,几百张足够,但一定要有代表性,不然有些层没被充分激活,量化系数就是错的,精度会掉得非常诡异。

5.3 端侧推理引擎与工具链的选型

模型量化好了,接下来要选一个能跑在目标硬件上的推理引擎。嵌入式工具链目前没有统一标准,不同的芯片有不同的最佳选择。

框架/工具目标平台特点
TFLite Micro通用MCU(ARM Cortex-M)谷歌生态,算子相对保守,稳定性好
STM32Cube.AISTM32全系从Keras/TFLite/ONNX自动转换,生成的C代码可读性强
TensorRTNVIDIA Jetson对NVIDIA GPU做了极致优化,适合高性能端侧
NCNN手机/ARM平台腾讯开源,轻量高效,对ARM处理器优化好
RKNN瑞芯微NPU针对RK3588等瑞芯微芯片NPU优化
自研C代码任意MCU模型够小时,手写卷积推理代码反而最可控

我自己把整套转换流程在PC上做过模拟,模型参数量大约6.2万个,经过量化之后权重占62KB左右,中间特征图峰值大约在十几KB,综合看下来,一块Cortex-M4、64KB RAM的MCU是能跑起来的,但已经是极限了。如果换成128KB RAM的MCU就跑得比较舒服。这种预算估算必须在项目立项阶段就做,等到开发板买回来才发现Flash不够,那才叫痛苦。

5.4 部署时的内存规划和算子映射

嵌入式部署的最终形态,是一个C语言项目。推理引擎会先把模型编译成C代码或二进制权重,然后在板子上执行。这里有一个嵌入式工程师最容易忽略的问题:推理引擎的内存分配策略和裸机开发的内存规划完全不同。

裸机开发时你会把变量放全局区、堆区、栈区,思路是人为主观控制的。推理引擎则偏向一次性申请大块内存做内存池,然后从池里分配每一层的输入输出Tensor,这样可以减少内存碎片,也方便给加速器做对齐访问。这个过程和你平时写程序完全不同,你在移植某个推理引擎时,第一个要研究的就是它的内存池策略。

算子映射方面,CNN的卷积、池化、全连接这些算子,推理引擎里通常都有优化过的实现。比如TFLite Micro会用CMSIS-NN把卷积里的乘加循环直接用SIMD指令加速,在Cortex-M上能比纯C实现快4~10倍。拿到一个新平台,第零件事就应该跑一遍官方的算子基准测试,别等到整个模型跑起来才发现核心算子慢得离谱。

6. 常见问题与排查思路

6.1 训练精度高,部署精度崩了

这是最典型的问题,99%的原因是量化校准出了问题。训练时是FP32精度,量化成INT8后,每一层的计算误差累积起来,到了输出层就被放大了。排查思路如下:

  • 先确认校准集的分布和真实部署场景一致。你用白天光照下的图片做校准,晚上部署到暗光环境精度必掉。
  • 再检查是否有某些层有极端值。比如某一层有个别很大的激活值,导致量化scale被拉得很大,其他正常值的精度就被牺牲了。这种情况可以尝试按per-channel量化,或者手动裁剪掉极端值。
  • 最后再考虑QAT。如果PTQ怎么调都回不到预期精度,那说明模型本身对量化敏感度较高,需要把量化误差纳入训练过程里一起优化。

绝不要想当然地把精度下降归咎于"模型不够好"。在端侧AI项目中,部署精度的问题超过一半是部署环节的问题,不是训练环节的问题。

6.2 Flash和RAM不够用

模型大小、中间特征图大小、代码段大小,三块加起来就是Flash和RAM的总需求。排查思路:

  • 把模型参数量算清楚,乘以量化字节数,先看权重占多少Flash。
  • 把中间特征图峰值算清楚。CNN的中间特征图峰值一般出现在第一层卷积之后,因为这时通道数可能已经变多,但分辨率还没降下来。
  • 把推理引擎本身的代码段算上。有些框架支持裁剪掉不用的算子,只保留当前模型需要的算子,能省不少Flash。

我之前在一个项目里,模型权重只占40KB,但推理引擎框架代码占了60KB,MCU的256KB Flash直接告急。这个问题发现晚了就非常难受,因为已经选型定板,只能在代码上做减法。

6.3 算子不支持或者编译报错

不同推理引擎支持的算子集合不一样,特别是你用了比较新的激活函数或者自定义算子,很可能在转换阶段直接报错。比如某些框架不支持LeakyReLU,只支持标准ReLU;有些框架对Flatten层的导出格式非常挑剔。

排查办法:

  • 把模型结构简化到只用Conv、ReLU、MaxPool、Flatten、Dense这几个最基础的算子。
  • 实在需要特殊算子,就用等效的普通算子组合去替换。比如LeakyReLU在推理时可以用两条ReLU分支拼出来,代价是代码复杂一点。
  • 在导出ONNX之前,先查一下目标推理引擎的支持算子列表,对着列表设计网络。这句话值得刻在电脑屏幕上。

6.4 推理延迟超出预期

同样的模型在PC上跑可能只要0.5毫秒,到了MCU上跑了50毫秒甚至100毫秒,这很正常。MCU的主频、内存带宽、是否支持SIMD指令,全部会影响推理速度。如果延迟超标:

  • 先做算子级性能剖析,不要只看整体延迟。TFLite Micro和CMSIS-NN都有官方的基准测试代码,先确认每个算子单独跑耗时多少。
  • 如果卷积算子慢,优先看是否量化成了INT8。FP32的卷积在MCU上慢到不可接受。
  • 如果已经是INT8还是慢,尝试调整内存对齐和缓冲区的内存分配策略,有时只是访问不对齐导致性能骤降。

排查延迟问题的时候,记得把编译器优化等级开到-O2或-Ofast,开不开优化,性能差距可能有两三倍,这是最容易被忽略的一个点。

7. 写在最后的两个小建议

第一个建议:嵌入式转端侧AI,不要想着"我先学完所有理论再动手"。CNN的理论概念再多,真正让你能理解它的是把它跑起来、部署到板子上的这一次闭环过程。我自己就是先从MNIST这个玩具级的网络开始,跑通训练、导出ONNX、量化、再模拟部署到嵌入式环境,整个过程大概花了两周。这一个闭环走完之后,后面去看MobileNet、YOLO这些真正能产出的模型,上手速度快到连自己都意外。

第二个建议:一定要保留嵌入式工程师的硬件直觉。端侧AI比云侧AI更需要人懂硬件——内存、算力、带宽、功耗,刀刀见血。你不需要成为大模型专家,但要成为一个能把模型准确塞进硬件里的人。这两种能力放在市场上,是真正稀缺的组合。我从CNN重新开始,不是为了追赶风口,而是为了把十年前就练好的底层功底,用一个新的方式重新用起来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 13:29:36

YOLOv8自定义数据集制作:从类别设计、标注转换到划分体检

项目跑通官方示例之后&#xff0c;真正卡住绝大多数人的一步从来不是改模型结构&#xff0c;而是把自己的业务数据变成模型能吃的格式。我见过太多这样的情况&#xff1a;拿现成公开数据训练&#xff0c;指标漂亮得像模像样&#xff0c;一换到自己的摄像头画面&#xff0c;mAP …

作者头像 李华
网站建设 2026/10/26 13:29:36

GPT-6.1 Sol 25项更新解析:从API到成本优化的开发者指南

OpenAI这次没有搞预告&#xff0c;直接在凌晨把GPT-6.1 Sol推进了生产环境。我早上泡咖啡的时候刷到推送&#xff0c;手一抖差点把水洒在键盘上——倒不是被“新模型”三个字吓到&#xff0c;而是快&#xff0c;太快了。距离上一轮能力更新还没缓过神&#xff0c;25项更新已经整…

作者头像 李华
网站建设 2026/10/26 13:27:53

小模型训练中的注意力“保险丝”:QK-norm、softcap与退火方案详解

上个月我在训一个 0.5B 的小模型&#xff0c;大概跑到 20B token 的时候&#xff0c;loss 开始规律性地出现尖峰。查了一圈&#xff0c;不是数据问题也不是学习率问题&#xff0c;最后把 attention 里的 logits 打出来看了一眼&#xff0c;一个 head 的注意力分数直接冲到了四位…

作者头像 李华
网站建设 2026/10/26 13:27:52

Gemma 4:轻量级多模态AI模型的技术解析与应用实践

1. Gemma 4&#xff1a;口袋里的AI革命 Google最新发布的Gemma 4模型正在重新定义个人AI助手的边界。这个仅有20亿参数的开源模型在Apache 2.0许可下释放了惊人的多模态能力——它能理解并生成文本、图像、代码&#xff0c;甚至处理简单的视频内容。就像把哆啦A梦的百宝袋装进了…

作者头像 李华
网站建设 2026/10/26 13:26:34

AI Agent开发课程怎么选?避坑指南与学习路线

先交代背景&#xff1a;我自己是从传统后端转过来学 AI Agent 开发的&#xff0c;前后折腾了差不多 8 个月&#xff0c;花过冤枉钱报过班&#xff0c;也白嫖过不少优质资源&#xff0c;最后才慢慢把 Agent 这条线捋清楚。这篇帖子不吹不黑&#xff0c;只讲真实感受&#xff0c;…

作者头像 李华
网站建设 2026/10/26 13:25:30

自动驾驶决策算法选型与落地:从数据集构建到仿真实车验证

决策算法是自动驾驶的大脑&#xff0c;它决定了车辆在复杂交通环境中如何行动。这篇内容适合自动驾驶算法工程师、决策规划方向的从业者、以及刚入行想了解决策模块全貌的研究者。我会从方案选型、数据集构建、仿真与实车验证等几个维度&#xff0c;展开聊聊我在实际项目中对决…

作者头像 李华