陷阱二:BEV特征图尺寸与NPU内存对齐的“隐形墙”

好,咱们接着聊。上一章讲了量化,这一章我带你碰一个更隐蔽的坑——内存对齐

说实话,我第一次踩这个坑的时候,整整调了两天。模型在PC上跑得飞起,一上NPU,要么跑出来的结果全是乱的,要么干脆跑不起来。后来一查,问题出在特征图的尺寸上。

你可能会问:“尺寸不对,大不了补零嘛,能有多大事?”

嗯,还真不是补零那么简单。NPU的内存访问有它自己的“脾气”。

NPU为什么需要内存对齐?

先讲个底层原理。NPU处理数据,不是按“一个像素”来的。

它一次读一大块数据。比如32字节、64字节,甚至128字节。

如果特征图的宽度不是这些对齐单位的整数倍,就会出问题。

举个例子。假设NPU一次读32字节。你的特征图宽度是17像素,每个像素4字节(float32)。

17 × 4 = 68字节。68除以32,余4。

这就尴尬了。NPU读第一行,需要读3次(32+32+4)。但第三次只用了4字节,剩下的28字节怎么办?

有些NPU会直接报错。有些NPU会读脏数据。还有些NPU,嗯,它“假装”没看见,但结果就是错的。

核心结论:BEV特征图的宽度和高度,必须满足NPU的对齐要求。通常是16、32或64的整数倍。

我在项目中遇到的真实案例

我记得有一次部署一个BEV模型。输入图像是608×608,经过backbone后,特征图尺寸是19×19×256。

19?你想想看,19能被32整除吗?显然不能。

结果就是,NPU在计算时,把19当成了32来处理。多出来的13个位置,全是随机数。

最终输出的BEV鸟瞰图,边缘全是噪点。我当时还以为是模型没训练好,折腾了好久。

后来怎么解决的?

我把输入改成640×640。特征图变成20×20。20虽然也不是32的倍数,但至少是4的倍数,很多NPU能处理。

更稳妥的做法,是改成32的倍数,比如608改成640,或者干脆用672。

注意:不要以为只有宽度需要对齐。高度也一样。有些NPU对通道数也有对齐要求,比如通道数必须是8或16的倍数。

常见的对齐要求一览

不同NPU的对齐要求不一样。我整理了一个表格,方便你对照:

NPU类型 宽度/高度对齐 通道对齐 备注
瑞芯微RK3588 16像素 8通道 部分算子要求32对齐
地平线J5 32像素 16通道 BEV特征图建议64对齐
寒武纪MLU220 64像素 32通道 要求比较严格
高通SNPE 16像素 4通道 相对宽松

这个表只是参考。具体到你的芯片,一定要查手册。我个人习惯是,拿到新芯片先跑一个对齐测试。

如何检测对齐问题?

说实话,对齐问题很难肉眼发现。因为模型在PC上跑是对的,上板子就错。

我教你三个方法:

  1. 打印特征图尺寸:在模型转换时,把每一层的输出尺寸都打印出来。看有没有“非对齐”的数字。
  2. 对比输出:用同一张图,在PC上跑一次,在NPU上跑一次。逐像素对比。如果差异很大,大概率是对齐问题。
  3. 补零测试:把特征图尺寸强行补到对齐。如果补零后结果变好了,那就是对齐的锅。

小技巧:我写了一个脚本,自动检测模型所有层的尺寸是否对齐。脚本逻辑很简单:遍历所有层的输出shape,检查每个维度是否能被对齐单位整除。不能整除的,标红报警。

解决方案:补零与裁剪

发现问题后,怎么修?

主要有两种做法:

  • 补零(Padding):在特征图右侧和下方补零,让尺寸变成对齐的倍数。比如19×19补成32×32。注意,补零后要记录原始尺寸,后续处理要裁剪回来。
  • 调整输入:直接修改输入图像的尺寸,让整个pipeline的输出都对齐。比如输入从608改成640。这是最干净的做法。

我个人更推荐第二种。因为补零会引入额外的计算量,而且有些NPU对补零的处理并不高效。

我曾经在一个项目里,为了省事用了补零。结果NPU把补零的区域也算了,白白浪费了30%的算力。后来改成调整输入尺寸,性能直接提升了一截。

避坑指南

最后,给你几条我踩坑踩出来的经验:

  • 设计模型时就考虑对齐:不要等到部署了才发现。在模型设计阶段,就把特征图尺寸设成32或64的倍数。
  • 不要相信“自动对齐”:有些模型转换工具声称会自动对齐。但据我观察,它们经常对齐得不对。还是自己手动检查最靠谱。
  • 注意BEV特有的尺寸:BEV模型的输出通常是H×W×C,比如200×200×64。200能被32整除吗?可以。但如果是180×180呢?180除以32,余20。不行。
  • 多尺度特征图要统一对齐:BEV模型经常用FPN,多个尺度的特征图融合。每个尺度的尺寸都要对齐,否则融合时会出问题。

一句话总结:内存对齐是NPU部署的“隐形墙”。你撞上去之前,根本感觉不到它的存在。但撞一次,就记住了。

好了,这一章就到这里。下一章我们聊聊BEV模型里最让人头疼的“动态尺寸”问题。到时候见。