已关闭
[Bug-Report|缺陷反馈]: Python 属性列表的 DataType 枚举被错误写入 list_int #633
廖氏如神创建于  10月3日关闭于  13 天前
廖氏如神
廖氏如神
10月3日 创建

问题描述与影响

Node.set_attr("types", [DataType.DT_FLOAT16, DataType.DT_INT32]) 调用 SetListInt,而不是 SetListDataType;普通整数的匹配分支吞掉 IntEnum 类型。

影响:Node、Graph、Operator 属性中的数据类型列表变成整数列表,原生读取 LIST_DATA_TYPE 属性时发生类型不匹配。

基线:cann/ge:develop,提交 ba12e592e8f84bc59709464bd3ad6ca010498d8b。任务分支直接从刷新后的上游建立。

环境与复现

本地 Windows / Python 3.12.14,加载实际生产 Python 源码。pyge 使用 pytest,与 scripts/build_fwk.sh 一致。Graph/GraphBuilder/Node 和方法适配使用实际实现,C API、原生 pass 类型及未使用的描述符边界被替换。

  1. 在未修复基线上运行下面的构造/触发示例,或应用 PR 对应回归及必要 helper。
  2. 从仓库根目录运行下面命令,核对实际断言失败;相同测试应用修复后通过。
  3. 同时检查兼容控制与替身边界,未将依赖/收集错误作为缺陷复现。
Node.set_attr("types", [DataType.DT_FLOAT16, DataType.DT_INT32])
# 原版原生边界为 SetListInt,预期 SetListDataType。新增回归调用实际 Node。
python -m pytest -q -p no:cacheprovider tests/ge/ut/ge/graph/pyge_tests/attr_list_datatype_dispatch_test.py

直接导入示例要求项目依赖可导入;本地 CPU 环境边界如上。

预期行为

完整 DataType 列表写入 LIST_DATA_TYPE,普通 int/bool/float/string 列表保留既有类型。

根因和修复范围

实现:api/python/ge/ge/graph/_attr.py。

DataType 继承 IntEnum,也是 int;set_value 的列表分派先检查 int 再检查 DataType,后者无法到达。

将完整 DataType 列表的分支移动到 int 列表之前,沿用已有类型校验和 C API。

等级建议:L3,依据实际复现影响提出,最终请维护者/SIG 评定,不预先认定奖励等级。

验证

5 项:实际 Node.set_attr 写入 DataType 列表,检查 SetListDataType、ctypes 缓冲区及元素值;普通 int/bool/float/string 列表保留分派。

独立修复本地结果:5 passed in 0.06s;回归 tests/ge/ut/ge/graph/pyge_tests/attr_list_datatype_dispatch_test.py。最终分组结果见 PR;LLM 已接入实际 unittest UT/ST 入口。

本地组合验证:32 passed, 49 subtests passed in 0.85s,与 ['llm-options-snapshot', 'llm-cache-transfer-metadata', 'llm-transfer-worker-results', 'llm-numpy-string-conversions'] 试合验证。未验证真实 CANN/NPU、原生 ABI、全量 C++ UT/ST。远端完整 CI 按当前 PR head 实际终态确认,本地通过不等于门禁通过。

重复核查与关联

核查全部作者、所有状态 Issue/PR 的标题正文,并读取 525 个开放 PR 的实际文件差异;接口失败已补查。

修复 PR:https://gitcode.com/cann/ge/pull/5294,目标 develop。

likedislike
廖氏如神廖氏如神
10月3日 添加了label:bug-report
廖氏如神廖氏如神
10月3日 关联了pull request:fix(python): dispatch DataType lists before integer attributes (#633)
廖氏如神廖氏如神
10月3日 修改了issue 的描述
廖氏如神
廖氏如神
10月3日 评论:

/assign

likedislike
CANN-robotCANN-robot成员
10月3日 将 gcw_Z57idahf 设为负责人
KKenChow成员
20 天前 将 m0_50621083 设为负责人,移除负责人 gcw_Z57idahf
洪跃城
洪跃城成员
20 天前 评论:

已收到您的反馈,我们将会核实,请关注issue状态。

likedislike
洪跃城
洪跃城成员
15 天前 评论:

感谢反馈,也感谢您直接给出源码级定位、回归用例和修复 PR。

结论:问题属实。这是 GE Python API(pyge)_AttrValue.set_value 列表分派的分支顺序缺陷,属本仓(GE)责任田。我们在 master 上逐条复核,与您在 develop 基线上的判断一致;缺陷在当前 master HEAD 仍然存在。

核查证据

源码位置基于 main/ge(cann/ge master),下列行号在 225dd7adb 与当前 HEAD 完全一致。

  1. DataType 实例同时是 int —— class DataType(IntEnum) [main/ge/api/python/ge/ge/graph/types.py:15]

  2. 列表分派中 int 分支在 DataType 分支之前,后者不可达 —— _AttrValue.set_value [main/ge/api/python/ge/ge/graph/_attr.py:273]

    elif isinstance(value, list) and all(isinstance(v, int) for v in value):      # :297 先命中
        self.set_list_int(value)
    elif isinstance(value, list) and all(isinstance(v, DataType) for v in value): # :299 永不可达
        self.set_list_data_type(value)
    

    对照标量路径:DataType 分支 [_attr.py:287] 排在 int 分支 [_attr.py:291] 之前,所以单个 DataType 走 set_data_type 是正确的 —— 缺陷只在列表路径,与您的描述吻合。

  3. 影响链成立 —— set_list_int 绑定 GeApiWrapper_AttrValue_SetListInt(int64_t 数组)[_attr.py:504],属性被写成 VT_LIST_INT;原生侧 AttrUtils::GetListDataType [main/ge/graph_metadef/graph/attr/ge_attr_value.cc:430] 经 AttrStore::GetByName<T> [main/ge/inc/graph_metadef/graph/attr_store.h:257] 做类型匹配,取不到 std::vector<DataType> 即返回 false,就是您说的"原生读取 LIST_DATA_TYPE 属性时类型不匹配"。

  4. 修复不需要动 C 侧或 ABI —— GeApiWrapper_AttrValue_SetListDataType 已实现 [main/ge/api/python/ge/ge_api_c_wrapper/c_anyvalue.cc:202],Python 绑定已声明 [main/ge/api/python/ge/ge/_capi/pygraph_wrapper.py:152],set_list_data_type 工厂也已就绪 [_attr.py:522]。您"沿用已有类型校验和 C API"的判断正确。

不依赖 NPU 的最小复核

在仓库根目录执行,只加载枚举模块,不需要 libgraph_wrapper.so(本机已实测):

python3 - <<'EOF'
import importlib.util
spec = importlib.util.spec_from_file_location("ge_types", "api/python/ge/ge/graph/types.py")
m = importlib.util.module_from_spec(spec)
spec.loader.exec_module(m)
DataType = m.DataType
v = [DataType.DT_FLOAT16, DataType.DT_INT32]
print("isinstance(DataType.DT_FLOAT16, int) =", isinstance(DataType.DT_FLOAT16, int))
print("int 分支 all(isinstance(v, int))     =", all(isinstance(x, int) for x in v))
print("DataType 分支 all(isinstance(v, DT)) =", all(isinstance(x, DataType) for x in v))
EOF

输出三项均为 True,即两个分支条件同时满足,谁在前谁生效 —— 这正是 :297 截获 :299 的原因。

影响范围

Node.set_attr [main/ge/api/python/ge/ge/graph/node.py:236]、Graph.set_attr [main/ge/api/python/ge/ge/graph/graph.py:249]、Operator.set_attr [main/ge/api/python/ge/ge/graph/operator.py:84] 三个入口都经 attr_value.set_value(value) 分派,因此都受影响。

我们另外确认了两点边界:仓内现有代码没有以 DataType 列表调用 set_attr 的路径,影响面在 pyge 对外 API 使用者侧;bool 列表分派在 int 之前,bool 不是 DataType,因此把 DataType 分支上移不会改变 int/bool/float/str 列表的既有分派结果。

后续

您提出的修复方向(DataType 列表分支上移到 int 列表分支之前)我们认可,已关联 PR #5294,由维护团队按流程评审。评审时会一并关注两处:

  • 混合列表语义:调整后 [DataType.DT_FLOAT16, 3] 这类混合列表会落到 set_list_int(元素不全是 DataType),是否需要显式报错而非静默按 int 写入,希望在 PR 里明确。
  • 回归用例落点:建议补进 tests/ge/ut/ge/graph/pyge_tests/attr_test.py。该文件现有用例只覆盖显式调用 set_list_data_type,未覆盖 set_value 的自动分派路径,正是这次漏网的原因。

改动影响性评估与回归验证由维护方承担。合入时间与版本由维护团队统一评估,有进展会在本 issue 更新。

likedislike
CANN-robotCANN-robot成员
13 天前 关闭了 issue
洪跃城洪跃城成员
13 天前 issue状态由 进行中 改变为 已完成
CANN-robotCANN-robot成员
13 天前 添加了label:resolved