fc_op.cc 5.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/operators/fc_op.h"
16
#include <vector>
T
tensor-tang 已提交
17
#include "paddle/fluid/operators/math/blas.h"
18
#include "paddle/fluid/operators/math/fc_compute.h"
T
tensor-tang 已提交
19

20 21 22 23 24 25 26 27 28 29
namespace paddle {
namespace operators {

void FCOp::InferShape(framework::InferShapeContext* ctx) const {
  PADDLE_ENFORCE(ctx->HasInput("Input"),
                 "X(Input) of Fully Connected should not be null.");
  PADDLE_ENFORCE(ctx->HasOutput("Out"),
                 "Out(Output) of Fully Connected should not be null.");
  PADDLE_ENFORCE(ctx->HasInput("W"),
                 "W(Input) of Fully Connected should not be null.");
T
tensor-tang 已提交
30
  // NCHW
31
  auto in_dims = ctx->GetInputDim("Input");
T
tensor-tang 已提交
32
  // IO, I=C*H*W
33 34 35
  auto w_dims = ctx->GetInputDim("W");
  std::vector<int64_t> output_shape({in_dims[0], w_dims[1]});

T
tensor-tang 已提交
36 37 38
  if (ctx->HasInput("Bias")) {
    auto bias_dims = ctx->GetInputDim("Bias");
    PADDLE_ENFORCE_EQ(bias_dims[0], 1, "The shape of Bias must be [1, dim].");
T
tensor-tang 已提交
39
    PADDLE_ENFORCE_EQ(bias_dims[1], w_dims[1],
T
tensor-tang 已提交
40 41
                      "The shape of Bias must be [1, dim].");
  }
42
  PADDLE_ENFORCE(in_dims.size() == 2 || in_dims.size() == 4,
M
mozga-intel 已提交
43
                 "Fully Connected input should be 2-D or 4-D tensor.");
T
tensor-tang 已提交
44 45 46
  PADDLE_ENFORCE_EQ(w_dims.size(), 2UL,
                    "Fully Connected input should be 2-D tensor.");
  PADDLE_ENFORCE_EQ(framework::product(in_dims) / in_dims[0], w_dims[0],
T
tensor-tang 已提交
47 48
                    "Fully Connected input and weigth size do not match.");

49 50 51 52 53 54
  ctx->SetOutputDim("Out", framework::make_ddim(output_shape));
  ctx->ShareLoD("Input", "Out");
}

framework::OpKernelType FCOp::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
T
tensor-tang 已提交
55 56
  framework::LibraryType library = framework::LibraryType::kPlain;
  framework::DataLayout layout = framework::DataLayout::kAnyLayout;
T
tensor-tang 已提交
57
  if (ctx.Attr<bool>("use_mkldnn")) {
T
tensor-tang 已提交
58 59 60
    library = framework::LibraryType::kMKLDNN;
    layout = framework::DataLayout::kMKLDNN;
  }
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
  return framework::OpKernelType(
      framework::ToDataType(ctx.Input<Tensor>("Input")->type()), ctx.GetPlace(),
      layout, library);
}

void FCOpGrad::InferShape(framework::InferShapeContext* ctx) const {
  auto in_dims = ctx->GetInputDim("Input");
  auto w_dims = ctx->GetInputDim("W");

  if (ctx->HasOutput(framework::GradVarName("Input"))) {
    ctx->SetOutputDim(framework::GradVarName("Input"), in_dims);
  }
  if (ctx->HasOutput(framework::GradVarName("W"))) {
    ctx->SetOutputDim(framework::GradVarName("W"), w_dims);
  }
T
tensor-tang 已提交
76 77

  if (ctx->HasInput("Bias")) {
T
tensor-tang 已提交
78 79
    PADDLE_ENFORCE(ctx->HasOutput(framework::GradVarName("Bias")),
                   "Should have bias grad");
T
tensor-tang 已提交
80 81 82
    auto bias_dims = ctx->GetInputDim("Bias");
    ctx->SetOutputDim(framework::GradVarName("Bias"), bias_dims);
  }
83 84 85 86
}

framework::OpKernelType FCOpGrad::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
T
tensor-tang 已提交
87 88
  framework::LibraryType library = framework::LibraryType::kPlain;
  framework::DataLayout layout = framework::DataLayout::kAnyLayout;
T
tensor-tang 已提交
89
  if (ctx.Attr<bool>("use_mkldnn")) {
T
tensor-tang 已提交
90 91 92
    library = framework::LibraryType::kMKLDNN;
    layout = framework::DataLayout::kMKLDNN;
  }
93 94 95 96 97
  return framework::OpKernelType(
      framework::ToDataType(ctx.Input<Tensor>("Input")->type()), ctx.GetPlace(),
      layout, library);
}

Y
Yu Yang 已提交
98
void FCOpMaker::Make() {
T
tensor-tang 已提交
99 100 101 102 103
  AddInput("Input",
           "(Tensor), The input tensor of fully connected operator with format "
           "(NCHW). ");
  AddInput("W", "(Tensor), The weight fc op with shape (I, O).");
  AddInput("Bias", "(Tensor, optional) Bias vector with shape (1 x O")
T
tensor-tang 已提交
104
      .AsDispensable();
105
  AddOutput("Out", "(Tensor) The output tensor of fully connected operator. ");
106 107 108 109 110 111
  AddAttr<bool>("use_mkldnn",
                "(bool, default false) Only used in mkldnn kernel")
      .SetDefault(false);
  AddComment(R"DOC(
  Fully Connected Operator.

112
  The fully connected operation calculates the output based on the input, weights and bias.
113 114 115 116
  The size of each dimension of the parameters checked in the infer-shape.
)DOC");
}

T
tensor-tang 已提交
117 118 119 120
template <typename T>
class FCOpKernel : public framework::OpKernel<T> {
 public:
  void Compute(const paddle::framework::ExecutionContext& ctx) const override {
T
tensor-tang 已提交
121
    PADDLE_ENFORCE(platform::is_cpu_place(ctx.GetPlace()),
T
tensor-tang 已提交
122 123 124
                   "It must use CPUPlace.");
    auto input = ctx.Input<Tensor>("Input");
    auto w = ctx.Input<Tensor>("W");
T
tensor-tang 已提交
125
    auto bias = ctx.Input<Tensor>("Bias");
T
tensor-tang 已提交
126
    auto output = ctx.Output<Tensor>("Out");
T
tensor-tang 已提交
127 128
    auto in_dims = input->dims();
    auto w_dims = w->dims();
T
tensor-tang 已提交
129 130 131 132

    const T* input_data = input->data<T>();
    const T* w_data = w->data<T>();
    T* output_data = output->mutable_data<T>(ctx.GetPlace());
133 134 135 136
    auto blas = math::GetBlas<platform::CPUDeviceContext, T>(ctx);
    math::FCCompute<platform::CPUDeviceContext, T>(
        blas, in_dims[0], w_dims[1], w_dims[0], input_data, w_data, output_data,
        bias ? bias->data<T>() : NULL);
T
tensor-tang 已提交
137 138 139
  }
};

140 141 142
}  // namespace operators
}  // namespace paddle

T
tensor-tang 已提交
143 144
namespace ops = paddle::operators;
REGISTER_OPERATOR(fc, ops::FCOp, ops::FCOpMaker,
145
                  paddle::framework::DefaultGradOpDescMaker<true>);
T
tensor-tang 已提交
146
REGISTER_OPERATOR(fc_grad, ops::FCOpGrad);
T
tensor-tang 已提交
147
REGISTER_OP_CPU_KERNEL(fc, ops::FCOpKernel<float>, ops::FCOpKernel<double>);