You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Numpy einsum操作转换为Eigen Tensor运算(适配Jet类型)

将Numpy Einsum转换为Eigen Tensor(支持Jet类型向量化)

理解原Einsum操作

原Numpy代码中的np.einsum('ijl,jkl->ikl', U, L)等价于:对每个索引l,执行矩阵乘法U[:, :, l] @ L[:, :, l],最终将所有结果沿l维度堆叠,输出形状为(2,2,136)的张量。

Eigen Tensor实现方案

利用Eigen的表达式模板(避免显式循环),通过shuffle(维度重排)和contract(张量收缩)实现,确保Jet类型能被自动向量化优化。

步骤1:定义类型与张量

#include <Eigen/Dense>
#include <Eigen/Tensor>

// 假设Jet类型为自动微分的对偶数类型
using Jet = Eigen::AutoDiffScalar<Eigen::VectorXd>;

// 对应原Numpy的维度:I=2, J=2, L_dim=136
constexpr int I = 2, J = 2, L_dim = 136;

// 初始化张量(与Numpy行优先存储一致,指定RowMajor)
Eigen::Tensor<Jet, 3, Eigen::RowMajor> U(I, J, L_dim);
Eigen::Tensor<Jet, 3, Eigen::RowMajor> L(J, I, L_dim); // K=2,对应原L的J,K,L维度

// 省略U和L的初始化代码(对应np.random.rand)

步骤2:通过批量矩阵乘法实现

将l维度转为批量维度,执行批量矩阵乘法后再恢复原维度顺序:

// 1. 将U的维度从(I,J,L)重排为(L,I,J)(批量维度前置)
Eigen::array<int, 3> u_perm = {2, 0, 1};
auto U_batch = U.shuffle(u_perm);

// 2. 将L的维度从(J,K,L)重排为(L,J,K)
Eigen::array<int, 3> l_perm = {2, 0, 1};
auto L_batch = L.shuffle(l_perm);

// 3. 执行批量矩阵乘法:每个批量(l)对应矩阵I×J 乘 J×K,得到(L,I,K)
Eigen::array<Eigen::IndexPair<int>, 1> matmul_dims = {Eigen::IndexPair<int>(2, 1)};
auto result_batch = U_batch.contract(L_batch, matmul_dims);

// 4. 将结果维度从(L,I,K)重排为(I,K,L),匹配原Einsum输出
Eigen::array<int, 3> res_perm = {1, 2, 0};
Eigen::Tensor<Jet, 3, Eigen::RowMajor> result = result_batch.shuffle(res_perm);

步骤3:直接张量收缩实现

也可以直接通过张量收缩指定维度映射,一步得到结果:

// 指定收缩维度:U的第1维(J)与L的第0维(J)
Eigen::array<Eigen::IndexPair<int>, 1> contract_dims = {Eigen::IndexPair<int>(1, 0)};

// 直接收缩并指定结果维度顺序:I, K, L
Eigen::Tensor<Jet, 3, Eigen::RowMajor> result = U.contract(L, contract_dims).reshape(Eigen::array<int, 3>{I, I, L_dim});

关键优势

  • 所有操作(shuffle/contract/reshape)均为Eigen表达式模板,不会立即执行,编译器可将整个操作融合为向量化内核。
  • 完全兼容Jet类型,Eigen会自动重载操作符实现对数值和梯度数组的向量化计算,无需手动循环。

内容的提问来源于stack exchange,提问作者Niteya Shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:20:24