【Bug已解决】CPU EP mis-loads packed `UINT2` Constant initializer (treats `UInt2x4` as unpacked storage;…
【Bug已解决】CPU EP mis-loads packedUINT2Constant initializer (treatsUInt2x4as unpacked storage;INT2unaffected) 解决方案一、现象长什么样模型里有一个被量化成2-bit的权重常量用 ONNX 的UINT2打包数据类型在每个字节里塞 4 个 2-bit 元素UInt2x4存成Constant初始化器。在 ONNX Runtime 的 CPU EP 上加载并推理结果全是垃圾值和预期差很远余弦相似度接近 0或分类输出全错 —— 但同一个模型在 GPU EP 上结果正确最小触发import onnxruntime as ort # 模型含一个 UINT2 打包的 Constant 初始化器 sess ort.InferenceSession(uint2_model.onnx, providers[CPUExecutionProvider]) out sess.run(None, feed)[0] # 结果错误换成 providers[CUDAExecutionProvider] 结果正确排查发现CPU EP 把UInt2x4当成了未打包的存储来读——也就是按“每字节一个元素”去解释那块 buffer而实际上每字节装了 4 个 2-bit 元素。偏偏INT22-bit 有符号是正确的只有UINT2错。这是典型的“打包数据类型反序列化漏了一种”。二、背景ONNX 从 opset 21 起支持 2-bit 和 4-bit 的“打包”数据类型UINT2/INT2每字节 4 个、UINT4/INT4每字节 2 个。打包后的常量在 proto 里表现为外层 tensor 的elem_type是UINT2dims描述的是打包后的形状比如原始 1024 个元素打包成 256 个字节dims[256]原始元素个数靠data_type 一个packed属性或约定推断。加载时运行时需要识别elem_type UINT2按“每字节 4 个元素”做位解包bit-unpack还原出 1024 个 0~3 的值把解包后的张量交给后续算子。CPU EP 的常量加载器tensor deserializer对INT2写了正确的解包路径但对UINT2走错了分支——直接把dims[256]的字节 buffer 当 256 个完整uint8元素用没解包。于是 256 个字节被当成 256 个值范围 0255而不是 1024 个 03 的值形状也对不上后续算子拿到完全错误的数据。三、根因根因是CPU EP 的常量加载器对UINT2和INT2的处理不对称解包分支漏了UINT2加载器里有一张elem_type - 加载函数的映射INT2指向了“位解包到 int8”的实现UINT2却错误地指向了“原样按 uint8 读”的默认实现或根本没在映射里fallback 到逐字节读。形状未还原因为没解包dims停留在打包后的[256]而下游算子期望[1024]读出来的元素个数和语义全错。INT2 正常对照INT2因为有正确的解包实现所以无影响——这进一步说明不是“打包机制整体坏了”而是UINT2这一支被漏掉。所以这不是模型算错而是CPU EP 反序列化 2-bit 数据时漏了对无符号UINT2的解包把它当成了未打包的 uint8。四、最小可运行复现下面用 Python NumPy 模拟“UINT2 打包数据被错误地当 uint8 读取”的偏差并给出正确的位解包import numpy as np def wrong_load(packed: np.ndarray) - np.ndarray: CPU EP 当前的错误做法把每字节当 1 个 uint8 元素。 return packed.astype(np.uint8) # 256 个值值域 0~255且未解包 def correct_unpack_uint2(packed: np.ndarray) - np.ndarray: 正确做法每字节拆出 4 个 2-bit 无符号元素低位在前。 packed packed.astype(np.uint8) out np.zeros(packed.shape[0] * 4, dtypenp.uint8) for i in range(4): out[i::4] (packed (2 * i)) 0x03 return out if __name__ __main__: # 打包前原始 4 个元素 [0,1,2,3] - 打包成 1 字节 0b11100100? 计算 raw np.array([0, 1, 2, 3], dtypenp.uint8) packed np.zeros(1, dtypenp.uint8) for i, v in enumerate(raw): packed[0] | (v 0x03) (2 * i) print(packed byte:, int(packed[0])) # 0b00001111 15 wrong wrong_load(packed) right correct_unpack_uint2(packed) print(错误加载:, wrong, 形状, wrong.shape) # [15] 错 print(正确解包:, right, 形状, right.shape) # [0 1 2 3] 对 assert np.array_equal(right, raw)跑出来错误加载得到[15]一个 uint8正确解包得到[0 1 2 3]四个 2-bit 元素。这正好复现了 CPU EP 把UInt2x4当未打包存储读错的现象。五、解决方案第一层最小直接修复最小修复在常量加载器里给UINT2补上和INT2对称的解包实现。对使用者来说临时规避是把模型里的UINT2常量在导出时改成UINT4或UINT8未打包绕开 CPU EP 的UINT2解包 bug或者干脆用 GPU EP 跑GPU EP 解包正确。对 ORT 仓库侧加载器映射应改成// 伪代码常量加载器的 elem_type 分支 switch (elem_type) { case ONNX_NAMESPACE::TensorProto::UINT2: return LoadPackeduint8_t, 2, /*signed*/false(tensor); // 补这一支 case ONNX_NAMESPACE::TensorProto::INT2: return LoadPackedint8_t, 2, /*signed*/true(tensor); case ONNX_NAMESPACE::TensorProto::UINT4: return LoadPackeduint8_t, 4, /*signed*/false(tensor); case ONNX_NAMESPACE::TensorProto::INT4: return LoadPackedint8_t, 4, /*signed*/true(tensor); default: return LoadPlain(tensor); }LoadPacked负责按 bits2 做位解包并把dims从打包形状还原成原始元素个数dim[0] * 4。这一层立刻让UINT2常量被正确解包。六、解决方案第二层结构性改进把“哪些打包类型需要解包、如何解包”收口成唯一的配置对象OrtCpuUint2ConstantPolicy加载器读它避免再漏类型from dataclasses import dataclass, field from typing import Dict, Tuple dataclass(frozenTrue) class OrtCpuUint2ConstantPolicy: CPU EP 打包常量加载的单一事实来源。 # 打包类型 - (每字节元素数, 是否有符号) packed_types: Tuple[str, ...] (UINT2, INT2, UINT4, INT4) bits_per_element: Dict[str, int] field(default_factorylambda: { UINT2: 2, INT2: 2, UINT4: 4, INT4: 4, }) signed: Dict[str, bool] field(default_factorylambda: { UINT2: False, INT2: True, UINT4: False, INT4: True, }) # 是否必须解包True 表示不能当 uint8 原样读 must_unpack: Tuple[str, ...] (UINT2, INT2, UINT4, INT4) # 字节内位序低位在前 lsb_first: bool True def needs_unpack(self, elem_type: str) - bool: return elem_type in self.must_unpack def unpack_shape_scale(self, elem_type: str) - int: return 8 // self.bits_per_element.get(elem_type, 8) def describe(self) - str: return UINT2/INT2/UINT4/INT4 全部走对称位解包无符号与有符号一致 POLICY OrtCpuUint2ConstantPolicy() def plan_load(elem_type: str, policy: OrtCpuUint2ConstantPolicy POLICY) - dict: return { unpack: policy.needs_unpack(elem_type), scale: policy.unpack_shape_scale(elem_type), signed: policy.signed.get(elem_type, False), }所有加载逻辑读同一份POLICY新增打包类型只要在packed_types里加一项就自动覆盖不会再出现“INT2 有、UINT2 漏”的不对称。七、解决方案第三层断言 / CI 守护把“UINT2 必须解包、结果与 GPU EP 一致”做成断言。下面用 pytest 风格守护复用第四节解包逻辑import numpy as np def test_uint2_must_unpack(policy): assert policy.needs_unpack(UINT2) is True assert policy.needs_unpack(INT2) is True def test_uint2_symmetrical_with_int2(policy): # UINT2 与 INT2 应走相同的解包机制仅符号不同 assert policy.bits_per_element[UINT2] policy.bits_per_element[INT2] assert policy.signed[UINT2] is False assert policy.signed[INT2] is True def test_unpack_recovers_values(): raw np.array([0, 1, 2, 3], dtypenp.uint8) packed np.zeros(1, dtypenp.uint8) for i, v in enumerate(raw): packed[0] | (v 0x03) (2 * i) assert np.array_equal(correct_unpack_uint2(packed), raw) def test_shape_restored_after_unpack(policy): scale policy.unpack_shape_scale(UINT2) assert scale 4 # 每字节 4 个元素这四组断言锁住(1)UINT2必须解包(2)UINT2/INT2对称仅符号差异(3) 解包还原正确值(4) 形状按 4 倍还原。CI 跑通即代表 CPU EP 的 2-bit 加载对称正确。八、排查清单遇到 CPU EP 上 2-bit 量化模型结果错、GPU EP 正常先换 EP 测GPU EP 结果对、CPU EP 错 → 多半是 CPU 反序列化问题。看常量 elem_type模型里是不是UINT2打包常量INT2正常可对照。检查加载器映射UINT2有没有指向位解包实现还是 fallback 到逐字节读。临时规避导出时把UINT2改UINT4/UINT8或暂用 GPU EP。根本修复给UINT2补对称解包并还原dims。统一策略对象用OrtCpuUint2ConstantPolicy固化新增打包类型自动覆盖。CI 守护断言UINT2解包正确、与INT2对称防止回归。九、小结CPU EP mis-loads packed UINT2 Constant initializer的根因是 CPU EP 的常量加载器对 2-bit 数据类型处理不对称INT2走了正确的位解包而UINT2漏了分支、被当成未打包的 uint8 逐字节读取导致值错误、形状未还原而 GPU EP 解包正确所以无影响。最小修复是给UINT2补上和INT2对称的解包实现并还原形状结构性改进是用唯一的OrtCpuUint2ConstantPolicy把打包类型的处理收口CI 用四组断言守护“UINT2 必须解包、与 INT2 对称、形状还原、值正确”。记住2-bit 打包数据在 CPU 反序列化时必须位解包无符号和有符号要走同一套机制、只差符号位。

相关新闻

从零开始搭建个人服务器 网站建设:一份写给独立开发者的真心话

从零开始搭建个人服务器 网站建设:一份写给独立开发者的真心话

在这个互联网巨头垄断流量、平台算法决定生死的大环境下,越来越多的技术人和内容创作者开始转向一种更底层、更本质,却也更具掌控力的生活方式——那就是通过个人服务器 网站建设 来实现数字空间的绝对自主。这不仅仅是一个技术项目的执行,更像是一场关于自由、隐私以及自我…

2026/10/4 9:17:11 阅读更多 →
从Softmax与交叉熵损失原理到NumPy实现:掌握分类任务核心梯度推导

从Softmax与交叉熵损失原理到NumPy实现:掌握分类任务核心梯度推导

1. 项目概述:从公式到代码的深度穿越 如果你正在入门深度学习,尤其是分类任务,那么“Softmax 交叉熵损失”这个组合对你来说,就像学开车必须先学会踩油门和刹车一样基础。但很多人可能只是调用了 torch.nn.CrossEntropyLoss() …

2026/9/29 20:20:45 阅读更多 →
搜索引擎爬虫触发LLM安全模糊测试:从Applebot现象看新型应用防御

搜索引擎爬虫触发LLM安全模糊测试:从Applebot现象看新型应用防御

最近在安全圈和AI圈的交界处,一个看似不起眼的变化正在发生:苹果的搜索引擎爬虫 Applebot,开始频繁地出现在一些大型语言模型(LLM)的访问日志里。这听起来可能只是技术栈里又多了一个用户代理字符串,但如果…

2026/10/1 17:24:42 阅读更多 →

最新新闻

OSCP备考资料包高效指南:整理、校验与索引式复习

OSCP备考资料包高效指南:整理、校验与索引式复习

简介:面向OSCP备考人员及渗透测试初学者,这份资料围绕渗透测试全生命周期,系统整理了通用测试方法、操作技巧与常用工具,内容覆盖Web服务、系统服务、Linux提权、Windows提权、靶机Writeups等核心模块;既适合按目录速查…

2026/10/4 9:17:18 阅读更多 →
Codex 读 CI 失败日志修 flaky test:AGENTS.md 约束下定位最小原因,TaoToken 统一 Key 接入实战

Codex 读 CI 失败日志修 flaky test:AGENTS.md 约束下定位最小原因,TaoToken 统一 Key 接入实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:17:18 阅读更多 →
从LLM到垂直领域智能体:30个智能体架构设计与工程实践

从LLM到垂直领域智能体:30个智能体架构设计与工程实践

1. 从大语言模型到垂直领域智能体:为什么“套壳对话”远远不够大语言模型(LLM)这两年的热度不用我多说,从写文案、写代码到做翻译、做总结,几乎每个团队都在试。但如果你真的在医疗、金融、法律、工业这些垂直领域落地…

2026/10/4 9:17:18 阅读更多 →
BLIP-2+SAM+ChatGPT:8G显存跑通图像转中文段落流水线

BLIP-2+SAM+ChatGPT:8G显存跑通图像转中文段落流水线

在动手之前先聊点实际的:把一张图变成一段自然、连贯、有层次的中文文字描述,这事放在一年前还像是个“论文里才有的效果”,但现在你完全可以自己搭出来。核心就是标题里那三个词:BLIP-2、SAM、ChatGPT。BLIP-2负责“看图说话”&a…

2026/10/4 9:17:18 阅读更多 →
基于Spring AI的MCP Server/Client实现及鉴权:把鉴权配置改到TaoToken

基于Spring AI的MCP Server/Client实现及鉴权:把鉴权配置改到TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:17:18 阅读更多 →
永磁同步电机三闭环位置伺服系统仿真研究——基于转子磁链定向的PI控制策略(Simulink仿真实现)

永磁同步电机三闭环位置伺服系统仿真研究——基于转子磁链定向的PI控制策略(Simulink仿真实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 &#x1f381…

2026/10/4 9:15:17 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →