提交 f3669ca3 编写于 作者: H hedaoyuan

Support input_grad = null or filter_grad = null.

上级 64b0b756
...@@ -28,6 +28,13 @@ class Conv2DOp : public framework::OperatorWithKernel { ...@@ -28,6 +28,13 @@ class Conv2DOp : public framework::OperatorWithKernel {
protected: protected:
void InferShape(const framework::InferShapeContext &ctx) const override { void InferShape(const framework::InferShapeContext &ctx) const override {
PADDLE_ENFORCE_NOT_NULL(ctx.InputVar("Input"),
"Input(Input) of Conv2DOp should not be null.");
PADDLE_ENFORCE_NOT_NULL(ctx.InputVar("Filter"),
"Input(Filter) of Conv2DOp should not be null.");
PADDLE_ENFORCE_NOT_NULL(ctx.OutputVar("Output"),
"Output(Output) of Conv2DOp should not be null.");
auto in = ctx.Input<Tensor>("Input"); auto in = ctx.Input<Tensor>("Input");
auto filter = ctx.Input<Tensor>("Filter"); auto filter = ctx.Input<Tensor>("Filter");
auto out = ctx.Output<framework::LoDTensor>("Output"); auto out = ctx.Output<framework::LoDTensor>("Output");
...@@ -108,8 +115,8 @@ class Conv2DOpGrad : public framework::OperatorWithKernel { ...@@ -108,8 +115,8 @@ class Conv2DOpGrad : public framework::OperatorWithKernel {
ctx.Output<framework::LoDTensor>(framework::GradVarName("Input")); ctx.Output<framework::LoDTensor>(framework::GradVarName("Input"));
auto d_filter = auto d_filter =
ctx.Output<framework::LoDTensor>(framework::GradVarName("Filter")); ctx.Output<framework::LoDTensor>(framework::GradVarName("Filter"));
d_in->Resize(in->dims()); if (d_in) d_in->Resize(in->dims());
d_filter->Resize(filter->dims()); if (d_filter) d_filter->Resize(filter->dims());
} }
}; };
......
...@@ -111,14 +111,16 @@ class GemmConvGrad2DKernel : public framework::OpKernel { ...@@ -111,14 +111,16 @@ class GemmConvGrad2DKernel : public framework::OpKernel {
context.Output<Tensor>(framework::GradVarName("Input")); context.Output<Tensor>(framework::GradVarName("Input"));
Tensor* filter_grad_ = Tensor* filter_grad_ =
context.Output<Tensor>(framework::GradVarName("Filter")); context.Output<Tensor>(framework::GradVarName("Filter"));
input_grad->mutable_data<T>(context.GetPlace());
filter_grad_->mutable_data<T>(context.GetPlace());
// The filter and filter_grad will be reshaped in the calculations, // The filter and filter_grad will be reshaped in the calculations,
// so here use an assignment operation, // so here use an assignment operation,
// that avoids modifying the variable in the Scope. // that avoids modifying the variable in the Scope.
Tensor filter = *context.Input<Tensor>("Filter"); Tensor filter = *context.Input<Tensor>("Filter");
Tensor filter_grad = *filter_grad_; Tensor filter_grad;
if (filter_grad_) {
filter_grad_->mutable_data<T>(context.GetPlace());
filter_grad = *filter_grad_;
}
std::vector<int> strides = context.Attr<std::vector<int>>("strides"); std::vector<int> strides = context.Attr<std::vector<int>>("strides");
std::vector<int> paddings = context.Attr<std::vector<int>>("paddings"); std::vector<int> paddings = context.Attr<std::vector<int>>("paddings");
...@@ -162,12 +164,20 @@ class GemmConvGrad2DKernel : public framework::OpKernel { ...@@ -162,12 +164,20 @@ class GemmConvGrad2DKernel : public framework::OpKernel {
framework::DDim filter_matrix_shape = {filter.dims()[0], framework::DDim filter_matrix_shape = {filter.dims()[0],
filter.numel() / filter.dims()[0]}; filter.numel() / filter.dims()[0]};
filter.Resize(filter_matrix_shape); filter.Resize(filter_matrix_shape);
filter_grad.Resize(filter_matrix_shape);
auto t1 = framework::EigenVector<T>::Flatten(filter_grad); if (filter_grad_) {
t1.device(context.GetEigenDevice<Place>()) = t1.constant(static_cast<T>(0)); filter_grad.Resize(filter_matrix_shape);
auto t2 = framework::EigenVector<T>::Flatten(*input_grad); auto t1 = framework::EigenVector<T>::Flatten(filter_grad);
t2.device(context.GetEigenDevice<Place>()) = t2.constant(static_cast<T>(0)); t1.device(context.GetEigenDevice<Place>()) =
t1.constant(static_cast<T>(0));
}
if (input_grad) {
input_grad->mutable_data<T>(context.GetPlace());
auto t2 = framework::EigenVector<T>::Flatten(*input_grad);
t2.device(context.GetEigenDevice<Place>()) =
t2.constant(static_cast<T>(0));
}
auto* device_context = auto* device_context =
const_cast<platform::DeviceContext*>(context.device_context_); const_cast<platform::DeviceContext*>(context.device_context_);
...@@ -176,35 +186,47 @@ class GemmConvGrad2DKernel : public framework::OpKernel { ...@@ -176,35 +186,47 @@ class GemmConvGrad2DKernel : public framework::OpKernel {
// convolution backward weight operator: im2col + gemm // convolution backward weight operator: im2col + gemm
int in_step = input_channels / groups; int in_step = input_channels / groups;
int out_step = output_channels / groups; int out_step = output_channels / groups;
Tensor in_grad_batch;
Tensor in_batch;
for (int i = 0; i < batch_size; i++) { for (int i = 0; i < batch_size; i++) {
Tensor out_grad_batch = Tensor out_grad_batch =
output_grad->Slice<T>(i, i + 1).Resize(output_matrix_shape); output_grad->Slice<T>(i, i + 1).Resize(output_matrix_shape);
Tensor in_grad_batch = input_grad->Slice<T>(i, i + 1).Resize(input_shape); if (input_grad) {
Tensor in_batch = input->Slice<T>(i, i + 1).Resize(input_shape); in_grad_batch = input_grad->Slice<T>(i, i + 1).Resize(input_shape);
}
if (filter_grad_) {
in_batch = input->Slice<T>(i, i + 1).Resize(input_shape);
}
for (int g = 0; g < groups; g++) { for (int g = 0; g < groups; g++) {
// gemm
Tensor out_grad_slice = Tensor out_grad_slice =
out_grad_batch.Slice<T>(g * out_step, (g + 1) * out_step); out_grad_batch.Slice<T>(g * out_step, (g + 1) * out_step);
Tensor filter_slice = filter.Slice<T>(g * out_step, (g + 1) * out_step); if (input_grad) {
math::matmul<Place, T>(filter_slice, true, out_grad_slice, false, // gemm
T(1.0), &col_matrix, T(0.0), device_context); Tensor filter_slice =
filter.Slice<T>(g * out_step, (g + 1) * out_step);
// col2im math::matmul<Place, T>(filter_slice, true, out_grad_slice, false,
Tensor in_grad_slice = T(1.0), &col_matrix, T(0.0), device_context);
in_grad_batch.Slice<T>(g * in_step, (g + 1) * in_step);
col2im(in_grad_slice, col, strides[0], strides[1], paddings[0], // col2im
paddings[1], device_context); Tensor in_grad_slice =
in_grad_batch.Slice<T>(g * in_step, (g + 1) * in_step);
// im2col col2im(in_grad_slice, col, strides[0], strides[1], paddings[0],
Tensor in_slice = in_batch.Slice<T>(g * in_step, (g + 1) * in_step); paddings[1], device_context);
im2col(in_slice, col, strides[0], strides[1], paddings[0], paddings[1], }
device_context);
if (filter_grad_) {
// gemm // im2col
Tensor filter_grad_slice = Tensor in_slice = in_batch.Slice<T>(g * in_step, (g + 1) * in_step);
filter_grad.Slice<T>(g * out_step, (g + 1) * out_step); im2col(in_slice, col, strides[0], strides[1], paddings[0],
math::matmul<Place, T>(out_grad_slice, false, col_matrix, true, T(1.0), paddings[1], device_context);
&filter_grad_slice, T(1.0), device_context);
// gemm
Tensor filter_grad_slice =
filter_grad.Slice<T>(g * out_step, (g + 1) * out_step);
math::matmul<Place, T>(out_grad_slice, false, col_matrix, true,
T(1.0), &filter_grad_slice, T(1.0),
device_context);
}
} }
} }
} }
......
...@@ -75,6 +75,12 @@ class TestConv2dOp(OpTest): ...@@ -75,6 +75,12 @@ class TestConv2dOp(OpTest):
def test_check_grad(self): def test_check_grad(self):
self.check_grad(set(['Input', 'Filter']), 'Output') self.check_grad(set(['Input', 'Filter']), 'Output')
def test_check_grad_no_filter(self):
self.check_grad(['Input'], 'Output', no_grad_set=set(['Filter']))
def test_check_grad_no_input(self):
self.check_grad(['Filter'], 'Output', no_grad_set=set(['Input']))
def init_groups(self): def init_groups(self):
self.groups = 1 self.groups = 1
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册