Conversation
paddle/operators/clip_op.cu
Outdated
| template <typename T> | ||
| __global__ void ClipGradientKernel(const int N, const T min, const T max, | ||
| const T* Y, const T* dY, T* dX) { | ||
| CUDA_1D_KERNEL_LOOP(i, N) { dX[i] = dY[i] * (Y[i] > min && Y[i] < max); } |
There was a problem hiding this comment.
This implementation depends on true is 1 in C++ and CUDA. It is not good.
reyoung
left a comment
There was a problem hiding this comment.
Well done. It seems that Relu is an alias of Clipping Operator with min=0.0, max=+inf. To alias an operator, please reference identity_op
paddle/operators/clip_op.cc
Outdated
| AddInput("X", "The input of clip op"); | ||
| AddOutput("Out", "The output of clip op"); | ||
| AddComment(R"DOC( | ||
| Clip Operator. |
There was a problem hiding this comment.
paddle/operators/clip_op.cc
Outdated
| Clip Operator. | ||
| )DOC"); | ||
| AddAttr<float>("min", "min value to be clipped."); | ||
| AddAttr<float>("max", "max value to be clipped."); |
There was a problem hiding this comment.
AddAttr放在DOC前面吧,min、max也需要类型模板,参考: https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/scale_op.cc#L36
There was a problem hiding this comment.
一个op的多个attrs的类型必须一样么?
| void InferShape(const framework::InferShapeContext &ctx) const override { | ||
| PADDLE_ENFORCE_NOT_NULL(ctx.InputVar("X"), "Input(X) should not be null"); | ||
| PADDLE_ENFORCE_NOT_NULL(ctx.InputVar(framework::GradVarName("Out")), | ||
| "Input(Out@GRAD) should not be null"); |
There was a problem hiding this comment.
The check is also needed in ClipOp.
paddle/operators/clip_op.cc
Outdated
| auto max = Attr<float>("max"); | ||
| auto min = Attr<float>("min"); | ||
| PADDLE_ENFORCE_LT(min, max, "max should be greater than min."); | ||
| ctx.Output<Tensor>("Out")->Resize(x_dims); |
There was a problem hiding this comment.
Output< framework::LoDTensor>
paddle/operators/clip_op.cc
Outdated
| PADDLE_ENFORCE_NOT_NULL(ctx.InputVar(framework::GradVarName("Out")), | ||
| "Input(Out@GRAD) should not be null"); | ||
| auto x_dims = ctx.Input<Tensor>("X")->dims(); | ||
| auto *x_grad = ctx.Output<Tensor>(framework::GradVarName("X")); |
There was a problem hiding this comment.
Output< framework::LoDTensor>
paddle/operators/clip_op.cu
Outdated
| public: | ||
| void Compute(const framework::ExecutionContext& context) const override { | ||
| auto max = context.op().Attr<float>("max"); | ||
| auto min = context.op().Attr<float>("min"); |
There was a problem hiding this comment.
context.op().Attr<> -> context.Attr<>
paddle/operators/clip_op.cu
Outdated
| size_t count = 1; | ||
| for (int i = 0; i < dims.size(); ++i) { | ||
| count *= dims[i]; | ||
| } |
There was a problem hiding this comment.
int64_t count = dims->numel()
paddle/operators/clip_op.cu
Outdated
| int block = 512; | ||
| int grid = (N * D + block - 1) / block; | ||
|
|
||
| ClipGradientKernel<T><<<grid, block>>>(count, min, max, x_data, d_out_data, |
There was a problem hiding this comment.
Need to use CUDA stream when launching kernel. Please refer to im2col.cu in paddle/operator/math.
paddle/operators/clip_op.h
Outdated
| size_t count = 1; | ||
| for (int i = 0; i < dims.size(); ++i) { | ||
| count *= dims[i]; | ||
| } |
| import numpy as np | ||
| from paddle.v2.framework.op import Operator | ||
| from gradient_checker import GradientChecker | ||
| from op_test_util import OpTestMeta |
There was a problem hiding this comment.
Use the new unit testing framework.
2. Fix unitest. 3. Fix comments and some issues. Merge branch 'develop' of https://github.com/PaddlePaddle/Paddle into clip_op
paddle/operators/clip_op.cc
Outdated
| auto x_dims = ctx.Input<LoDTensor>("X")->dims(); | ||
| auto *x_grad = ctx.Output<LoDTensor>(framework::GradVarName("X")); | ||
|
|
||
| x_grad->Resize(x_dims); |
There was a problem hiding this comment.
Check whether x_grad is nullptr before it is resized.
paddle/operators/clip_op.cu
Outdated
| if (Y[i] > min && Y[i] < max) { | ||
| dX[i] = dY[i]; | ||
| } else { | ||
| dX[i] = 0; |
There was a problem hiding this comment.
clip to 0 or min / max ?
There was a problem hiding this comment.
It's the gradient computation. Please refer ClipGradientOp of caffe2
paddle/operators/clip_op.cu
Outdated
| auto* x = context.Input<LoDTensor>("X"); | ||
| auto dims = d_x->dims(); | ||
| int64_t count = d_out->numel(); | ||
| auto d_x_data = d_x->mutable_data<T>(context.GetPlace()); |
There was a problem hiding this comment.
Why not just d_x->mutable_data<T>(context.GetPlace()) and keep using d_x?
There was a problem hiding this comment.
d_x_data is needed by ClipGradientKernel
There was a problem hiding this comment.
I mean d_x_data and d_x they are totally same. They point to the same memory.
paddle/operators/clip_op.cu
Outdated
| int D = d_x->dims()[1]; | ||
| int block = 512; | ||
| int grid = (N * D + block - 1) / block; | ||
| ClipGradientKernel<T><<< |
There was a problem hiding this comment.
This implement is too complex. @reyoung provids a global function transform to apply a functor to every elements in an iterable object.
See https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/platform/transform.h
It works on both CPU and GPU.
Here is a demo of how to use it: https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/prelu_op.h#L57
paddle/operators/clip_op.h
Outdated
| auto x_tensor = EigenTensor<T, D>::From(*x); | ||
| auto out_tensor = EigenTensor<T, D>::From(*out); | ||
| auto place = context.GetEigenDevice<Place>(); | ||
| out_tensor.device(place) = x_tensor.cwiseMin(max).cwiseMax(min); |
There was a problem hiding this comment.
transform() can also be used here. With it, there is no necessity to use Eigen and we can get rid of template parameter size_t D.
paddle/operators/clip_op.h
Outdated
| if (y > min_ && y < max_) | ||
| return x; | ||
| else | ||
| return 0; |
There was a problem hiding this comment.
return y > min_ && y < max_ ? x : 0;
paddle/operators/clip_op.h
Outdated
| auto* out = context.Output<Tensor>("Out"); | ||
| T* out_data = out->mutable_data<T>(context.GetPlace()); | ||
| const T* x_data = x->data<T>(); | ||
| int numel = x->numel(); |
paddle/operators/clip_op.h
Outdated
| if (d_x != nullptr) { | ||
| auto* x = context.Input<Tensor>("X"); | ||
| int64_t numel = d_out->numel(); | ||
| auto d_x_data = d_x->mutable_data<T>(context.GetPlace()); |
There was a problem hiding this comment.
d_x_data is a pointer, so please use auto*
fix #3910