Implementing complex tensor operations like det()
#4627
|
I am interested in implementing complex tensor operations like My current understanding is that there are two types of tensor operations: primitive (cannot be composed of other tensor ops) and non-primitive (more complex tensor ops that are computed using other primitive and non-primitive tensor ops). I assume most (or all) of the primitive tensor ops have already been implemented given that they are foundational operations. On the other hand, most non-primitive tensor operations can be implemented either using existing Burn tensor operations (a high level implementation) such as When we want to implement these types of complex non-primitive tensor operations, we generally want to make the Backend perform the actual computation either by delegating the operation to a Backend's native operation or by writing a custom cubecl kernel. I think the torch backend is special because it provides functions like det() which we can simply call when the torch backend is selected. On the other hand, for other backends, I think we need to write cubecl kernels. Am I right? However, there are already many high performance implementations of linear algebra operations in many different languages such as BLAS, LAPACK, cuBLAS, cuSOLVER, faes-rs, etc. If we do need to write a cubecl kernel for |
Replies: 2 comments 1 reply
It's a bit more nuanced than that. Primitive ops must be implemented by backends and non-primitive ops have default implementations built from primitives. Some ops have a default implementation that can be overridden by backends for performance. For
Yeah torch is a special case, because it already exposes an API to compute a lot of the tensor operations. So it could be specialized.
Using specialized libraries like cuBLAS or BLAS doesn't break the Burn / CubeCL abstractions per se, but it does reduce portability and composability. Those libraries are backend-specific, while CubeCL aims to provide a portable execution model across targets which can be heavily optimized. We want to leverage that as much as possible. That said, not all “operations” are the same. Some problems, like determinants or LU decompositions, are not really single operations but multi-step algorithms involving synchronization, data-dependent control flow (e.g. pivoting), and multiple kernel launches. While these can be expressed in CubeCL, achieving high performance requires careful global scheduling and numerical considerations, not just fast kernels. It's very different from adding support for another element-wise operation that can be defined using an intrinsic. There are also cases like NCCL, where the problem is fundamentally about inter-device communication and hardware topology rather than computation. They're more difficult to abstract and generalize. I think we're going to add some support in cubecl to leverage specialized libraries to bridge the gap. |
It's a bit more nuanced than that.
Primitive ops must be implemented by backends and non-primitive ops have default implementations built from primitives.
Some ops have a default implementation that can be overridden by backends for performance.
For
det(), I don't think you would write an actual kernel for that. It would likely be composed of other linalg ops to compute the determinant, such as LU decomposition. LU decomposition intensor::linalgcurr…