Как умножить Собственный Тензор на скалярную сумму другого Собственного Тензора в C ++? - PullRequest
0 голосов
/ 18 сентября 2018

Я использую тензорный аспект библиотеки Eigen в C ++ и хотел бы вычислить поэлементное произведение одного собственного Tensor, умноженное на скалярную сумму элементов во втором Eigen Tensor.Что-то вроде:

#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 предлагает использовать метод .constant(), связанный с объектами Tensor.И хотя

 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() возвращает «не оцененное выражение» (см. Тензорные операциии C ++ "auto" in README ).Существует также предположение, что оценка v.sum() может быть принудительно вызвана с помощью .eval(), хотя это, похоже, возвращает другой тип «не оцененного выражения», хотя и с 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());
                                    ^

Раздел TODO README упоминает:

" Представление скалярных значений: Скалярные значения часто представлены тензорами размера 1 и ранга 1. Это будетболее логично и удобно использовать вместо этого тензоры ранга 0. Например, Tensor :: maximum () в настоящее время возвращает Tensor. Аналогично, внутреннее произведение 2 1d-тензоров (через сокращения) возвращает 1d-тензор. В будущем эти операции могутобновиться, чтобы вместо этого возвращались 0d-тензоры. "

Это означает, что v.sum() должен возвращать тензор ранга 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));

1 Ответ

0 голосов
/ 19 сентября 2018

Согласно этому обмену , вы должны быть в состоянии форсировать оценку, назначив результат сокращения:

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

Это должно работать с вашей линией:

ans = u * u.constant(vSum);

Причина этого заключается в том, что если вы попытаетесь вызвать метод шаблона constant напрямую с v.sum(), он попытается использовать объявленный тип возврата как Scalar, что не работает.Eigen использует много сложных, по существу непрозрачных типов, чтобы минимизировать ненужные вычисления и копирование, но также и множество шаблонов, так что не редкость необходимость явно приводить преобразования типов, как в этом случае.

...