DEBUG.WIKI
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
雨云;给项目一台云服务器
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →

Numba 并行编译报 Illegal IR, del found,检查内联 argmax 组合

Numba 0.68.0 的强制内联、结构化字段视图和嵌套 argmax 归约组合可能触发非法 IR。可先退回串行 JIT,保留输入和算法,再按结果与耗时评估是否恢复并行。

Numba 0.68.0 编译带结构化数组的并行函数时,可能停在 native parfor lowering,而不是得到业务结果:

CompilerError: Failed in nopython mode pipeline
Illegal IR, del found at: del ...

一条明确的组合是:外层 parallel=True 与 prange,一个 inline="always" 辅助函数返回结构化 dtype 的字段视图,另一个强制内联辅助函数在末尾调用 np.argmax(),两者又以 outer(inner(...)) 直接嵌套。

这里的 del 指编译器中间表示里的清理节点,不表示用户源码里一定写了 del。去业务文件搜索并删除同名变量,通常改不到触发校验的那一层。

先退回串行 JIT,保留算法与输入

如果当前任务允许暂时放弃并行,先同时去掉外层并行选项和 prange。下面给出结构化字段取最大值的简化串行结构,说明修改位置;它不是完整故障复现:

import numba
import numpy as np

@numba.njit(inline="always")
def weights_of(record):
    return record["weights"]

@numba.njit(inline="always")
def choose(values):
    return np.argmax(values)

@numba.njit(parallel=False)
def choose_rows(records):
    result = np.empty(len(records), dtype=np.intp)
    for index in range(len(records)):
        result[index] = choose(weights_of(records[index]))
    return result

示例要求 records 是含 weights 字段的 NumPy 结构化数组,每条字段都是非空的一维数值数组。实际程序仍应保留原来的输入检查、概率归一化或其他计算,不要为了让示例编译而删除必要算法。

串行 JIT 不等于关闭整个 JIT。它避开这次涉及的并行转换路径,但可能明显增加运行时间;若原算法使用随机数,线程调度和随机序列也可能变化,不能要求与旧并行运行逐项随机结果相同。应按业务的确定性结果或统计约束验收。

必须并行时,减少触发组合后再比较结果

可以在隔离分支评估取消不必要的强制内联,或将这条内部 argmax 归约改为适合业务的串行实现。后者必须保留空数组、最大值并列及 NaN 等语义;一个只比较 > 的小循环不自动等价于 NumPy 对所有输入的行为。

Numba 的并行优化器会将支持的 np.argmax 展开为并行归约。当前 0.68.0 的相关清理流程与嵌套 parfor 组合仍可能保留不该存在的清理节点;不能把修改库内私有 IR 清理函数当作应用的常规修复,也不能仅凭开发分支修补建议判断某个正式版已解决。

保留一个能定位此组合的小输入,再覆盖原有计算结果、写入数组和异常分支。采用串行方案时记录可接受的耗时上限;后续恢复并行时重新比较结果与资源占用。若错误发生在普通类型推断、输入 dtype 不匹配等阶段,则应按新的堆栈处理,不把所有 Numba 编译失败归到这项 IR 问题。