TensorFlow Lite v1.3训练后量化模型在CPP中输出NaN的原因排查
遇到这种情况确实挺闹心的——未量化模型跑的好好的,量化后就输出NaN,结合TFLite v1.3这个早期版本的特性,我整理了几个最可能的原因和对应的排查思路:
校准数据集存在问题
训练后量化依赖校准数据统计激活值的分布范围,如果你的校准数据里包含NaN/Inf,或者数据分布和实际推理输入差异极大,会直接导致量化参数(缩放因子、零点)计算异常,推理时自然容易出现NaN。
排查:检查校准数据集是否和实际输入的分布一致,有没有清洗掉异常值;确保校准用了足够多的代表性样本(至少几百个),v1.3的量化逻辑对样本量的要求比新版本更严格。输入数据的量化转换错误
量化模型要求输入从浮点转换为对应整数类型(比如uint8或int8),如果C++代码里的转换逻辑错了,比如用错了输入的缩放因子和零点,或者直接强转浮点数为整数,会导致输入值超出量化范围,触发后续计算的NaN。
正确的转换公式应该是:quantized_input = static_cast<uint8_t>(round(input_float / input_scale + input_zero_point));排查:确认你在代码中正确读取了模型输入节点的
scale和zero_point参数,而不是硬编码或者忽略这些值。模型层的量化兼容性不足
TFLite v1.3对很多层的量化支持还不完善,比如自定义层、LSTM的某些变体、当时还未正式支持的激活函数(如Swish),这些层在量化后可能出现参数或激活值的计算错误,进而产生NaN。
排查:用Netron打开量化模型,检查是否存在v1.3文档中未列出的支持量化的层;尝试移除或替换这些层后重新量化,看问题是否解决。量化参数溢出
训练后量化会把浮点参数转换成整数,如果某个层的参数范围极大,超出了目标整数类型的范围(比如uint8的0-255),会导致参数溢出成无效值,推理时计算就会出现NaN。
排查:导出模型时查看tflite_convert的输出日志,有没有参数溢出的警告;用Netron查看量化后模型各层的scale和zero_point,判断参数值是否在量化范围内。C++推理代码的中间计算精度问题
量化模型的中间计算(比如卷积的累加)需要用足够精度的数据类型(比如int32),如果你的代码错误地用了更小的类型(如int)截断中间结果,会导致溢出或NaN。
排查:检查推理代码中处理中间计算的变量类型,确保和TFLite官方示例中的类型一致;比如v1.3的量化卷积实现要求中间累加用int32_t存储。TFLite v1.3的版本bug
作为早期版本,v1.3确实存在一些量化导出的已知bug,比如某些情况下缩放因子计算错误、模型结构转换时丢失信息等。
排查:尝试升级到同系列的稳定新版本(比如v1.14或v1.15)重新导出量化模型,看问题是否消失;或者使用v1.3的最新补丁版本进行导出。
内容的提问来源于stack exchange,提问作者Ahmed

