fc_op.cc 5.9 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
  if (ctx->HasInput("Bias")) {
    auto bias_dims = ctx->GetInputDim("Bias");
38 39 40 41 42 43 44 45
    if (bias_dims.size() == 2) {
      PADDLE_ENFORCE_EQ(bias_dims[0], 1, "The shape of Bias must be [1, dim].");
      PADDLE_ENFORCE_EQ(bias_dims[1], w_dims[1],
                        "The shape of Bias must be [1, dim].");
    } else if (bias_dims.size() == 1) {
      PADDLE_ENFORCE_EQ(bias_dims[0], w_dims[1],
                        "The shape of Bias must be [1, dim].");
    }
T
tensor-tang 已提交
46
  }
47
  PADDLE_ENFORCE(in_dims.size() == 2 || in_dims.size() == 4,
M
mozga-intel 已提交
48
                 "Fully Connected input should be 2-D or 4-D tensor.");
T
tensor-tang 已提交
49 50 51
  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 已提交
52 53
                    "Fully Connected input and weigth size do not match.");

54 55 56 57 58 59
  ctx->SetOutputDim("Out", framework::make_ddim(output_shape));
  ctx->ShareLoD("Input", "Out");
}

framework::OpKernelType FCOp::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
T
tensor-tang 已提交
60 61
  framework::LibraryType library = framework::LibraryType::kPlain;
  framework::DataLayout layout = framework::DataLayout::kAnyLayout;
T
tensor-tang 已提交
62
  if (ctx.Attr<bool>("use_mkldnn")) {
T
tensor-tang 已提交
63 64 65
    library = framework::LibraryType::kMKLDNN;
    layout = framework::DataLayout::kMKLDNN;
  }
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
  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 已提交
81 82

  if (ctx->HasInput("Bias")) {
T
tensor-tang 已提交
83 84
    PADDLE_ENFORCE(ctx->HasOutput(framework::GradVarName("Bias")),
                   "Should have bias grad");
T
tensor-tang 已提交
85 86 87
    auto bias_dims = ctx->GetInputDim("Bias");
    ctx->SetOutputDim(framework::GradVarName("Bias"), bias_dims);
  }
88 89 90 91
}

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

Y
Yu Yang 已提交
103
void FCOpMaker::Make() {
T
tensor-tang 已提交
104 105 106 107 108
  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 已提交
109
      .AsDispensable();
110
  AddOutput("Out", "(Tensor) The output tensor of fully connected operator. ");
111 112 113 114 115 116
  AddAttr<bool>("use_mkldnn",
                "(bool, default false) Only used in mkldnn kernel")
      .SetDefault(false);
  AddComment(R"DOC(
  Fully Connected Operator.

117
  The fully connected operation calculates the output based on the input, weights and bias.
118 119 120 121
  The size of each dimension of the parameters checked in the infer-shape.
)DOC");
}

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

    const T* input_data = input->data<T>();
    const T* w_data = w->data<T>();
    T* output_data = output->mutable_data<T>(ctx.GetPlace());
138 139 140 141
    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 已提交
142 143

    // TODO(TJ): fuse act
T
tensor-tang 已提交
144 145 146
  }
};

147 148 149
}  // namespace operators
}  // namespace paddle

T
tensor-tang 已提交
150 151
namespace ops = paddle::operators;
REGISTER_OPERATOR(fc, ops::FCOp, ops::FCOpMaker,
152
                  paddle::framework::DefaultGradOpDescMaker<true>);
T
tensor-tang 已提交
153
REGISTER_OPERATOR(fc_grad, ops::FCOpGrad);
T
tensor-tang 已提交
154
REGISTER_OP_CPU_KERNEL(fc, ops::FCOpKernel<float>, ops::FCOpKernel<double>);