如何在 C++ 中将特征张量乘以另一个特征张量的标量和?

How to multiply an Eigen Tensor by the scalar sum of another Eigen Tensor in C++?

我在 C++ 中使用 Eigen 库的张量方面,我想计算一个特征张量乘以第二个特征张量中元素的标量和的逐元素乘积。类似于:

#include <Eigen/Dense>
Eigen::Tensor<float,2>u(5,5);
Eigen::Tensor<float,2>v(5,5);

u.setConstant(1.f);
v.setConstant(2.f);

Eigen::Tensor<float,2>ans(5,5);
ans = u*v.sum();

但是这种方式不支持 * 运算符。

README建议使用与Tensor对象关联的.constant()方法。而

 ans = u*u.constant(5.);
 auto ans2 = u.sum(); 

正确编译和运行

ans = u*u.constant(v.sum());

没有。

error: no matching function for call to ‘Eigen::Tensor<float, 2>::constant(const Eigen::TensorReductionOp<Eigen::internal::SumReducer<float>, const Eigen::DimensionList<long int, 2ul>, const Eigen::Tensor<float, 2>, Eigen::MakePointer>)’
       ans = u*u.constant(v.sum());
                                 ^

从进一步阅读看来,这是因为 u.constant() 期望将标量值传递给它,而 v.sum() return 是 "non-evaluated expression"(参见 张量运算和 C++ "auto" README)。还有进一步的建议,可以使用 .eval() 强制评估 v.sum(),尽管这似乎 return 另一种 "non-evaluated expression" 类型,尽管在 ForcedEvalOp 上标记结束。

error: no matching function for call to ‘Eigen::Tensor<float, 2>::constant(const Eigen::TensorForcedEvalOp<const Eigen::TensorReductionOp<Eigen::internal::SumReducer<float>, const Eigen::DimensionList<long int, 2ul>, const Eigen::Tensor<float, 2>, Eigen::MakePointer> >)’
   ans = u*u.constant(v.sum().eval());
                                    ^

README 的 TODO 部分提到:

标量值的表示: 标量值通常由大小为 1 且秩为 1 的张量表示。使用秩为 0 的张量会更合乎逻辑且对用户更友好。例如 Tensor::maximum() 当前 return 是张量。类似地,2 个一维张量的内积(通过收缩)return 是一个一维张量。将来这些操作可能会更新为 return 0d 张量。"

这意味着 v.sum() 应该 return 一个长度为 1 的秩为 1 的张量。但是通常用于索引的 () 运算符似乎无法以可用的形式访问其值对于 u.constant() 和:

ans = u*u.constant(v.sum()(0))

同样编译失败

 error: no match for call to ‘(const Eigen::TensorReductionOp<Eigen::internal::SumReducer<float>, const Eigen::DimensionList<long int, 2ul>, const Eigen::Tensor<float, 2>, Eigen::MakePointer>) (int)’
   ans = u*u.constant(v.sum()(0));
                               ^

一样
ans = u*u.constant(v.sum().eval()(0))

.

error: no match for call to ‘(const Eigen::TensorForcedEvalOp<const Eigen::TensorReductionOp<Eigen::internal::SumReducer<float>, const Eigen::DimensionList<long int, 2ul>, const Eigen::Tensor<float, 2>, Eigen::MakePointer> >) (int)’
   ans = u*u.constant(v.sum().eval()(0));

根据this exchange,你应该可以通过赋值减少的结果来强制求值:

Eigen::Tensor<float, 0> vSum = v.sum();

这应该适用于您的线路:

ans = u * u.constant(vSum);

原因是,如果您尝试使用 v.sum() 直接调用模板方法 constant,它将尝试使用声明的返回类型 Scalar,这不会工作。 Eigen 使用了很多复杂的、本质上不透明的类型来最小化不必要的计算和复制,但也使用了很多模板,所以像在这种情况下那样必须显式强制类型转换并不少见。