fc_op.cc 6.8 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
Tao Luo 已提交
30

31 32 33
  auto in_dims = ctx->GetInputDim("Input");
  auto w_dims = ctx->GetInputDim("W");

T
tensor-tang 已提交
34 35
  if (ctx->HasInput("Bias")) {
    auto bias_dims = ctx->GetInputDim("Bias");
36 37 38 39 40 41 42 43
    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 已提交
44
  }
T
Tao Luo 已提交
45 46 47 48 49

  if (ctx->Attrs().Get<bool>("use_mkldnn")) {
    PADDLE_ENFORCE(in_dims.size() == 2 || in_dims.size() == 4,
                   "Fully Connected input should be 2-D or 4-D tensor.");
  }
T
tensor-tang 已提交
50
  PADDLE_ENFORCE_EQ(w_dims.size(), 2,
T
tensor-tang 已提交
51
                    "Fully Connected input should be 2-D tensor.");
T
Tao Luo 已提交
52 53 54 55 56 57 58
  int in_num_col_dims = ctx->Attrs().Get<int>("in_num_col_dims");
  PADDLE_ENFORCE_GT(
      in_dims.size(), in_num_col_dims,
      "The input tensor Input's rank of FCOp should be larger than "
      "in_num_col_dims.");

  std::vector<int64_t> output_dims;
L
luotao1 已提交
59
  FCOutputSize(in_dims, w_dims, output_dims, in_num_col_dims);
T
tensor-tang 已提交
60

T
Tao Luo 已提交
61
  ctx->SetOutputDim("Out", framework::make_ddim(output_dims));
62 63 64 65 66
  ctx->ShareLoD("Input", "Out");
}

framework::OpKernelType FCOp::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
T
tensor-tang 已提交
67 68
  framework::LibraryType library = framework::LibraryType::kPlain;
  framework::DataLayout layout = framework::DataLayout::kAnyLayout;
T
tensor-tang 已提交
69
  if (ctx.Attr<bool>("use_mkldnn")) {
T
tensor-tang 已提交
70 71 72
    library = framework::LibraryType::kMKLDNN;
    layout = framework::DataLayout::kMKLDNN;
  }
Y
Yu Yang 已提交
73 74
  return framework::OpKernelType(ctx.Input<Tensor>("Input")->type(),
                                 ctx.GetPlace(), layout, library);
75 76 77 78 79 80 81 82 83 84 85 86
}

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 已提交
87 88

  if (ctx->HasInput("Bias")) {
T
tensor-tang 已提交
89 90
    PADDLE_ENFORCE(ctx->HasOutput(framework::GradVarName("Bias")),
                   "Should have bias grad");
T
tensor-tang 已提交
91 92 93
    auto bias_dims = ctx->GetInputDim("Bias");
    ctx->SetOutputDim(framework::GradVarName("Bias"), bias_dims);
  }
94 95 96 97
}

framework::OpKernelType FCOpGrad::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
T
tensor-tang 已提交
98 99
  framework::LibraryType library = framework::LibraryType::kPlain;
  framework::DataLayout layout = framework::DataLayout::kAnyLayout;
T
tensor-tang 已提交
100
  if (ctx.Attr<bool>("use_mkldnn")) {
T
tensor-tang 已提交
101 102 103
    library = framework::LibraryType::kMKLDNN;
    layout = framework::DataLayout::kMKLDNN;
  }
Y
Yu Yang 已提交
104 105
  return framework::OpKernelType(ctx.Input<Tensor>("Input")->type(),
                                 ctx.GetPlace(), layout, library);
106 107
}

Y
Yu Yang 已提交
108
void FCOpMaker::Make() {
T
Tao Luo 已提交
109
  AddInput("Input", "(Tensor), The input tensor of fully connected operator.");
T
tensor-tang 已提交
110 111
  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 已提交
112
      .AsDispensable();
T
Tao Luo 已提交
113
  AddAttr<int>("in_num_col_dims",
T
Tao Luo 已提交
114 115 116 117
               "(int, default 1), The fc op can take tensors with more than "
               "two dimensions as its inputs.")
      .SetDefault(1)
      .EqualGreaterThan(1);
118
  AddOutput("Out", "(Tensor) The output tensor of fully connected operator. ");
119 120 121
  AddAttr<bool>("use_mkldnn",
                "(bool, default false) Only used in mkldnn kernel")
      .SetDefault(false);
L
luotao1 已提交
122 123 124 125 126 127
  AddAttr<bool>(
      framework::kAllKernelsMustComputeRuntimeShape,
      "If an Op has this attribute, all its kernels should calculate output"
      "variable's shape in the corresponding Compute() function. Note that "
      "this temporal attribute would be deleted after all ops contain it.")
      .SetDefault(true);
128 129 130
  AddComment(R"DOC(
  Fully Connected Operator.

131
  The fully connected operation calculates the output based on the input, weights and bias.
132 133 134 135
  The size of each dimension of the parameters checked in the infer-shape.
)DOC");
}

T
tensor-tang 已提交
136 137 138 139
template <typename T>
class FCOpKernel : public framework::OpKernel<T> {
 public:
  void Compute(const paddle::framework::ExecutionContext& ctx) const override {
T
tensor-tang 已提交
140
    PADDLE_ENFORCE(platform::is_cpu_place(ctx.GetPlace()),
T
tensor-tang 已提交
141
                   "It must use CPUPlace.");
L
luotao1 已提交
142 143 144 145 146
    auto input = ctx.Input<framework::LoDTensor>("Input");
    auto w = ctx.Input<framework::LoDTensor>("W");
    auto bias = ctx.Input<framework::LoDTensor>("Bias");
    auto output = ctx.Output<framework::LoDTensor>("Out");
    int in_num_col_dims = ctx.Attr<int>("in_num_col_dims");
T
tensor-tang 已提交
147
    auto w_dims = w->dims();
L
luotao1 已提交
148 149 150 151 152 153

    std::vector<int64_t> output_dims;
    FCOutputSize(input->dims(), w_dims, output_dims, in_num_col_dims);
    output->Resize(framework::make_ddim(output_dims));
    output->set_lod(input->lod());

T
Tao Luo 已提交
154
    auto out_dims = output->dims();
L
luotao1 已提交
155
    int M = framework::product(out_dims) / w_dims[1];
T
tensor-tang 已提交
156 157 158 159

    const T* input_data = input->data<T>();
    const T* w_data = w->data<T>();
    T* output_data = output->mutable_data<T>(ctx.GetPlace());
160 161
    auto blas = math::GetBlas<platform::CPUDeviceContext, T>(ctx);
    math::FCCompute<platform::CPUDeviceContext, T>(
T
Tao Luo 已提交
162
        blas, M, w_dims[1], w_dims[0], input_data, w_data, output_data,
163
        bias ? bias->data<T>() : NULL);
T
tensor-tang 已提交
164 165

    // TODO(TJ): fuse act
T
tensor-tang 已提交
166 167 168
  }
};

169 170 171
}  // namespace operators
}  // namespace paddle

T
tensor-tang 已提交
172 173
namespace ops = paddle::operators;
REGISTER_OPERATOR(fc, ops::FCOp, ops::FCOpMaker,
174
                  paddle::framework::DefaultGradOpDescMaker<true>);
T
tensor-tang 已提交
175
REGISTER_OPERATOR(fc_grad, ops::FCOpGrad);
T
tensor-tang 已提交
176
REGISTER_OP_CPU_KERNEL(fc, ops::FCOpKernel<float>, ops::FCOpKernel<double>);