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

LoDTensor in operators. #4151

Closed
qingqing01 opened this issue Sep 18, 2017 · 6 comments
Closed

LoDTensor in operators. #4151

qingqing01 opened this issue Sep 18, 2017 · 6 comments
Assignees

Comments

@qingqing01
Copy link
Contributor

qingqing01 commented Sep 18, 2017

关于LoDTensor在operator里的用法,合入#4083 之后, 对于非sequence operators使用,需要注意:

  1. 只需要在InferShape里对输出用: Output<framework::LoDTensor>
  2. Input以及operator kernel里还可继续用Tensor

SigmoidOp举例:

class SigmoidOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

 protected:
  void InferShape(const framework::InferShapeContext &ctx) const override {
    PADDLE_ENFORCE_NOT_NULL(ctx.InputVar("X"),
                            "Input(X) of SigmoidOp should not be null.");
    PADDLE_ENFORCE_NOT_NULL(ctx.OutputVar("Y"),
                            "Output(Y) of SigmoidOp should not be null.");

    ctx.Output<framework::LoDTensor>("Y")->Resize(
        ctx.Input<Tensor>("X")->dims());
  }
};

SigmoidKernel:

template <typename Place, typename T>
class SigmoidKernel : public framework::OpKernel {
 public:
  void Compute(const framework::ExecutionContext& context) const override {
    auto input = context.Input<Tensor>("X");
    auto output = context.Output<Tensor>("Y");
    output->mutable_data<T>(context.GetPlace());

    // The clipping is used in Paddle's raw implenmention
    auto X = EigenVector<T>::Flatten(*input);
    auto Y = EigenVector<T>::Flatten(*output);
    auto place = context.GetEigenDevice<Place>();

    Y.device(place) = 1. / (1. + (-X).exp());
  }
};

有同学觉得一些地方使用LoDTensor, 一些地方用Tensor,这样有点晕,大家怎么看?

如果要改的话,有两种方式:

  1. 所有operator的任何地方都用LoDTenor,(王益老师也强调,LoDTensor是我们的一个特点)

    • 会导致所有operators,即使非sequence operators,任何地方都感知LoDTensor.
  2. InferShapeContext::Output<T>(const std::string& name)函数对Tensor特化,GetMutable<LoDTensor>始终使用LoDTensor:

    • 会导致通过InferShapeContext::Output<Tensor>()永远无法在scope里创造出Tensor.
  template <>
  Tensor* ExecutionContext::Output<Tensor>(const std::string& name) const {
    auto* var = OutputVar(name);
    return var == nullptr ? nullptr : var->GetMutable<LoDTensor>();
  }

大家有什么建议吗?

@jacquesqiao
Copy link
Member

Output<framework::LoDTensor>

请教下Output为什么一定要是 LodTensor

@qingqing01
Copy link
Contributor Author

qingqing01 commented Sep 18, 2017

@jacquesqiao 上面comments确实没有解释为什么要使用Output<framework::LoDTensor>

InferShapeContext::Output<T>(const std::string& name) 函数如下:

  template <typename T>
  T* Output(const std::string& name) const {
    auto var = OutputVar(name);
    return var == nullptr ? nullptr : var->GetMutable<T>();
  }

这里调用Variable::GetMutable<T>()函数:

  template <typename T>
  T* GetMutable() {
    if (!IsType<T>()) {
      holder_.reset(new PlaceholderImpl<T>(new T()));
    }
    return static_cast<T*>(holder_->Ptr());
  }

第一次调用InferShape函数时,输出var里还没有创建任何类型,var里的holder_为空,GetMutable会给var里创建T类型,现在约定我们operators输入输出都是LoDTensor,所以必需调用Output<framework::LoDTensor>.

@hedaoyuan
Copy link
Contributor

hedaoyuan commented Sep 18, 2017

将非sequence operators的Op输入输出构造成LoDTensor的主要目的是为了传递sequence信息,但这些Op的计算都是不需要感知LoDTensor类型的。所以,我倾向于,对于不用感知LoDTenor类型的Op里面不需要出现LoDTenor(包括在Op,Op.InferShape,OpKernel的实现中),比如矩阵乘法Op,elementwise Op等。

  1. 对于使用variable时,可以考虑在这些Op的InferShape, Kernel中按照Tensor类型从context中去获取输入输出(上面SigmoidKernel例子中就是在使用variable时用Tensro类型来get的例子)。
  2. 而对于variable的创建逻辑,比如上述SigmoidOp.InferShape例子中的output Y的创建。这里可以考虑在InferShapeContext中实例化Output<framework::Tensor>的实现,对T=Tensor时也是在variable中构造一个LoDTensor,这样就可以避免在非sequence operators中出现LoDTensor了。

@jacquesqiao
Copy link
Member

jacquesqiao commented Sep 18, 2017

现状理解:

  1. 隐含约束是所有Tensor必须初始化成 LodTensor
  2. 如果已经初始化成LodTensor,那么后面可以用 Get 拿到一个Tensor类型,但实际上底层依然是LodTensor(因为是继承关系)

问题:

  1. 我印象中LodTensor和Tensor后面会用组合的方式来实现,这个继承关系后面会不存在?
  2. 我支持道远的说法,Variable在初始化的时候,如果发现还没有类型,并且要求的type是tensor,则自动创建LodTensor类型,用户无需感知。

@hedaoyuan
Copy link
Contributor

@Superjom 我看了一下你上面comment中的三个链接,好像只有第一个链接中的现有代码迁移一节是跟这个issue相关的,不过没看明白你的倾向是什么?这个issue主要讨论的就是 @qingqing01 第一个comment中的1,2两点,你可以给出自己的看法,倾向于哪一种实现。

@Superjomn
Copy link
Contributor

不是LoD 传递相关的吗? fc(lodtensor as tensor) -> lodtensor ?

如果不是这个问题或者只是选择题请忽略。
@hedaoyuan

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

No branches or pull requests

6 participants