phi_utils.cc 9.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* Copyright (c) 2021 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. */

15 16
#include "paddle/fluid/framework/phi_utils.h"

17 18
#include <sstream>

19
#include "paddle/fluid/framework/convert_utils.h"
20
#include "paddle/fluid/framework/lod_tensor.h"
Z
Zeng Jinle 已提交
21
#include "paddle/fluid/framework/op_info.h"
22
#include "paddle/fluid/framework/selected_rows_utils.h"
23 24
#include "paddle/fluid/framework/variable.h"
#include "paddle/fluid/string/string_helper.h"
25 26 27
#include "paddle/phi/core/compat/convert_utils.h"
#include "paddle/phi/core/compat/op_utils.h"
#include "paddle/phi/core/kernel_factory.h"
28
#include "paddle/phi/core/type_defs.h"
29 30 31 32

namespace paddle {
namespace framework {

Z
Zeng Jinle 已提交
33 34 35 36 37
class KernelArgsNameMakerByOpProto : public KernelArgsNameMaker {
 public:
  explicit KernelArgsNameMakerByOpProto(
      const framework::proto::OpProto* op_proto)
      : op_proto_(op_proto) {
38 39 40
    PADDLE_ENFORCE_NOT_NULL(
        op_proto_,
        platform::errors::InvalidArgument("Op proto cannot be nullptr."));
Z
Zeng Jinle 已提交
41 42 43 44
  }

  ~KernelArgsNameMakerByOpProto() {}

C
Chen Weihang 已提交
45 46 47
  const paddle::small_vector<const char*>& GetInputArgsNames() override;
  const paddle::small_vector<const char*>& GetOutputArgsNames() override;
  const paddle::small_vector<const char*>& GetAttrsArgsNames() override;
Z
Zeng Jinle 已提交
48

49
  phi::KernelSignature GetKernelSignature();
Z
Zeng Jinle 已提交
50 51 52 53 54 55 56

 private:
  DISABLE_COPY_AND_ASSIGN(KernelArgsNameMakerByOpProto);

 private:
  const framework::proto::OpProto* op_proto_;

C
Chen Weihang 已提交
57 58 59
  paddle::small_vector<const char*> input_names_;
  paddle::small_vector<const char*> output_names_;
  paddle::small_vector<const char*> attr_names_;
Z
Zeng Jinle 已提交
60 61
};

62
OpKernelType TransPhiKernelKeyToOpKernelType(const phi::KernelKey& kernel_key) {
63
  proto::VarType::Type data_type =
64
      paddle::framework::TransToProtoVarType(kernel_key.dtype());
65
  // no need to set current device id here
66
  platform::Place place = phi::TransToPhiPlace(kernel_key.backend(), false);
67
  DataLayout data_layout = kernel_key.layout();
68
  LibraryType library_type = LibraryType::kPlain;
69
  if (kernel_key.backend() == phi::Backend::ONEDNN) {
70
    library_type = LibraryType::kMKLDNN;
71
  } else if (kernel_key.backend() == phi::Backend::GPUDNN) {
72
    library_type = LibraryType::kCUDNN;
73 74
  } else if (kernel_key.backend() == phi::Backend::KPS) {
    library_type = LibraryType::kKP;
75 76 77 78 79 80 81
  } else {
    // do nothing
  }
  // TODO(chenweihang): the customized_type_value is lost
  return OpKernelType(data_type, place, data_layout, library_type);
}

82
phi::KernelKey TransOpKernelTypeToPhiKernelKey(
83
    const OpKernelType& kernel_type) {
84
  phi::Backend backend = phi::TransToPhiBackend(kernel_type.place_);
85 86 87 88 89
  switch (kernel_type.library_type_) {
    case LibraryType::kCUDNN:
      backend = phi::Backend::GPUDNN;
      break;
    case LibraryType::kMKLDNN:
90
      backend = phi::Backend::ONEDNN;
91 92 93 94 95 96
      break;
    case LibraryType::kKP:
      backend = phi::Backend::KPS;
      break;
    default:
      break;
97
  }
98 99
  return phi::KernelKey(backend,
                        kernel_type.data_layout_,
100
                        framework::TransToPhiDataType(kernel_type.data_type_));
101 102
}

H
HongyuJia 已提交
103
phi::KernelKey FallBackToCpu(const phi::KernelKey& kernel_key,
104
                             const framework::OperatorBase& op) {
105
#ifdef PADDLE_WITH_XPU
H
HongyuJia 已提交
106
  if (kernel_key.backend() == phi::Backend::XPU ||
107
      paddle::platform::is_in_xpu_black_list(op.Type())) {
108
    VLOG(3) << "phi missing XPU kernel: " << op.Type()
H
HongyuJia 已提交
109 110
            << ", expected_kernel_key:" << kernel_key
            << ", fallback to CPU one!";
111 112
    return phi::KernelKey(
        phi::Backend::CPU, kernel_key.layout(), kernel_key.dtype());
113 114 115
  }
#endif
#ifdef PADDLE_WITH_ASCEND_CL
H
HongyuJia 已提交
116
  if (kernel_key.backend() == phi::Backend::NPU) {
117
    VLOG(3) << "phi missing NPU kernel: " << op.Type()
H
HongyuJia 已提交
118 119
            << ", expected_kernel_key:" << kernel_key
            << ", fallback to CPU one!";
120 121
    return phi::KernelKey(
        phi::Backend::CPU, kernel_key.layout(), kernel_key.dtype());
122 123 124
  }
#endif
#ifdef PADDLE_WITH_MLU
H
HongyuJia 已提交
125
  if (kernel_key.backend() == phi::Backend::MLU) {
126
    VLOG(3) << "phi missing MLU kernel: " << op.Type()
H
HongyuJia 已提交
127 128
            << ", expected_kernel_key:" << kernel_key
            << ", fallback to CPU one!";
129 130
    return phi::KernelKey(
        phi::Backend::CPU, kernel_key.layout(), kernel_key.dtype());
131 132 133
  }
#endif
#ifdef PADDLE_WITH_IPU
H
HongyuJia 已提交
134
  if (kernel_key.backend() == phi::Backend::IPU) {
135
    VLOG(3) << "phi missing IPU kernel: " << op.Type()
H
HongyuJia 已提交
136 137
            << ", expected_kernel_key:" << kernel_key
            << ", fallback to CPU one!";
138 139
    return phi::KernelKey(
        phi::Backend::CPU, kernel_key.layout(), kernel_key.dtype());
140 141 142
  }
#endif
#ifdef PADDLE_WITH_CUSTOM_DEVICE
H
HongyuJia 已提交
143 144 145
  auto place = phi::TransToPhiPlace(kernel_key.backend());
  if (platform::is_custom_place(place)) {
    VLOG(3) << "phi missing " << place.GetDeviceType()
146
            << " kernel: " << op.Type()
H
HongyuJia 已提交
147 148
            << ", expected_kernel_key:" << kernel_key
            << ", fallback to CPU one!";
149 150
    return phi::KernelKey(
        phi::Backend::CPU, kernel_key.layout(), kernel_key.dtype());
151 152
  }
#endif
153
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
H
HongyuJia 已提交
154 155
  if (kernel_key.backend() == phi::Backend::GPU ||
      kernel_key.backend() == phi::Backend::GPUDNN) {
156 157 158 159 160
    PADDLE_THROW(platform::errors::Unavailable(
        "For GPU kernel, they must not fallback into CPU kernel."));
  }
#endif

161
  return phi::KernelKey();
162 163
}

C
Chen Weihang 已提交
164
const paddle::small_vector<const char*>&
165 166 167 168 169 170 171 172
KernelArgsNameMakerByOpProto::GetInputArgsNames() {
  for (int i = 0; i < op_proto_->inputs_size(); ++i) {
    auto& in = op_proto_->inputs()[i];
    auto& in_name = in.name();
    if ((in.has_extra() && in.extra()) || (in.has_quant() && in.quant())) {
      continue;
    }
    // If contains dispensable input, we should override the
173
    // OpArgumentMapping method self in phi/ops/compat dir
174 175 176
    if (in.has_dispensable() && in.dispensable()) {
      continue;
    }
177 178 179 180 181
    input_names_.emplace_back(in_name.c_str());
  }
  if (VLOG_IS_ON(10)) {
    std::ostringstream sout;
    sout << "PhiKernel inputs: ";
182 183
    std::copy(input_names_.begin(),
              input_names_.end(),
184 185
              std::ostream_iterator<const char*>(sout, ", "));
    VLOG(10) << sout.str();
186 187 188 189
  }
  return input_names_;
}

C
Chen Weihang 已提交
190
const paddle::small_vector<const char*>&
191 192 193 194
KernelArgsNameMakerByOpProto::GetOutputArgsNames() {
  for (int i = 0; i < op_proto_->outputs_size(); ++i) {
    auto& out = op_proto_->outputs()[i];
    auto& out_name = out.name();
195 196 197
    if ((out.has_extra() && out.extra()) || (out.has_quant() && out.quant())) {
      continue;
    }
198 199 200 201 202
    output_names_.emplace_back(out_name.c_str());
  }
  if (VLOG_IS_ON(10)) {
    std::ostringstream sout;
    sout << "PhiKernel outputs: ";
203 204
    std::copy(output_names_.begin(),
              output_names_.end(),
205 206
              std::ostream_iterator<const char*>(sout, ", "));
    VLOG(10) << sout.str();
207 208 209 210
  }
  return output_names_;
}

C
Chen Weihang 已提交
211
const paddle::small_vector<const char*>&
212 213 214 215
KernelArgsNameMakerByOpProto::GetAttrsArgsNames() {
  for (int i = 0; i < op_proto_->attrs_size(); ++i) {
    auto& attr = op_proto_->attrs()[i];
    auto& attr_name = attr.name();
216 217 218 219
    if (attr_name == "use_mkldnn" || attr_name == "use_cudnn" ||
        attr_name == "op_role" || attr_name == "op_role_var" ||
        attr_name == "op_namescope" || attr_name == "op_callstack" ||
        attr_name == "op_device") {
220 221 222 223 224 225
      continue;
    }
    if ((attr.has_extra() && attr.extra()) ||
        (attr.has_quant() && attr.quant())) {
      continue;
    }
226 227 228 229 230
    attr_names_.emplace_back(attr_name.c_str());
  }
  if (VLOG_IS_ON(10)) {
    std::ostringstream sout;
    sout << "PhiKernel attributes: ";
231 232
    std::copy(attr_names_.begin(),
              attr_names_.end(),
233 234
              std::ostream_iterator<const char*>(sout, ", "));
    VLOG(10) << sout.str();
235 236 237 238
  }
  return attr_names_;
}

239 240
phi::KernelSignature KernelArgsNameMakerByOpProto::GetKernelSignature() {
  return phi::KernelSignature(
241 242 243 244
      phi::TransToPhiKernelName(op_proto_->type()).c_str(),
      GetInputArgsNames(),
      GetAttrsArgsNames(),
      GetOutputArgsNames());
245 246
}

247 248 249 250 251 252 253
std::once_flag kernel_sig_map_init_flag;

void InitDefaultKernelSignatureMap() {
  std::call_once(kernel_sig_map_init_flag, [] {
    for (const auto& pair : paddle::framework::OpInfoMap::Instance().map()) {
      const auto& op_type = pair.first;
      const auto* op_proto = pair.second.proto_;
254
      if (phi::KernelFactory::Instance().HasCompatiblePhiKernel(op_type) &&
255 256
          op_proto) {
        paddle::framework::KernelArgsNameMakerByOpProto maker(op_proto);
257
        VLOG(10) << "Register `" << op_type << "` kernel signature:";
258
        phi::DefaultKernelSignatureMap::Instance().Insert(
259 260 261 262 263 264
            op_type, std::move(maker.GetKernelSignature()));
      }
    }
  });
}

265
static void SetAllocationForUninitializedDenseTensor(
266
    phi::DenseTensor* dense_tensor, const platform::Place& place) {
267 268 269 270 271 272 273 274 275
  int dtype_size = dense_tensor->dtype() == DataType::UNDEFINED
                       ? 0
                       : experimental::SizeOf(dense_tensor->dtype());
  int64_t numels = product(dense_tensor->dims());
  numels = numels < 0 ? 0 : numels;
  auto tmp_allocation_ptr = memory::Alloc(place, numels * dtype_size);
  auto& deleter = tmp_allocation_ptr.get_deleter();
  auto* allocation_ptr = tmp_allocation_ptr.release();
  auto shared_allocation =
276
      std::shared_ptr<phi::Allocation>(allocation_ptr, deleter);
277 278 279 280

  dense_tensor->ResetHolder(shared_allocation);
}

281 282
}  // namespace framework
}  // namespace paddle