-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactorize Tensor to Eigen convesion #2953
Conversation
paddle/operators/add_op.h
Outdated
input0.flat<T>() + input1.flat<T>(); | ||
framework::EigenVector<T>::From(*output).device( | ||
*(context.GetEigenDevice<Place>())) = | ||
framework::EigenVector<T>(*input0) + framework::EigenVector<T>(*input1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line should be
framework::EigenTensor<T, rank>::From(*output).device(
*(context.GetEigenDevice<Place>())) =
framework::EigenTensor<T, rank>::From(input0)+
framework::EigenTensor<T, rank>::From(input1);
But we could not get the template parameter rank. So, we need a flatten method to reshape a tensor with multi-dimension into one dimension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I understand that we need Flatten. I just didn't have enough time today to add it. If would be great if you can take this PR and go on finishing it. Thanks!
paddle/framework/eigen_test.cc
Outdated
} | ||
|
||
EigenTensor<float, 3>::Type et = EigenTensor<float, 3>::From(t); | ||
// TODO: check the content of et. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check can be:
for (int i = 0; i < 1 * 2 * 3; i++) {
EXPECT_EQ(et(i), static_cast<float>(i));
}
paddle/framework/eigen.h
Outdated
template <typename T, size_t D, typename IndexType = Eigen::DenseIndex> | ||
struct EigenTensor { | ||
using Type = Eigen::TensorMap<Eigen::Tensor<T, D, Eigen::RowMajor, IndexType>, | ||
Eigen::Aligned>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot think all memory is aligned even our memory allocator is aligned because we could invoke Tensor::Slice or change Tensor::offset_.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and now, make EigenTensor default unaligned.
And we will make a benchmark between aligned and unaligned version in future.
paddle/framework/eigen.h
Outdated
}; | ||
|
||
// Interpret paddle::platform::Tensor as EigenTensor and EigenConstTensor. | ||
template <typename T, size_t D, typename IndexType = Eigen::DenseIndex> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, even our default configuration is RowMajor
, but we could also make RowMajor
to here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Just make RowMajor default.
paddle/framework/eigen.h
Outdated
|
||
// Interpret paddle::platform::Tensor as EigenMatrix and EigenConstMatrix. | ||
template <typename T, typename IndexType = Eigen::DenseIndex> | ||
struct EigenMatrix { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not
template <typename T, typename IndexType = Eigen::DenseIndex>
using EigenMatrix = EigenTensor<T, 2, IndexType>;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
paddle/framework/eigen.h
Outdated
|
||
// Interpret paddle::platform::Tensor as EigenVecotr and EigenConstVector. | ||
template <typename T, typename IndexType = Eigen::DenseIndex> | ||
struct EigenVector { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not
template <typename T, typename IndexType = Eigen::DenseIndex>
class EigenVector: public EigenTensor<T, 1, IndexType> {
Flatten() {...}
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
template <typename T, size_t D, int MajorType = Eigen::RowMajor, | ||
typename IndexType = Eigen::DenseIndex> | ||
struct EigenTensor { | ||
// TODO(qijun) Now, default type in unaligned, and we will make a benchmark on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good TODO comment!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically LGTM, but please do not compare float value with ==
or EQ
. That will unit-test failed in some situation. Please change that before merge.
// Flatten is to reshape a Tensor into a one dimension EigenVector | ||
static typename EigenTensor<T, 1>::Type Flatten(Tensor& tensor) { | ||
return EigenTensor<T, 1>::From( | ||
tensor, make_ddim({static_cast<int>(product(tensor.dims_))})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tensor, {static_cast<int>(product(tensor.dims_)))}
is enough. But it does not matter.
paddle/framework/eigen_test.cc
Outdated
|
||
TEST(EigenDim, From) { | ||
EigenDim<3>::Type ed = EigenDim<3>::From(make_ddim({1, 2, 3})); | ||
EXPECT_EQ(1, ed[0]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should prefer ASSERT_XXX
than EXPECT_XXX
, because ASSERT_XXX
die soon.
|
||
TEST(Eigen, Tensor) { | ||
Tensor t; | ||
float* p = t.mutable_data<float>(make_ddim({1, 2, 3}), platform::CPUPlace()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use {1, 2, 3}
now, make_ddim
is a little noising.
paddle/framework/eigen_test.cc
Outdated
for (int i = 0; i < 1; i++) { | ||
for (int j = 0; j < 2; j++) { | ||
for (int k = 0; k < 3; k++) { | ||
EXPECT_EQ((i * 2 + j) * 3 + k, et(i, j, k)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never use EQ
on float
type. Use ASSERT_NEAR instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
paddle/framework/eigen_test.cc
Outdated
EXPECT_EQ(6, ev.dimension(0)); | ||
|
||
for (int i = 0; i < 6; i++) { | ||
EXPECT_EQ(i, ev(i)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ASSERT_NEAR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -29,8 +30,10 @@ class AddKernel : public framework::OpKernel { | |||
|
|||
output->mutable_data<T>(context.GetPlace()); | |||
|
|||
output->flat<T>().device(*(context.GetEigenDevice<Place>())) = | |||
input0.flat<T>() + input1.flat<T>(); | |||
framework::EigenVector<T>::Flatten(*output).device( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very noising code for implement kernel. Maybe we should think a better way after this PR.
Maybe that way is OK?
struct OpKernelUseEigen : public framework::OpKernel {
protected:
template <typename T>
using Flatten = framework::EigenVector<T>::Flatten;
};
struct EigenVector : public EigenTensor<T, 1, MajorType, IndexType> { | ||
// Flatten is to reshape a Tensor into a one dimension EigenVector | ||
static typename EigenTensor<T, 1>::Type Flatten(Tensor& tensor) { | ||
return EigenTensor<T, 1>::From( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flatten
的return typeEigenTensor<T,1>
实际上是 EigenTensor<T, 1, Eigen::RowMajor, Eigen::DenseIndex>
。而EigenVector被specialized的时候,可能用户传进来的template parameters不是 RowMajor和DenseIndex。结果就可能是用户写:
auto et = EigenVector<float, Eigen::ColumnMajor, Eigen:SparseIndex>::Flatten(t);
的时候,心里期待 et
的类型是 EigenTensor<float, 1, ColumnMajor, SparseIndex>
,但是实际上是 EigenTensor<float, 1, RowMajor, DenseIndex>
了?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
对,这里bug了。。
struct EigenVector : public EigenTensor<T, 1, MajorType, IndexType> {
Type Flatten(...);
};
应该就可以。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wangkuiyi Yes, Got it! I am fixing it now.
Fixes #2952.
I rewrote the interpretation of Tensor as Eigen::TensorMap. It seems that the amount of source code can be significantly reduce. Also, code can be put together other than scattered around in multiple source files.