必须先调用 dnnl_engine_create(&engine, dnnl_cpu, 0) 初始化 cpu 引擎,再调用 dnnl_stream_create(&stream, engine, dnnl_stream_default_flags) 创建流,所有 primitive 执行均需传入该 stream。

怎么初始化 dnnl_engine 和 dnnl_stream
不初始化就调用 dnnl_primitive 会直接 crash,不是报错而是段错误——因为 oneDNN(原 DNNL)所有计算都必须绑定到具体硬件上下文。CPU 和 GPU 引擎初始化方式不同,但绝大多数 C++ 项目起步只用 CPU。
常见错误是跳过 dnnl_engine_create 或传错 dnnl_engine_kind_t;比如误用 dnnl_gpu 却没装 Intel GPU 驱动或 oneDNN 的 GPU 后端,结果 dnnl_success 返回 false 但没检查返回值。
- 先调
dnnl_engine_create(&engine, dnnl_cpu, 0),第二个参数固定为dnnl_cpu,第三个是设备索引(CPU 总是 0) - 紧接着必须调
dnnl_stream_create(&stream, engine, dnnl_stream_default_flags),不能复用 engine 而漏掉 stream - 所有 primitive 执行都需传入这个
stream,哪怕只是创建 primitive 描述符(如dnnl_inner_product_forward_desc_init)也依赖 engine
如何正确构造 memory descriptor(dnnl_memory_desc_t)
memory desc 是 oneDNN 最容易写错的一环:维度顺序、数据类型、内存格式 tag 三者必须严格匹配,否则 dnnl_primitive_desc_create 返回 dnnl_unimplemented 或运行时数值全零。
典型场景是卷积输入:NHWC 输入要转成 NCHW 才能被大多数 primitive 接受,但 oneDNN 不自动转换——你得手动指定 dnnl_format_tag_t,比如 dnnl_nchw,并确保 dims 数组按该 tag 解释。
-
dims是 int64_t 数组,顺序必须和 tag 一致:用dnnl_nchw就得是{N, C, H, W},不是{N, H, W, C} - 数据类型用
dnnl_f32最稳;dnnl_bf16需 CPU 支持 AVX512_BF16 指令集,否则dnnl_primitive_desc_create失败 - 别直接传裸指针给
dnnl_memory_create;先用dnnl_memory_desc_init_by_tag初始化 desc,再用dnnl_memory_create绑定 buffer
为什么 dnnl_primitive_desc_create 总返回 dnnl_unimplemented
这不是 bug,是 oneDNN 的设计哲学:它只实现特定 layout + data type + algorithm 的组合。哪怕 dims 完全合法,只要 format tag 和算法不匹配,就拒绝创建 primitive 描述符。
最常踩的坑是默认用 dnnl_format_tag_any 以为能“自动适配”,结果后续 dnnl_primitive_create 时因内存 layout 不兼容而失败。oneDNN 不做隐式重排,_any 只是让库内部选一个它支持的 layout,但你后续必须用 dnnl_primitive_desc_query 拿到真实 layout 并按此准备 memory。
- 调试时先打印
dnnl_status_t返回值,别只看nullptr判定失败 - 对卷积/全连接等,优先用明确 tag(如
dnnl_oihw权重、dnnl_nchw输入),避开_any - 如果必须用
_any,立刻调dnnl_primitive_desc_query_md(pd, dnnl_query_src_md, 0)拿实际内存描述符,再据此分配 buffer
如何避免 dnnl_memory_map_data 崩溃或读出乱码
dnnl_memory_map_data 不是 memcpy 包装器,它是把 oneDNN 内部 memory object 映射到用户可读地址。崩溃往往因为 memory 对象生命周期结束早于 map,或者映射后没调 dnnl_memory_unmap_data 导致资源泄漏甚至下次 map 失败。
更隐蔽的问题是:GPU memory 无法用 dnnl_memory_map_data(会返回 dnnl_unimplemented),但 CPU memory 映射后若 buffer 被 primitive 在 stream 上异步修改,map 出来的指针内容可能未同步——你得先 dnnl_stream_wait(stream)。
- 只对 CPU engine 创建的 memory 调用
dnnl_memory_map_data,GPU 请改用dnnl_memory_get_data_handle+ 自行 memcpy(且确保 host buffer 已 pin) - map 前确认 stream 已完成所有依赖操作:
dnnl_stream_wait(stream)必须在 map 之前 - map 返回的指针不能长期持有;用完立即
dnnl_memory_unmap_data,否则后续 primitive 执行可能卡死
dnnl_invalid_arguments 或 dnnl_unimplemented,一旦出现,基本意味着你的 desc 构造逻辑有硬伤,而不是换个参数就能绕过去。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











