mkldnn_reuse.h 45.2 KB
Newer Older
J
Jacek Czaja 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* Copyright (c) 2017 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. */
#pragma once

16
#include <algorithm>
17
#include <memory>
18
#include <sstream>
J
Jacek Czaja 已提交
19
#include <string>
20
#include <utility>
J
Jacek Czaja 已提交
21
#include <vector>
22

23
#include "boost/optional.hpp"
X
xiaoli.liu@intel.com 已提交
24
#include "paddle/fluid/framework/data_layout_transform.h"
J
Jacek Czaja 已提交
25
#include "paddle/fluid/framework/operator.h"
26
#include "paddle/fluid/operators/pool_op.h"
J
Jacek Czaja 已提交
27 28 29 30 31 32
#include "paddle/fluid/platform/mkldnn_helper.h"
#include "paddle/fluid/platform/place.h"

namespace paddle {
namespace platform {

33 34
using framework::DataLayout;
using framework::Tensor;
J
Jacek Czaja 已提交
35
using user_function = std::function<std::shared_ptr<float>(const float*)>;
36
using memory = dnnl::memory;
J
Jacek Czaja 已提交
37

38 39 40 41 42
template <typename T, typename TForward,
          typename TBackward = mkldnn_dummy_primitive,
          typename TBackward_params = mkldnn_dummy_primitive>
class MKLDNNHandlerNoCachingT {
 public:
43
  MKLDNNHandlerNoCachingT(dnnl::engine engine, platform::Place cpu_place)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
      : engine_(engine), place_(cpu_place), fwd_pd_(nullptr), bwd_pd_(nullptr) {
    platform::MKLDNNDeviceContext::tls().log_lib_version();
  }

  std::shared_ptr<TForward> AcquireForwardPrimitive() {
    return std::make_shared<TForward>(*fwd_pd_);
  }

  std::shared_ptr<TBackward> AcquireBackwardPrimitive() {
    return std::make_shared<TBackward>(*bwd_pd_);
  }

  std::shared_ptr<TBackward_params> AcquireBackwardWeightsPrimitive() {
    PADDLE_ENFORCE_NOT_NULL(
        bwd_w_pd_, platform::errors::Unavailable("BWD_PD should be set when "
                                                 "getting BWD prim ."));
    return std::make_shared<TBackward_params>(*bwd_w_pd_);
  }

63
  std::shared_ptr<dnnl::memory> AcquireSrcMemory(
64 65 66 67 68 69 70
      const framework::Tensor* input) {
    const T* input_data = input->data<T>();
    return this->AcquireMemoryFromPrimitive(fwd_pd_->src_desc(),
                                            to_void_cast<T>(input_data));
  }

  template <typename T_out = T>
71
  std::shared_ptr<dnnl::memory> AcquireDstMemory(framework::Tensor* output) {
72 73 74 75 76 77
    T_out* ptr =
        output->mutable_data<T_out>(place_, fwd_pd_->dst_desc().get_size());
    return this->AcquireMemoryFromPrimitive(fwd_pd_->dst_desc(), ptr);
  }

  template <typename T_out = T>
78
  std::shared_ptr<dnnl::memory> AcquireDstMemory(void) {
79 80 81 82
    return this->AcquireMemoryFromPrimitive(fwd_pd_->dst_desc());
  }

  template <typename T_out = T>
83
  std::shared_ptr<dnnl::memory> AcquireDstMemory(
84 85 86 87 88 89
      const framework::Tensor* output) {
    const T_out* output_data = output->data<T_out>();
    return this->AcquireMemoryFromPrimitive(bwd_pd_->dst_desc(),
                                            to_void_cast<T_out>(output_data));
  }

90
  std::shared_ptr<dnnl::memory> AcquireDiffDstMemory(
91 92 93 94 95 96
      const framework::Tensor* diffdst) {
    const T* ptr = diffdst->data<T>();
    return this->AcquireMemoryFromPrimitive(bwd_pd_->diff_dst_desc(),
                                            to_void_cast<T>(ptr));
  }

97
  std::shared_ptr<dnnl::memory> AcquireDiffSrcMemory(
98 99 100 101 102 103 104
      framework::Tensor* diffsrc) {
    T* ptr =
        diffsrc->mutable_data<T>(place_, bwd_pd_->diff_src_desc().get_size());
    return this->AcquireMemoryFromPrimitive(bwd_pd_->diff_src_desc(), ptr);
  }

  // Buffer of given Tensor is used for oneDNN computation
105
  std::shared_ptr<dnnl::memory> AcquireDiffWeightsMemory(
106 107 108 109 110 111 112 113 114 115 116 117
      framework::Tensor* diff_weights) {
    PADDLE_ENFORCE_NOT_NULL(
        bwd_w_pd_,
        platform::errors::Unavailable(
            "BWD_W_PD should be set when getting BWD grad of weights."));
    T* ptr = diff_weights->mutable_data<T>(
        place_, bwd_w_pd_->diff_weights_desc().get_size());
    return this->AcquireMemoryFromPrimitive(bwd_w_pd_->diff_weights_desc(),
                                            ptr);
  }

  // Buffer is allocated by oneDNN to store computation results
118
  std::shared_ptr<dnnl::memory> AcquireDiffWeightsMemory(void) {
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    PADDLE_ENFORCE_NOT_NULL(
        bwd_w_pd_,
        platform::errors::Unavailable(
            "BWD_W_PD should be set when getting BWD grad of weights."));
    return this->AcquireMemoryFromPrimitive(bwd_w_pd_->diff_weights_desc());
  }

 protected:
  // If your primitive descriptor requires attributes, pass them as a
  // first argument and paramters to descriptor constructor in the following
  // arguments. Otherwise, all arguments will be forwarded to descriptor
  // constructor, including the first one.
  template <typename Arg, typename... Args>
  void AcquireForwardPrimitiveDescriptor(Arg&& first_arg, Args&&... args) {
    CreateForwardPrimitiveDescriptor(first_arg, std::forward<Args>(args)...);
  }

  // Using sfinae to specialise variadic function. Workaround for not having
  // if constexpr in C++ 11.
  template <class First, class... Args>
  typename std::enable_if<std::is_same<typename std::decay<First>::type,
                                       dnnl::primitive_attr>::value>::type
  CreateForwardPrimitiveDescriptor(First&& first, Args&&... args) {
    auto fwd_desc = typename TForward::desc(std::forward<Args>(args)...);
    fwd_pd_ = std::make_shared<typename TForward::primitive_desc>(
        fwd_desc, first, engine_);
  }

  template <class First, class... Args>
  typename std::enable_if<!std::is_same<typename std::decay<First>::type,
                                        dnnl::primitive_attr>::value>::type
  CreateForwardPrimitiveDescriptor(First&& first, Args&&... args) {
    auto fwd_desc = typename TForward::desc(std::forward<First>(first),
                                            std::forward<Args>(args)...);
    fwd_pd_ =
        std::make_shared<typename TForward::primitive_desc>(fwd_desc, engine_);
  }

  template <typename... Args>
  void AcquireBackwardPrimitiveDescriptor(Args&&... args) {
    // fwd_pd_ is set during grad by calling
    // AcquireForwardPrimitiveDescriptor
    PADDLE_ENFORCE_NOT_NULL(fwd_pd_,
                            platform::errors::Unavailable(
                                "Get MKLDNN Forward primitive %s failed."));
    auto bwd_desc = typename TBackward::desc(std::forward<Args>(args)...);
    bwd_pd_ = std::make_shared<typename TBackward::primitive_desc>(
        bwd_desc, engine_, *fwd_pd_);
  }

  template <typename... Args>
  void AcquireBackwardWeightsPrimitiveDescriptor(Args&&... args) {
    // fwd_pd_ is set during grad by calling
    // AcquireForwardPrimitiveDescriptor
    PADDLE_ENFORCE_NOT_NULL(fwd_pd_,
                            platform::errors::Unavailable(
                                "Get MKLDNN Forward primitive %s failed."));
    auto bwd_desc =
        typename TBackward_params::desc(std::forward<Args>(args)...);
    bwd_w_pd_ = std::make_shared<typename TBackward_params::primitive_desc>(
        bwd_desc, engine_, *fwd_pd_);
  }

182 183 184
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
      dnnl::memory::desc md, void* ptr) {
    return std::make_shared<dnnl::memory>(md, engine_, ptr);
185 186
  }

187 188 189
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
      dnnl::memory::desc md) {
    return std::make_shared<dnnl::memory>(md, engine_);
190 191
  }

192 193
  void AcquireReorder(const std::shared_ptr<dnnl::memory>& user_memory_p,
                      const std::shared_ptr<dnnl::memory>& target_memory_p) {
194
    auto reorder_p =
195
        std::make_shared<dnnl::reorder>(*user_memory_p, *target_memory_p);
196 197 198 199 200

    auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();

    platform::RecordEvent record_reorder("int_reorder",
                                         platform::EventRole::kUniqueOp);
201 202
    reorder_p->execute(astream, {{DNNL_ARG_FROM, *user_memory_p},
                                 {DNNL_ARG_TO, *target_memory_p}});
203 204 205 206
    astream.wait();
  }

  template <typename F = T>
207 208 209
  std::shared_ptr<dnnl::memory> AcquireMemoryWithReorder(
      const dnnl::memory::desc& user_md, const dnnl::memory::desc& target_md,
      void* ptr, bool is_persistent = false,
210
      std::function<std::shared_ptr<F>(const F*)> custom_reorder_func = {}) {
211
    std::shared_ptr<dnnl::memory> target_memory_p;
212 213 214 215 216 217 218
    if (custom_reorder_func) {
      auto reordered_data =
          custom_reorder_func(reinterpret_cast<const F*>(ptr));
      ptr = reinterpret_cast<void*>(reordered_data.get());
    }
    auto user_memory_p = std::make_shared<dnnl::memory>(user_md, engine_, ptr);
    if (user_md != target_md) {
219
      target_memory_p = std::make_shared<dnnl::memory>(target_md, engine_);
220 221 222 223 224 225
      auto reorder_p =
          std::make_shared<dnnl::reorder>(*user_memory_p, *target_memory_p);

      auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();
      platform::RecordEvent record_reorder("int_reorder",
                                           platform::EventRole::kUniqueOp);
226 227
      reorder_p->execute(astream, {{DNNL_ARG_FROM, *user_memory_p},
                                   {DNNL_ARG_TO, *target_memory_p}});
228 229 230 231 232 233 234
      astream.wait();
    } else {
      target_memory_p = user_memory_p;
    }
    return target_memory_p;
  }

235
  dnnl::engine engine_;
236 237 238 239 240 241
  platform::Place place_;
  std::shared_ptr<typename TForward::primitive_desc> fwd_pd_;
  std::shared_ptr<typename TBackward::primitive_desc> bwd_pd_;
  std::shared_ptr<typename TBackward_params::primitive_desc> bwd_w_pd_;
};

242
template <typename T, typename TForward,
243 244
          typename TBackward = mkldnn_dummy_primitive,
          typename TBackward_params = mkldnn_dummy_primitive>
245 246
class MKLDNNHandlerT {
 public:
247
  MKLDNNHandlerT(const MKLDNNDeviceContext& dev_ctx, dnnl::engine engine,
248 249 250 251 252
                 platform::Place cpu_place, const std::string& base_key)
      : dev_ctx_(dev_ctx),
        engine_(engine),
        place_(cpu_place),
        key_common_(base_key),
253
        key_(platform::ExtendKeyWithThreadInfoIfNeeded(dev_ctx, base_key)),
254
        fwd_pd_(nullptr),
255 256 257
        bwd_pd_(nullptr) {
    platform::MKLDNNDeviceContext::tls().log_lib_version();
  }
258

A
Adam 已提交
259
  std::shared_ptr<TForward> AcquireForwardPrimitive() {
260
    const std::string key_p = key_ + "@fwd_p";
261 262 263
    auto forward_p =
        std::static_pointer_cast<TForward>(dev_ctx_.GetBlob(key_p));
    if (forward_p == nullptr) {
A
Adam 已提交
264
      forward_p = std::make_shared<TForward>(*fwd_pd_);
265 266 267 268 269
      dev_ctx_.SetBlob(key_p, forward_p);
    }
    return forward_p;
  }

A
Adam 已提交
270
  std::shared_ptr<TBackward> AcquireBackwardPrimitive() {
271
    const std::string key_p = key_ + "@bwd_p";
272 273 274
    auto backward_p =
        std::static_pointer_cast<TBackward>(dev_ctx_.GetBlob(key_p));
    if (backward_p == nullptr) {
A
Adam 已提交
275
      backward_p = std::make_shared<TBackward>(*bwd_pd_);
276 277 278 279 280
      dev_ctx_.SetBlob(key_p, backward_p);
    }
    return backward_p;
  }

281 282 283 284 285 286
  std::shared_ptr<TBackward_params> AcquireBackwardWeightsPrimitive() {
    const std::string key_p = key_ + "@bwd_w_p";
    auto backward_p =
        std::static_pointer_cast<TBackward_params>(dev_ctx_.GetBlob(key_p));
    if (backward_p == nullptr) {
      PADDLE_ENFORCE_NOT_NULL(bwd_w_pd_, platform::errors::Unavailable(
287
                                             "BWD_PD should be set when "
288 289 290 291 292 293 294 295
                                             "getting BWD prim witk key: %s .",
                                             key_p));
      backward_p = std::make_shared<TBackward_params>(*bwd_w_pd_);
      dev_ctx_.SetBlob(key_p, backward_p);
    }
    return backward_p;
  }

296
  std::shared_ptr<dnnl::memory> AcquireSrcMemory(
297 298
      const framework::Tensor* input) {
    const T* input_data = input->data<T>();
A
Adam 已提交
299 300
    return this->AcquireMemoryFromPrimitive(
        fwd_pd_->src_desc(), to_void_cast<T>(input_data), "@src_mem_p");
301 302
  }

303
  template <typename T_out = T>
304
  std::shared_ptr<dnnl::memory> AcquireDstMemory(framework::Tensor* output) {
305 306
    T_out* ptr =
        output->mutable_data<T_out>(place_, fwd_pd_->dst_desc().get_size());
A
Adam 已提交
307
    return this->AcquireMemoryFromPrimitive(fwd_pd_->dst_desc(), ptr,
308 309 310
                                            "@dst_mem_p");
  }

311
  template <typename T_out = T>
312
  std::shared_ptr<dnnl::memory> AcquireDstMemory(void) {
313 314 315
    return this->AcquireMemoryFromPrimitive(fwd_pd_->dst_desc(), "@dstt_mem_p");
  }

316
  template <typename T_out = T>
317
  std::shared_ptr<dnnl::memory> AcquireDstMemory(
318
      const framework::Tensor* output) {
319 320 321 322
    const T_out* output_data = output->data<T_out>();
    return this->AcquireMemoryFromPrimitive(bwd_pd_->dst_desc(),
                                            to_void_cast<T_out>(output_data),
                                            "@bwd-dst_mem_p");
323 324
  }

325
  std::shared_ptr<dnnl::memory> AcquireDiffDstMemory(
326 327
      const framework::Tensor* diffdst) {
    const T* ptr = diffdst->data<T>();
A
Adam 已提交
328 329
    return this->AcquireMemoryFromPrimitive(
        bwd_pd_->diff_dst_desc(), to_void_cast<T>(ptr), "@diff_dst_mem_p");
330 331
  }

332
  std::shared_ptr<dnnl::memory> AcquireDiffSrcMemory(
333
      framework::Tensor* diffsrc) {
A
Adam 已提交
334 335 336 337
    T* ptr =
        diffsrc->mutable_data<T>(place_, bwd_pd_->diff_src_desc().get_size());
    return this->AcquireMemoryFromPrimitive(bwd_pd_->diff_src_desc(), ptr,
                                            "@diff_src_mem_p");
338 339
  }

340
  // Buffer of given Tensor is used for oneDNN computation
341
  std::shared_ptr<dnnl::memory> AcquireDiffWeightsMemory(
342 343 344 345
      framework::Tensor* diff_weights) {
    PADDLE_ENFORCE_NOT_NULL(
        bwd_w_pd_,
        platform::errors::Unavailable(
346
            "BWD_W_PD should be set when getting BWD grad of weights."));
347 348 349 350 351 352 353
    T* ptr = diff_weights->mutable_data<T>(
        place_, bwd_w_pd_->diff_weights_desc().get_size());
    return this->AcquireMemoryFromPrimitive(bwd_w_pd_->diff_weights_desc(), ptr,
                                            "@diff_wei_mem_p");
  }

  // Buffer is allocated by oneDNN to store computation results
354
  std::shared_ptr<dnnl::memory> AcquireDiffWeightsMemory(void) {
355 356 357
    PADDLE_ENFORCE_NOT_NULL(
        bwd_w_pd_,
        platform::errors::Unavailable(
358
            "BWD_W_PD should be set when getting BWD grad of weights."));
359 360 361 362
    return this->AcquireMemoryFromPrimitive(bwd_w_pd_->diff_weights_desc(),
                                            "@diff_wei_mem_p");
  }

363
 protected:
364
  bool isCached() {
365 366 367 368 369 370 371
    const std::string key_pd = key_ + "@fwd_pd";
    fwd_pd_ = std::static_pointer_cast<typename TForward::primitive_desc>(
        dev_ctx_.GetBlob(key_pd));

    return (fwd_pd_ != nullptr);
  }

372
  bool isBwdCached() {
373
    const std::string key_pd = key_ + "@bwd_pd";
374 375 376
    bwd_pd_ = std::static_pointer_cast<typename TBackward::primitive_desc>(
        dev_ctx_.GetBlob(key_pd));

377 378 379
    if (bwd_pd_ == nullptr) {
      return false;
    } else {
380 381 382 383 384 385 386 387
      if (std::is_same<TBackward_params, mkldnn_dummy_primitive>::value ==
          false) {
        const std::string key_bw_w_pd = key_ + "@bwd_w_pd";
        bwd_w_pd_ =
            std::static_pointer_cast<typename TBackward_params::primitive_desc>(
                dev_ctx_.GetBlob(key_bw_w_pd));
      }

388 389 390 391 392 393 394 395 396
      // When BWD is cached then still we need to Get FWD PD
      const std::string key_fpd = key_ + "@fwd_pd";
      fwd_pd_ = std::static_pointer_cast<typename TForward::primitive_desc>(
          dev_ctx_.GetBlob(key_fpd));
      PADDLE_ENFORCE_NOT_NULL(
          fwd_pd_, platform::errors::Unavailable(
                       "Error: FWD PD should be set when BWD PD is cached."));
      return true;
    }
397 398
  }

399 400 401 402 403 404
  // If your primitive descriptor requires attributes, pass them as a
  // first argument and paramters to descriptor constructor in the following
  // arguments. Otherwise, all arguments will be forwarded to descriptor
  // constructor, including the first one.
  template <typename Arg, typename... Args>
  void AcquireForwardPrimitiveDescriptor(Arg&& first_arg, Args&&... args) {
405 406 407 408 409 410 411 412 413 414 415
    // This is used when we can recreate FWD PD in BWD so
    // we do not need to pass FWD to BWD
    const std::string key_pd = key_ + "@fwd_pd";
    fwd_pd_ = std::static_pointer_cast<typename TForward::primitive_desc>(
        dev_ctx_.GetBlob(key_pd));
    if (fwd_pd_ == nullptr) {
      CreateForwardPrimitiveDescriptor(first_arg, std::forward<Args>(args)...);
      dev_ctx_.SetBlob(key_pd, fwd_pd_);
    }
  }

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
  // Using sfinae to specialise variadic function. Workaround for not having
  // if constexpr in C++ 11.
  template <class First, class... Args>
  typename std::enable_if<std::is_same<typename std::decay<First>::type,
                                       dnnl::primitive_attr>::value>::type
  CreateForwardPrimitiveDescriptor(First&& first, Args&&... args) {
    auto fwd_desc = typename TForward::desc(std::forward<Args>(args)...);
    fwd_pd_ = std::make_shared<typename TForward::primitive_desc>(
        fwd_desc, first, engine_);
  }

  template <class First, class... Args>
  typename std::enable_if<!std::is_same<typename std::decay<First>::type,
                                        dnnl::primitive_attr>::value>::type
  CreateForwardPrimitiveDescriptor(First&& first, Args&&... args) {
    auto fwd_desc = typename TForward::desc(std::forward<First>(first),
                                            std::forward<Args>(args)...);
    fwd_pd_ =
        std::make_shared<typename TForward::primitive_desc>(fwd_desc, engine_);
  }

437 438
  template <typename... Args>
  void AcquireBackwardPrimitiveDescriptor(Args&&... args) {
439
    // fwd_pd_ is set during grad by calling
440
    // AcquireForwardPrimitiveDescriptor
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
    PADDLE_ENFORCE_NOT_NULL(
        fwd_pd_,
        platform::errors::Unavailable("Get MKLDNN Forward primitive %s failed.",
                                      key_ + "@fwd_pd"));
    const std::string key_pd = key_ + "@bwd_pd";
    bwd_pd_ = std::static_pointer_cast<typename TBackward::primitive_desc>(
        dev_ctx_.GetBlob(key_pd));
    if (bwd_pd_ == nullptr) {
      auto bwd_desc = typename TBackward::desc(std::forward<Args>(args)...);
      bwd_pd_ = std::make_shared<typename TBackward::primitive_desc>(
          bwd_desc, engine_, *fwd_pd_);
      dev_ctx_.SetBlob(key_pd, bwd_pd_);
    }
  }

456
  template <typename... Args>
457
  void AcquireBackwardWeightsPrimitiveDescriptor(Args&&... args) {
458
    // fwd_pd_ is set during grad by calling
459
    // AcquireForwardPrimitiveDescriptor
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    PADDLE_ENFORCE_NOT_NULL(
        fwd_pd_,
        platform::errors::Unavailable("Get MKLDNN Forward primitive %s failed.",
                                      key_ + "@fwd_pd"));
    const std::string key_pd = key_ + "@bwd_w_pd";
    bwd_w_pd_ =
        std::static_pointer_cast<typename TBackward_params::primitive_desc>(
            dev_ctx_.GetBlob(key_pd));
    if (bwd_w_pd_ == nullptr) {
      auto bwd_desc =
          typename TBackward_params::desc(std::forward<Args>(args)...);
      bwd_w_pd_ = std::make_shared<typename TBackward_params::primitive_desc>(
          bwd_desc, engine_, *fwd_pd_);
      dev_ctx_.SetBlob(key_pd, bwd_w_pd_);
    }
  }

477
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
478
      const std::string& suffix) {
479
    return std::static_pointer_cast<dnnl::memory>(
480 481 482
        dev_ctx_.GetBlob(key_ + suffix));
  }

483 484
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
      dnnl::memory::desc md, void* ptr, const std::string& suffix) {
485
    const auto local_key = key_ + suffix;
486
    auto mem_p =
487
        std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(local_key));
488
    if (mem_p == nullptr) {
489
      mem_p = std::make_shared<dnnl::memory>(md, engine_, ptr);
490 491 492 493 494 495 496
      dev_ctx_.SetBlob(local_key, mem_p);
    } else {
      mem_p->set_data_handle(ptr);
    }
    return mem_p;
  }

497 498
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
      dnnl::memory::desc md, const std::string& suffix) {
499 500
    const auto local_key = key_ + suffix;
    auto mem_p =
501
        std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(local_key));
502
    if (mem_p == nullptr) {
503
      mem_p = std::make_shared<dnnl::memory>(md, engine_);
504 505 506 507 508
      dev_ctx_.SetBlob(local_key, mem_p);
    }
    return mem_p;
  }

509 510
  void AcquireReorder(const std::shared_ptr<dnnl::memory>& user_memory_p,
                      const std::shared_ptr<dnnl::memory>& target_memory_p) {
511
    auto reorder_p =
512
        std::make_shared<dnnl::reorder>(*user_memory_p, *target_memory_p);
513

514
    auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();
515 516 517

    platform::RecordEvent record_reorder("int_reorder",
                                         platform::EventRole::kUniqueOp);
518 519
    reorder_p->execute(astream, {{DNNL_ARG_FROM, *user_memory_p},
                                 {DNNL_ARG_TO, *target_memory_p}});
520 521 522
    astream.wait();
  }

523
  template <typename F = T>
524 525 526
  std::shared_ptr<dnnl::memory> AcquireMemoryWithReorder(
      const dnnl::memory::desc& user_md, const dnnl::memory::desc& target_md,
      void* ptr, const std::string& suffix, bool is_persistent = false,
A
Adam Osewski 已提交
527 528
      std::function<std::shared_ptr<F>(const F*)> custom_reorder_func = {},
      const std::vector<float>& scale_data = {1.0f}, int mask = 0) {
529 530 531 532 533 534 535 536
    const auto target_key = key_ + suffix + "_target";
    const auto key_reorder_p = key_ + suffix + "reorder_p";
    const auto user_key = key_ + suffix + "_user";

    auto target_memory_p =
        std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(target_key));

    if (target_memory_p == nullptr) {
537 538 539 540 541 542
      if (custom_reorder_func) {
        auto reordered_data =
            custom_reorder_func(reinterpret_cast<const F*>(ptr));
        dev_ctx_.SetBlob(key_reorder_p + "-custom_reorder", reordered_data);
        ptr = reinterpret_cast<void*>(reordered_data.get());
      }
543 544 545
      auto user_memory_p =
          std::make_shared<dnnl::memory>(user_md, engine_, ptr);
      if (user_md != target_md) {
546
        target_memory_p = std::make_shared<dnnl::memory>(target_md, engine_);
A
Adam Osewski 已提交
547 548 549 550 551 552 553 554 555 556 557
        dnnl::reorder::primitive_desc reorder_pdesc;
        if (is_int8<T>()) {
          dnnl::primitive_attr attr;
          attr.set_output_scales(mask, scale_data);
          reorder_pdesc = dnnl::reorder::primitive_desc(*user_memory_p,
                                                        *target_memory_p, attr);
        } else {
          reorder_pdesc =
              dnnl::reorder::primitive_desc(*user_memory_p, *target_memory_p);
        }
        auto reorder_p = std::make_shared<dnnl::reorder>(reorder_pdesc);
558 559
        dev_ctx_.SetBlob(key_reorder_p, reorder_p);

560
        auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();
561 562
        platform::RecordEvent record_reorder("int_reorder",
                                             platform::EventRole::kUniqueOp);
563 564
        reorder_p->execute(astream, {{DNNL_ARG_FROM, *user_memory_p},
                                     {DNNL_ARG_TO, *target_memory_p}});
565 566 567 568 569 570 571
        astream.wait();
      } else {
        target_memory_p = user_memory_p;
      }
      dev_ctx_.SetBlob(user_key, user_memory_p);
      dev_ctx_.SetBlob(target_key, target_memory_p);
    } else if (!is_persistent) {
572
      auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();
573 574 575 576 577

      auto user_memory_p =
          std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(user_key));
      user_memory_p->set_data_handle(ptr);

578 579
      // TODO(jczaja): Here we detect if reorder is cached it means it is needed
      // need to change this to get rid of keys
580
      auto reorder_p = std::static_pointer_cast<dnnl::reorder>(
581 582
          dev_ctx_.GetBlob(key_reorder_p));
      if (reorder_p != nullptr) {
583 584
        platform::RecordEvent record_reorder("int_reorder",
                                             platform::EventRole::kUniqueOp);
585 586
        reorder_p->execute(astream, {{DNNL_ARG_FROM, *user_memory_p},
                                     {DNNL_ARG_TO, *target_memory_p}});
587 588 589 590 591 592
        astream.wait();
      }
    }
    return target_memory_p;
  }

593
  std::shared_ptr<dnnl::memory> AcquireMemory(const std::string& suffix) {
594
    const auto local_key = key_ + suffix;
595
    return std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(local_key));
596 597
  }

598
  const MKLDNNDeviceContext& dev_ctx_;
599
  dnnl::engine engine_;
600 601
  platform::Place place_;
  std::string key_common_;
602
  std::string key_;
603 604
  std::shared_ptr<typename TForward::primitive_desc> fwd_pd_;
  std::shared_ptr<typename TBackward::primitive_desc> bwd_pd_;
605
  std::shared_ptr<typename TBackward_params::primitive_desc> bwd_w_pd_;
606 607
};

608
template <typename T>
609 610
class BinaryMKLDNNHandler
    : public platform::MKLDNNHandlerNoCachingT<T, dnnl::binary> {
611
 public:
612
  BinaryMKLDNNHandler(const dnnl::algorithm algo, const int axis,
613
                      const dnnl::engine engine, platform::Place cpu_place,
614
                      const Tensor* x, const Tensor* y, Tensor* z,
615 616
                      float scale_x, float scale_y, float scale_z,
                      const dnnl::post_ops& post_ops = dnnl::post_ops())
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::binary>(engine, cpu_place) {
    PADDLE_ENFORCE_EQ(
        x->layout(), DataLayout::kMKLDNN,
        platform::errors::InvalidArgument(
            "Wrong layout set for X tensor. Expected: %d (kMKLDNN), Actual: %d",
            DataLayout::kMKLDNN, x->layout()));
    PADDLE_ENFORCE_NE(x->format(), MKLDNNMemoryFormat::undef,
                      platform::errors::InvalidArgument(
                          "Wrong format set for X tensor : %d (undef)",
                          static_cast<unsigned int>(x->format())));

    PADDLE_ENFORCE_EQ(
        y->layout(), DataLayout::kMKLDNN,
        platform::errors::InvalidArgument(
            "Wrong layout set for Y tensor. Expected: %d (kMKLDNN), Actual: %d",
            DataLayout::kMKLDNN, y->layout()));
    PADDLE_ENFORCE_NE(y->format(), MKLDNNMemoryFormat::undef,
                      platform::errors::InvalidArgument(
                          "Wrong format set for Y tensor : %d (undef)",
                          static_cast<unsigned int>(y->format())));

    const auto src_x_tz = framework::vectorize(x->dims());
    const auto src_y_tz = framework::vectorize(y->dims());
    // if output tensor(z) is nullptr then we are computing into oneDNN
    // managed buffer
    auto rankdiff = x->dims().size() - y->dims().size();
    const auto dst_tz = (z == nullptr) ? (rankdiff > 0 ? src_x_tz : src_y_tz)
                                       : framework::vectorize(z->dims());

    auto src0_md = dnnl::memory::desc(
        src_x_tz, platform::MKLDNNGetDataType<T>(), x->format());
    auto src1_md = dnnl::memory::desc(
        src_y_tz, platform::MKLDNNGetDataType<T>(), y->format());
    if (rankdiff > 0) {  // Second input is of smaller rank than first
      std::vector<int64_t> dims1_ex(rankdiff, 1);
      dims1_ex.insert(next(dims1_ex.begin(), (axis == -1 ? rankdiff : axis)),
                      src_y_tz.begin(), src_y_tz.end());
J
Jacek Czaja 已提交
654 655 656 657 658
      // For broadcasting for NHWC we need rotate extended shape
      if (MKLDNNDeviceContext::tls().get_cur_paddle_data_layout() ==
          framework::DataLayout::kNHWC) {
        std::rotate(dims1_ex.begin() + 1, dims1_ex.end() - 1, dims1_ex.end());
      }
659 660 661 662 663
      src1_md = src1_md.reshape(dims1_ex);
    } else if (rankdiff < 0) {  // First input is of smaller than second
      std::vector<int64_t> dims0_ex(-rankdiff, 1);
      dims0_ex.insert(next(dims0_ex.begin(), (axis == -1 ? -rankdiff : axis)),
                      src_x_tz.begin(), src_x_tz.end());
J
Jacek Czaja 已提交
664 665 666 667 668
      // For broadcasting for NHWC we need rotate extended shape
      if (MKLDNNDeviceContext::tls().get_cur_paddle_data_layout() ==
          framework::DataLayout::kNHWC) {
        std::rotate(dims0_ex.begin() + 1, dims0_ex.end() - 1, dims0_ex.end());
      }
669
      src0_md = src0_md.reshape(dims0_ex);
670
    }
671 672 673 674
    const auto dst_md = memory::desc(dst_tz, platform::MKLDNNGetDataType<T>(),
                                     MKLDNNMemoryFormat::any);

    auto attributes = CreateAttributes(algo, scale_x, scale_y, scale_z);
675 676
    attributes.set_post_ops(post_ops);

677 678
    this->AcquireForwardPrimitiveDescriptor(attributes, algo, src0_md, src1_md,
                                            dst_md);
679
  }
680
  std::shared_ptr<dnnl::memory> AcquireSecondSrcMemory(
681 682
      const framework::Tensor* input) {
    const T* input_data = input->data<T>();
683 684
    return this->AcquireMemoryFromPrimitive(this->fwd_pd_->src1_desc(),
                                            to_void_cast<T>(input_data));
685
  }
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717

 private:
  static inline dnnl::primitive_attr CreateAttributes(dnnl::algorithm op,
                                                      float scale_x,
                                                      float scale_y,
                                                      float scale_z) {
    // Scales set in attributes for inputs contibute to the output equation
    // in the following way (assuming no broadcasting takes place):
    // output_i = scale_0 * x_i <+ or *> scale_1 * y_i;
    // Hence we have to create scales that will:
    // 1. Dequantize both values, by multiplying with (1.0 / scale_x_or_y)
    // 2. Quantize their result to output scale range, by multiplying with
    // (scale_z)
    // If we combine these two, we end up with following equation
    // output = scale_out * (1/scale_x * x <* or +> 1/scale_y * y)
    // Hence, to mimic such behaviour using provided interface,
    // For add operation the equation is equal to:
    // output = (scale_out / scale_x) * x + (scale_out / scale_y) * y
    //                <scale_0>                  <scale_1>
    // For mul operation on the other hand
    // output = (scale_out / scale_x) * x * (1.0 / scale_y) * y
    //                <scale_0>                 <scale_1>
    float scale_0 = scale_z / scale_x;
    float scale_1 =
        op == dnnl::algorithm::binary_add ? scale_z / scale_y : 1.0 / scale_y;
    dnnl::primitive_attr attributes;
    attributes.set_scales(/* input_x_id = */ DNNL_ARG_SRC_0, /* mask = */ 0,
                          {scale_0});
    attributes.set_scales(/* input_y_id = */ DNNL_ARG_SRC_1, /* mask = */ 0,
                          {scale_1});
    return attributes;
  }
718 719
};

720 721
template <typename T>
class BroadcastDataMKLDNNHandler
722
    : public platform::MKLDNNHandlerNoCachingT<T, dnnl::binary> {
723 724
 public:
  BroadcastDataMKLDNNHandler(const dnnl::algorithm algo,
725
                             const dnnl::engine engine,
726 727
                             platform::Place cpu_place, const Tensor* out,
                             const Tensor* x, float scale_x, float scale_y,
728
                             const std::vector<int64_t>& input_dims)
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::binary>(engine, cpu_place) {
    PADDLE_ENFORCE_EQ(
        x->layout(), DataLayout::kMKLDNN,
        platform::errors::InvalidArgument("Wrong layout set for X tensor."));
    PADDLE_ENFORCE_NE(
        x->format(), MKLDNNMemoryFormat::undef,
        platform::errors::InvalidArgument("Wrong format set for X tensor."));

    const auto src0_tz = framework::vectorize(out->dims());

    const auto src0_md = dnnl::memory::desc(
        src0_tz, platform::MKLDNNGetDataType<T>(), out->format());
    const auto src1_md = dnnl::memory::desc(
        input_dims, platform::MKLDNNGetDataType<T>(), out->format());

    dnnl::primitive_attr attributes;
    attributes.set_scales(DNNL_ARG_SRC_0, 0, {scale_x});
    attributes.set_scales(DNNL_ARG_SRC_1, 0, {scale_y});

    this->AcquireForwardPrimitiveDescriptor(attributes, algo, src0_md, src1_md,
                                            src0_md);
750 751
  }

752
  template <typename T_out = T>
753
  std::shared_ptr<dnnl::memory> AcquireDstMemory(framework::Tensor* output) {
754 755 756
    T_out* ptr = output->mutable_data<T_out>(
        this->place_, this->fwd_pd_->dst_desc().get_size());
    memset(ptr, 0, this->fwd_pd_->dst_desc().get_size());
757
    return this->AcquireMemoryFromPrimitive(this->fwd_pd_->dst_desc(), ptr);
758 759 760
  }
};

761 762
template <typename T>
class ReductionMKLDNNHandler
763
    : public platform::MKLDNNHandlerNoCachingT<T, dnnl::reduction> {
764 765
 public:
  ReductionMKLDNNHandler(const dnnl::algorithm algo, const float p,
766
                         const float eps, const dnnl::engine engine,
767
                         platform::Place cpu_place, const Tensor* x,
768 769
                         const Tensor* y, std::vector<int64_t> y_tz,
                         const dnnl::primitive_attr& attr = NULL)
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::reduction>(engine,
                                                              cpu_place) {
    PADDLE_ENFORCE_EQ(
        x->layout(), DataLayout::kMKLDNN,
        platform::errors::InvalidArgument("Wrong layout set for X tensor."));
    PADDLE_ENFORCE_NE(
        x->format(), MKLDNNMemoryFormat::undef,
        platform::errors::InvalidArgument("Wrong format set for X tensor."));

    const auto x_tz = framework::vectorize(x->dims());

    const auto x_md =
        dnnl::memory::desc(x_tz, platform::MKLDNNGetDataType<T>(), x->format());
    const auto y_md =
        memory::desc(y_tz, platform::MKLDNNGetDataType<T>(), x->format());

786 787 788 789
    if (attr)
      this->AcquireForwardPrimitiveDescriptor(attr, algo, x_md, y_md, p, eps);
    else
      this->AcquireForwardPrimitiveDescriptor(algo, x_md, y_md, p, eps);
790 791 792
  }
};

793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
template <typename T>
class MatMulV2MKLDNNHandler
    : public paddle::platform::MKLDNNHandlerNoCachingT<T, dnnl::matmul> {
 public:
  MatMulV2MKLDNNHandler(const dnnl::engine engine,
                        paddle::platform::Place cpu_place,
                        const std::vector<int64_t>& x_org_dims, bool trans_x,
                        const std::vector<int64_t>& y_org_dims, bool trans_y,
                        bool is_output_fused,
                        const std::vector<int64_t>& x_strides_override,
                        const std::vector<int64_t>& y_strides_override)
      : paddle::platform::MKLDNNHandlerNoCachingT<T, dnnl::matmul>(engine,
                                                                   cpu_place) {
    // M X K * K X N
    std::vector<int64_t> x_dims(x_org_dims);
    std::vector<int64_t> y_dims(y_org_dims);

    const int MB_idx = x_dims.size() - 3;
    const int H_idx = x_dims.size() - 2;
    const int W_idx = x_dims.size() - 1;

    if (trans_x) std::swap(x_dims[H_idx], x_dims[W_idx]);
    if (trans_y) std::swap(y_dims[H_idx], y_dims[W_idx]);

    const memory::dim M = x_dims[H_idx];
    const memory::dim K = x_dims[W_idx];
    const memory::dim N = y_dims[W_idx];

    std::vector<int64_t> x_strides(x_dims.size() - 3, 1);
    std::vector<int64_t> y_strides(x_dims.size() - 3, 1);
    std::vector<int64_t> out_strides(x_dims.size() - 3, 1);
    std::vector<int64_t> out_ddims(x_dims.size() - 3, 1);

    x_strides.reserve(x_dims.size());
    y_strides.reserve(x_dims.size());
    out_strides.reserve(x_dims.size());

    if (!x_strides_override.empty()) {
      x_strides = x_strides_override;
    } else {
      if (!trans_x) {
        x_strides.insert(x_strides.end(), {M * K, K, 1});
      } else {
        x_strides.insert(x_strides.end(), {M * K, 1, M});
      }
    }

    if (!y_strides_override.empty()) {
      y_strides = y_strides_override;
    } else {
      if (!trans_y) {
        y_strides.insert(y_strides.end(), {N * K, N, 1});
      } else {
        y_strides.insert(y_strides.end(), {N * K, 1, K});
      }
    }

    out_strides.insert(out_strides.end(), {M * N, N, 1});
    out_ddims.insert(out_ddims.end(),
                     {std::max(x_dims[MB_idx], y_dims[MB_idx]), M, N});

    for (int i = x_dims.size() - 4; i >= 0; --i) {
      out_ddims[i] = std::max(x_dims[i], y_dims[i]);
      if (x_strides_override.empty()) {
        x_strides[i] = x_dims[i + 1] * x_strides[i + 1];
      }
      if (y_strides_override.empty()) {
        y_strides[i] = y_dims[i + 1] * y_strides[i + 1];
      }
      out_strides[i] = out_ddims[i + 1] * out_strides[i + 1];
    }

    if (is_output_fused) {
      out_strides = FakeTransposeStrides(out_ddims);
    }

    auto x_md = memory::desc(x_dims, MKLDNNGetDataType<T>(), x_strides);
    auto y_md = memory::desc(y_dims, MKLDNNGetDataType<T>(), y_strides);
    auto out_md = memory::desc(out_ddims, MKLDNNGetDataType<T>(), out_strides);

    this->AcquireForwardPrimitiveDescriptor(x_md, y_md, out_md);
  }

  std::vector<int64_t> FakeTransposeStrides(
      const std::vector<int64_t>& matmul_out_dims) const {
    // fuse matmul_v2 + transpose + reshape guarantees that output is 4D and
    // transpose axis are: {0, 2, 1, 3}
    std::vector<int64_t> transpose_axis = {0, 2, 1, 3};
    std::vector<int64_t> fake_strides(transpose_axis.size());
    int ndims = static_cast<int>(transpose_axis.size());

    int total_stride = 1;

    for (int i = ndims - 1; i >= 0; --i) {
      fake_strides[transpose_axis[i]] = total_stride;
      total_stride *= matmul_out_dims[transpose_axis[i]];
    }

    return fake_strides;
  }

  std::shared_ptr<memory> AcquireWeightsMemory(const Tensor* input) {
    const T* input_data = input->data<T>();
    return this->AcquireMemoryFromPrimitive(this->fwd_pd_->weights_desc(),
                                            to_void_cast<T>(input_data));
  }
};

901
template <typename T>
902
class ActivationMKLDNNHandler
903 904
    : public MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                     dnnl::eltwise_backward> {
905
 public:
906
  ActivationMKLDNNHandler(dnnl::algorithm algorithm,
907
                          const framework::ExecutionContext& ctx,
908
                          const dnnl::engine engine, Place cpu_place,
909
                          const framework::Tensor* in_x)
910 911 912
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                          dnnl::eltwise_backward>(engine,
                                                                  cpu_place) {
913 914
    float alpha = ctx.HasAttr("alpha") ? ctx.Attr<float>("alpha") : 0;
    float beta = ctx.HasAttr("beta") ? ctx.Attr<float>("beta") : 0;
915 916

    if (ctx.Type() == "scale") {
917 918
      bool bias_after_scale = ctx.Attr<bool>("bias_after_scale");
      auto* scale_tensor = ctx.Input<Tensor>("ScaleTensor");
919 920 921
      alpha = (scale_tensor == nullptr)
                  ? ctx.Attr<float>("scale")
                  : static_cast<float>(*(scale_tensor->data<T>()));
922 923 924 925 926
      beta = ctx.Attr<float>("bias");
      // if bias_after_scale == true
      //   out = scale*X + bias
      // else
      //   out = scale*(X + bias) = scale*X + scale*bias
927 928 929 930 931 932 933 934
      if (!bias_after_scale) {
        beta *= alpha;
      }
    } else if (ctx.Type() == "clip") {
      alpha = ctx.HasInput("Min") ? ctx.Input<Tensor>("Min")->data<float>()[0]
                                  : ctx.Attr<float>("min");
      beta = ctx.HasInput("Max") ? ctx.Input<Tensor>("Max")->data<float>()[0]
                                 : ctx.Attr<float>("max");
935 936
    } else {
      // paddle uses beta but mkldnn uses alpha for swish
937
      if (algorithm == dnnl::algorithm::eltwise_swish) {
938 939 940
        std::swap(alpha, beta);
      } else if (algorithm == dnnl::algorithm::eltwise_bounded_relu) {
        alpha = ctx.Attr<float>("threshold");
941
      }
942
    }
943

944 945 946 947 948
    PADDLE_ENFORCE(in_x->dims().size() >= 1 || in_x->dims().size() <= 6,
                   platform::errors::Unimplemented(
                       "Input dimension size can be 1, 2, 3, 4, "
                       "5, or 6, but now the dimension size is",
                       in_x->dims().size()));
949

950 951 952
    auto src_tz = framework::vectorize<int64_t>(in_x->dims());
    auto src_fmt = src_tz.size() == 2 ? MKLDNNMemoryFormat::nc : in_x->format();
    auto md =
953
        dnnl::memory::desc(src_tz, platform::MKLDNNGetDataType<T>(), src_fmt);
954

955
    this->AcquireForwardPrimitiveDescriptor(dnnl::prop_kind::forward_training,
956
                                            algorithm, md, alpha, beta);
957 958
  }

959
  ActivationMKLDNNHandler(dnnl::algorithm algorithm,
960
                          const framework::ExecutionContext& ctx,
961
                          const dnnl::engine engine, Place cpu_place,
962
                          const framework::Tensor* in_x, const Tensor* out_grad)
963 964 965
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                          dnnl::eltwise_backward>(engine,
                                                                  cpu_place) {
966 967 968 969
    float alpha = ctx.HasAttr("alpha") ? ctx.Attr<float>("alpha") : 0;
    float beta = ctx.HasAttr("beta") ? ctx.Attr<float>("beta") : 0;

    // paddle uses beta but mkldnn uses alpha for swish
970
    if (algorithm == dnnl::algorithm::eltwise_swish) {
971 972 973 974
      std::swap(alpha, beta);
    } else if (algorithm == dnnl::algorithm::eltwise_bounded_relu) {
      alpha = ctx.Attr<float>("threshold");
    }
975

976 977 978 979 980 981 982
    if (ctx.Type() == "clip_grad") {
      alpha = ctx.HasInput("Min") ? ctx.Input<Tensor>("Min")->data<float>()[0]
                                  : ctx.Attr<float>("min");
      beta = ctx.HasInput("Max") ? ctx.Input<Tensor>("Max")->data<float>()[0]
                                 : ctx.Attr<float>("max");
    }

983
    auto diff_dst_tz = framework::vectorize<int64_t>(out_grad->dims());
984

985 986 987 988
    auto src_fmt =
        diff_dst_tz.size() == 2 ? MKLDNNMemoryFormat::nc : in_x->format();
    auto diff_fmt =
        diff_dst_tz.size() == 2 ? MKLDNNMemoryFormat::nc : out_grad->format();
989

990 991 992 993 994
    auto dims = framework::vectorize(in_x->dims());
    auto diff_dst_md = platform::MKLDNNMemDesc(
        dims, platform::MKLDNNGetDataType<T>(), diff_fmt);
    auto src_md = platform::MKLDNNMemDesc(
        dims, platform::MKLDNNGetDataType<T>(), src_fmt);
995

996
    this->AcquireForwardPrimitiveDescriptor(dnnl::prop_kind::forward_training,
997 998 999
                                            algorithm, src_md, alpha, beta);
    this->AcquireBackwardPrimitiveDescriptor(algorithm, diff_dst_md, src_md,
                                             alpha, beta);
1000
  }
1001

1002
  std::shared_ptr<dnnl::memory> AcquireBackwardSrcMemory(
1003 1004
      const framework::Tensor* input) {
    const T* input_data = input->data<T>();
A
Adam 已提交
1005
    return this->AcquireMemoryFromPrimitive(this->bwd_pd_->src_desc(),
1006
                                            to_void_cast<T>(input_data));
1007 1008 1009
  }
};

1010
class ReorderMKLDNNHandler {
1011
 public:
A
Adam 已提交
1012
  ReorderMKLDNNHandler(std::vector<int64_t>& dims,  // NOLINT
1013
                       framework::proto::VarType::Type vtype,
1014
                       dnnl::memory::data_type dtype, dnnl::engine engine)
1015
      : dims_(dims),
1016
        vtype_(vtype),
1017 1018
        vtype_dst_(vtype),
        dtype_(dtype),
1019 1020
        dtype_dst_(dtype),
        engine_(engine) {}
1021 1022 1023

  ReorderMKLDNNHandler(std::vector<int64_t>& dims,  // NOLINT
                       framework::proto::VarType::Type vtype,
1024
                       dnnl::memory::data_type dtype,
1025
                       framework::proto::VarType::Type vtype_dst,
1026
                       dnnl::memory::data_type dtype_dst, dnnl::engine engine)
1027
      : dims_(dims),
1028 1029 1030
        vtype_(vtype),
        vtype_dst_(vtype_dst),
        dtype_(dtype),
1031 1032
        dtype_dst_(dtype_dst),
        engine_(engine) {}
1033

1034 1035 1036 1037
  std::shared_ptr<dnnl::memory> AcquireSrcMemory(const MKLDNNMemoryFormat& fmt,
                                                 void* ptr) {
    auto md = dnnl::memory::desc(dims_, dtype_, fmt);
    return std::make_shared<dnnl::memory>(md, engine_, ptr);
1038 1039
  }

1040
  std::shared_ptr<dnnl::memory> AcquireSubmemory(
1041
      const std::vector<int64_t>& dims, const std::vector<int64_t>& offset,
1042
      const std::shared_ptr<dnnl::memory>& mem_p) {
1043
    auto sub_md = mem_p->get_desc().submemory_desc(dims, {offset});
1044 1045
    auto sub_mem_p = std::make_shared<dnnl::memory>(sub_md, engine_,
                                                    mem_p->get_data_handle());
1046 1047 1048
    return sub_mem_p;
  }

1049 1050 1051
  std::shared_ptr<dnnl::memory> AcquireDstMemory(framework::Tensor* output,
                                                 const MKLDNNMemoryFormat& fmt,
                                                 platform::Place place) {
1052 1053
    auto dst_md = platform::MKLDNNMemDesc(dims_, dtype_dst_, fmt);
    auto dst_data = output->mutable_data(place, vtype_dst_, dst_md.get_size());
1054
    return std::make_shared<dnnl::memory>(dst_md, engine_, dst_data);
1055 1056
  }

1057
  std::shared_ptr<dnnl::memory> AcquireDstMemory(
1058
      framework::Tensor* output, const std::vector<int64_t>& dims,
1059 1060 1061
      const MKLDNNMemoryFormat& fmt, platform::Place place) {
    auto dst_md = platform::MKLDNNMemDesc(dims, dtype_dst_, fmt);
    auto dst_data = output->mutable_data(place, vtype_dst_, dst_md.get_size());
1062
    return std::make_shared<dnnl::memory>(dst_md, engine_, dst_data);
1063 1064
  }

1065 1066 1067 1068
  std::shared_ptr<dnnl::reorder> AcquireReorder(
      std::shared_ptr<dnnl::memory> dst_memory_p,
      std::shared_ptr<dnnl::memory> src_memory_p) {
    return std::make_shared<dnnl::reorder>(*(src_memory_p), *(dst_memory_p));
1069 1070 1071
  }

 private:
A
Adam 已提交
1072
  std::vector<int64_t> dims_;
1073
  framework::proto::VarType::Type vtype_, vtype_dst_;
1074 1075
  dnnl::memory::data_type dtype_, dtype_dst_;
  dnnl::engine engine_;
1076 1077
};

1078 1079 1080
template <typename T>
static void SetDstMemoryQuantized(
    const framework::ExecutionContext& ctx, framework::Tensor* output,
1081 1082 1083
    std::vector<int64_t> dst_tz, const dnnl::engine& engine,
    std::shared_ptr<dnnl::memory::desc>& dst_md,  // NOLINT
    std::shared_ptr<dnnl::memory>& dst_memory,    // NOLINT
1084
    MKLDNNMemoryFormat output_format) {
1085 1086
  T* output_data = output->mutable_data<T>(ctx.GetPlace());
  const size_t dst_dims = dst_tz.size();
1087
  MKLDNNMemoryFormat dst_fmt;
1088

G
GaoWei8 已提交
1089 1090 1091 1092
  PADDLE_ENFORCE_LE(dst_dims, 5, platform::errors::InvalidArgument(
                                     "Dst memory for quantization can not have "
                                     "dims > 5. But received dst_dims is %d.",
                                     dst_dims));
1093
  dst_fmt = platform::MKLDNNFormatForSize(dst_dims, output_format);
1094

A
Adam 已提交
1095
  auto tmp_dst_md = platform::MKLDNNMemDesc(
1096
      {dst_tz}, paddle::framework::ToMKLDNNDataType(
1097
                    framework::DataTypeTrait<T>::DataType()),
1098
      dst_fmt);
1099
  dst_md.reset(new dnnl::memory::desc(tmp_dst_md));
A
Adam 已提交
1100
  dst_memory.reset(
1101
      new dnnl::memory(*dst_md, engine, to_void_cast<T>(output_data)));
1102
}
A
Adam Osewski 已提交
1103

J
Jacek Czaja 已提交
1104 1105
}  // namespace platform
}  // namespace paddle