[WIP] feat: add InfiniOps as optional kernel provider#161
Conversation
614baf6 to
91b309a
Compare
91b309a to
c7e3c27
Compare
Wire InfiniOps in as a pluggable kernel provider keyed at the GEMM level: Dispatcher consults a per-key whitelist hook and routes registered ops to InfiniOps, falling back to the default CUDA kernel otherwise. linear, matmul and outer now invoke Gemm via Dispatcher rather than calling the cuBLAS wrapper directly, so InfiniOps Gemm transparently covers all three.
c7e3c27 to
865b51c
Compare
There was a problem hiding this comment.
这里是出于什么原因要单独写一套 registry,而不能直接复用 InfiniTrain 原有的注册表呢?
There was a problem hiding this comment.
这个头文件内容没什么问题,但不适合放到 include 里作为公共头文件暴露,先放 infini_train/src/kernels/common 里吧
There was a problem hiding this comment.
这里不应该给 infinops 开额外分支,之前接沐曦 kernel 这块是不需要动的。
There was a problem hiding this comment.
这里沐曦和 infinops 的区别在于 infinops 需要解耦 device。
沐曦/MACA 是 InfiniTrain 的一个 device backend。它和 CUDA/CPU 一样,kernel 是按 device + op 注册的,所以可以继续用现有 REGISTER_KERNEL(device, kernel_name, kernel_func)
但 infinops 里面封装了不同 device 的执行,不是某一个具体 device,而是 kernel provider / backend provider。InfiniOps 自己内部再根据 handle/tensor device 去适配 NVIDIA、CPU、MUSA、Moore 等后端。所以框架这边调的时候也要在 Dispatcher::GetKernel 之前或里面做一层 provider policy。 infiniops_registry.h 里重写一套注册也是这个原因,其实就是无法复用REGISTER_KERNEL 接口,要把 device 参数换成 backend 参数。
这里其实可以不特化写一个 InfiniOpsRegistry,而是给Dispatcher添加一个通用的REGISTER_KERNEL_BACKEND(backend, kernel_name, kernel_func) ,InfiniOps调用REGISTER_KERNEL_BACKEND("InfiniOps", kernel_name, kernel_func)。这样 dispatcher.h 可能会整洁一点。
There was a problem hiding this comment.
我理解可以复用 REGISTER_KERNEL(device, kernel_name, kernel_func) 来注册不同 device 的 infiniops kernel。在框架层,不需要关心底层算子库的实现,只按需注册对应 device 的 kernel 即可,类似:
https://github.com/InfiniTensor/InfiniTensor/blob/fcd1fb0299e181f841918c4db4e5f13a18a2ae60/src/kernels/infiniop/element_wise.cc#L36
| @@ -0,0 +1,25 @@ | |||
| #include "infini_train/include/core/kernel_provider/infiniops/adapter.h" | |||
|
|
||
| } // namespace infini_train::kernel_provider::infiniops | ||
|
|
||
| REGISTER_INFINIOPS_KERNEL(AddForward, infini_train::kernel_provider::infiniops::AddForward) |
There was a problem hiding this comment.
如果是为了修改注册 key 而专门给 infiniops 写一套注册机制的话感觉不是很有必要,直接按平台注册就行。
There was a problem hiding this comment.
意思是按平台注册但其实平台参数没用?
There was a problem hiding this comment.
平台参数在这里的作用更多是框架侧显式声明“哪些平台注册了 kernel”(类似白名单机制)。如果某个平台未注册,dispatcher 可以直接报错。
具体执行时使用哪个 device,还是在 adapter 层通过 ToOpsDevice 转换后再传给 infiniops。
There was a problem hiding this comment.
这部分是必要的通用 gemm 接口抽象改动,不涉及 infiniops 相关,可以考虑单独提 pr 先合。
| // FIXME: Requires stride tracking in the Tensor class before this can be implemented | ||
| // correctly. Currently always returns true as a placeholder. The contiguous guard in | ||
| // elementwise.cu ensures non-contiguous tensors fall back to the broadcast path. | ||
| // the elementwise provider ensures non-contiguous tensors fall back to the broadcast path. |
There was a problem hiding this comment.
感觉应该是 elementwise provider,起码 elementwise.maca 里也有这个逻辑
| std::shared_ptr<Tensor> Contiguous(); | ||
| // FIXME: Currently returns true unconditionally. Requires stride tracking in the Tensor | ||
| // class before this can be implemented correctly. The guard in elementwise.cu ensures | ||
| // class before this can be implemented correctly. The elementwise broadcast guard ensures |
Summary
引入 InfiniOps 作为可选的 kernel provider,通过
USE_INFINIOPS=ON启用。插拔粒度落在 Dispatcher::Call():Dispatcher 在
GetKernel里增加白名单 hook,命中的 key 路由到 InfiniOps registry,未命中则回退到默认 CUDA kernel。linear、matmul、outer 三个上层算子从直接调用
GemmCuda改为Dispatcher::Instance().Call<void>({device.type(), "Gemm"}, ...),因此 InfiniOps 一次提供 Gemm 即可透明覆盖这三个上层算子,无需逐个包装。Changes
USE_INFINIOPSCMake 选项;third_party/InfiniOps作为子模块接入;启用时按需 add_subdirectory 并链接InfiniOps::infiniops。GetKernel增加 InfiniOps lookup hook;未命中 whitelist 时维持原行为。InfiniOpsRegistry(独立于主 Dispatcher 的 map)+REGISTER_INFINIOPS_KERNEL宏 + 全局 whitelist(当前包含Gemm、AddForward)。adapter.{h,cc}提供ToOpsDataType/ToOpsDevice/ToOpsTensor类型与张量桥接,dtype/device 对照采用inline const std::unordered_map。gemm.cc、elementwise.cc(AddForward)。common/gemm.{cu,cuh}把GemmCuda重命名为Gemm并通过REGISTER_KERNEL注册;linear/matmul/outer 的所有 GEMM 调用走 Dispatcher。测试
当前单卡测试性能精度对齐

问题:InfiniTrain 原生 CUDA GEMM 在 gemm.cu (line 63) 固定用CUBLAS_COMPUTE_32F,但 InfiniOps NVIDIA GEMM 原来对 fp32 走的是CUBLAS_COMPUTE_32F_FAST_TF32,这里我手动修改了 InfiniOps 源码
TODO:解决编译warning