Skip to content
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

Merged
merged 9 commits into from
Jul 19, 2017

Conversation

wangkuiyi
Copy link
Collaborator

@wangkuiyi wangkuiyi commented Jul 18, 2017

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.

input0.flat<T>() + input1.flat<T>();
framework::EigenVector<T>::From(*output).device(
*(context.GetEigenDevice<Place>())) =
framework::EigenVector<T>(*input0) + framework::EigenVector<T>(*input1);
Copy link
Member

@QiJune QiJune Jul 19, 2017

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.

Copy link
Collaborator Author

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!

}

EigenTensor<float, 3>::Type et = EigenTensor<float, 3>::From(t);
// TODO: check the content of et.
Copy link
Member

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));
  }

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>;
Copy link
Collaborator

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_.

Copy link
Member

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.

};

// Interpret paddle::platform::Tensor as EigenTensor and EigenConstTensor.
template <typename T, size_t D, typename IndexType = Eigen::DenseIndex>
Copy link
Collaborator

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.

Copy link
Member

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.


// Interpret paddle::platform::Tensor as EigenMatrix and EigenConstMatrix.
template <typename T, typename IndexType = Eigen::DenseIndex>
struct EigenMatrix {
Copy link
Collaborator

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>;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


// Interpret paddle::platform::Tensor as EigenVecotr and EigenConstVector.
template <typename T, typename IndexType = Eigen::DenseIndex>
struct EigenVector {
Copy link
Collaborator

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() {...}
};

Copy link
Member

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good TODO comment!

Copy link
Collaborator

@reyoung reyoung left a 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_))}));
Copy link
Collaborator

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.


TEST(EigenDim, From) {
EigenDim<3>::Type ed = EigenDim<3>::From(make_ddim({1, 2, 3}));
EXPECT_EQ(1, ed[0]);
Copy link
Collaborator

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());
Copy link
Collaborator

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.

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));
Copy link
Collaborator

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

EXPECT_EQ(6, ev.dimension(0));

for (int i = 0; i < 6; i++) {
EXPECT_EQ(i, ev(i));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASSERT_NEAR

Copy link
Member

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(
Copy link
Collaborator

@reyoung reyoung Jul 19, 2017

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;
};

@QiJune QiJune merged commit d810849 into PaddlePaddle:develop Jul 19, 2017
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(
Copy link
Collaborator Author

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>了?

Copy link
Collaborator

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(...);
};

应该就可以。

Copy link
Member

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.

@wangkuiyi wangkuiyi deleted the tensor_type_to_eigen branch July 21, 2017 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants