mkldnn_reuse.h 44.4 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 380 381 382 383 384 385 386 387 388
    if (bwd_pd_ == nullptr) {
      return false;
    } else {
      // 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;
    }
389 390
  }

391 392 393 394 395 396
  // 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) {
397 398 399 400 401 402 403 404 405 406 407
    // 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_);
    }
  }

408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
  // 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_);
  }

429 430
  template <typename... Args>
  void AcquireBackwardPrimitiveDescriptor(Args&&... args) {
431
    // fwd_pd_ is set during grad by calling
432
    // AcquireForwardPrimitiveDescriptor
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
    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_);
    }
  }

448
  template <typename... Args>
449
  void AcquireBackwardWeightsPrimitiveDescriptor(Args&&... args) {
450
    // fwd_pd_ is set during grad by calling
451
    // AcquireForwardPrimitiveDescriptor
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
    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_);
    }
  }

469
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
470
      const std::string& suffix) {
471
    return std::static_pointer_cast<dnnl::memory>(
472 473 474
        dev_ctx_.GetBlob(key_ + suffix));
  }

475 476
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
      dnnl::memory::desc md, void* ptr, const std::string& suffix) {
477
    const auto local_key = key_ + suffix;
478
    auto mem_p =
479
        std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(local_key));
480
    if (mem_p == nullptr) {
481
      mem_p = std::make_shared<dnnl::memory>(md, engine_, ptr);
482 483 484 485 486 487 488
      dev_ctx_.SetBlob(local_key, mem_p);
    } else {
      mem_p->set_data_handle(ptr);
    }
    return mem_p;
  }

489 490
  std::shared_ptr<dnnl::memory> AcquireMemoryFromPrimitive(
      dnnl::memory::desc md, const std::string& suffix) {
491 492
    const auto local_key = key_ + suffix;
    auto mem_p =
493
        std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(local_key));
494
    if (mem_p == nullptr) {
495
      mem_p = std::make_shared<dnnl::memory>(md, engine_);
496 497 498 499 500
      dev_ctx_.SetBlob(local_key, mem_p);
    }
    return mem_p;
  }

501 502
  void AcquireReorder(const std::shared_ptr<dnnl::memory>& user_memory_p,
                      const std::shared_ptr<dnnl::memory>& target_memory_p) {
503
    auto reorder_p =
504
        std::make_shared<dnnl::reorder>(*user_memory_p, *target_memory_p);
505

506
    auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();
507 508 509

    platform::RecordEvent record_reorder("int_reorder",
                                         platform::EventRole::kUniqueOp);
510 511
    reorder_p->execute(astream, {{DNNL_ARG_FROM, *user_memory_p},
                                 {DNNL_ARG_TO, *target_memory_p}});
512 513 514
    astream.wait();
  }

515
  template <typename F = T>
516 517 518
  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 已提交
519 520
      std::function<std::shared_ptr<F>(const F*)> custom_reorder_func = {},
      const std::vector<float>& scale_data = {1.0f}, int mask = 0) {
521 522 523 524 525 526 527 528
    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) {
529 530 531 532 533 534
      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());
      }
535 536 537
      auto user_memory_p =
          std::make_shared<dnnl::memory>(user_md, engine_, ptr);
      if (user_md != target_md) {
538
        target_memory_p = std::make_shared<dnnl::memory>(target_md, engine_);
A
Adam Osewski 已提交
539 540 541 542 543 544 545 546 547 548 549
        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);
550 551
        dev_ctx_.SetBlob(key_reorder_p, reorder_p);

552
        auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();
553 554
        platform::RecordEvent record_reorder("int_reorder",
                                             platform::EventRole::kUniqueOp);
555 556
        reorder_p->execute(astream, {{DNNL_ARG_FROM, *user_memory_p},
                                     {DNNL_ARG_TO, *target_memory_p}});
557 558 559 560 561 562 563
        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) {
564
      auto& astream = platform::MKLDNNDeviceContext::tls().get_stream();
565 566 567 568 569

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

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

585
  std::shared_ptr<dnnl::memory> AcquireMemory(const std::string& suffix) {
586
    const auto local_key = key_ + suffix;
587
    return std::static_pointer_cast<dnnl::memory>(dev_ctx_.GetBlob(local_key));
588 589
  }

590
  const MKLDNNDeviceContext& dev_ctx_;
591
  dnnl::engine engine_;
592 593
  platform::Place place_;
  std::string key_common_;
594
  std::string key_;
595 596
  std::shared_ptr<typename TForward::primitive_desc> fwd_pd_;
  std::shared_ptr<typename TBackward::primitive_desc> bwd_pd_;
597
  std::shared_ptr<typename TBackward_params::primitive_desc> bwd_w_pd_;
598 599
};

600
template <typename T>
601 602
class BinaryMKLDNNHandler
    : public platform::MKLDNNHandlerNoCachingT<T, dnnl::binary> {
603
 public:
604
  BinaryMKLDNNHandler(const dnnl::algorithm algo, const int axis,
605
                      const dnnl::engine engine, platform::Place cpu_place,
606
                      const Tensor* x, const Tensor* y, Tensor* z,
607 608
                      float scale_x, float scale_y, float scale_z,
                      const dnnl::post_ops& post_ops = dnnl::post_ops())
609 610 611 612 613 614 615 616 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
      : 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());
      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());
      src0_md = src0_md.reshape(dims0_ex);
652
    }
653 654 655 656
    const auto dst_md = memory::desc(dst_tz, platform::MKLDNNGetDataType<T>(),
                                     MKLDNNMemoryFormat::any);

    auto attributes = CreateAttributes(algo, scale_x, scale_y, scale_z);
657 658
    attributes.set_post_ops(post_ops);

659 660
    this->AcquireForwardPrimitiveDescriptor(attributes, algo, src0_md, src1_md,
                                            dst_md);
661
  }
662
  std::shared_ptr<dnnl::memory> AcquireSecondSrcMemory(
663 664
      const framework::Tensor* input) {
    const T* input_data = input->data<T>();
665 666
    return this->AcquireMemoryFromPrimitive(this->fwd_pd_->src1_desc(),
                                            to_void_cast<T>(input_data));
667
  }
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699

 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;
  }
700 701
};

702 703
template <typename T>
class BroadcastDataMKLDNNHandler
704
    : public platform::MKLDNNHandlerNoCachingT<T, dnnl::binary> {
705 706
 public:
  BroadcastDataMKLDNNHandler(const dnnl::algorithm algo,
707
                             const dnnl::engine engine,
708 709
                             platform::Place cpu_place, const Tensor* out,
                             const Tensor* x, float scale_x, float scale_y,
710
                             const std::vector<int64_t>& input_dims)
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
      : 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);
732 733
  }

734
  template <typename T_out = T>
735
  std::shared_ptr<dnnl::memory> AcquireDstMemory(framework::Tensor* output) {
736 737 738
    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());
739
    return this->AcquireMemoryFromPrimitive(this->fwd_pd_->dst_desc(), ptr);
740 741 742
  }
};

743 744
template <typename T>
class ReductionMKLDNNHandler
745
    : public platform::MKLDNNHandlerNoCachingT<T, dnnl::reduction> {
746 747
 public:
  ReductionMKLDNNHandler(const dnnl::algorithm algo, const float p,
748
                         const float eps, const dnnl::engine engine,
749
                         platform::Place cpu_place, const Tensor* x,
750 751
                         const Tensor* y, std::vector<int64_t> y_tz,
                         const dnnl::primitive_attr& attr = NULL)
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
      : 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());

768 769 770 771
    if (attr)
      this->AcquireForwardPrimitiveDescriptor(attr, algo, x_md, y_md, p, eps);
    else
      this->AcquireForwardPrimitiveDescriptor(algo, x_md, y_md, p, eps);
772 773 774
  }
};

775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 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
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));
  }
};

883
template <typename T>
884
class ActivationMKLDNNHandler
885 886
    : public MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                     dnnl::eltwise_backward> {
887
 public:
888
  ActivationMKLDNNHandler(dnnl::algorithm algorithm,
889
                          const framework::ExecutionContext& ctx,
890
                          const dnnl::engine engine, Place cpu_place,
891
                          const framework::Tensor* in_x)
892 893 894
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                          dnnl::eltwise_backward>(engine,
                                                                  cpu_place) {
895 896
    float alpha = ctx.HasAttr("alpha") ? ctx.Attr<float>("alpha") : 0;
    float beta = ctx.HasAttr("beta") ? ctx.Attr<float>("beta") : 0;
897 898

    if (ctx.Type() == "scale") {
899 900
      bool bias_after_scale = ctx.Attr<bool>("bias_after_scale");
      auto* scale_tensor = ctx.Input<Tensor>("ScaleTensor");
901 902 903
      alpha = (scale_tensor == nullptr)
                  ? ctx.Attr<float>("scale")
                  : static_cast<float>(*(scale_tensor->data<T>()));
904 905 906 907 908
      beta = ctx.Attr<float>("bias");
      // if bias_after_scale == true
      //   out = scale*X + bias
      // else
      //   out = scale*(X + bias) = scale*X + scale*bias
909 910 911 912 913 914 915 916
      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");
917 918
    } else {
      // paddle uses beta but mkldnn uses alpha for swish
919
      if (algorithm == dnnl::algorithm::eltwise_swish) {
920 921 922
        std::swap(alpha, beta);
      } else if (algorithm == dnnl::algorithm::eltwise_bounded_relu) {
        alpha = ctx.Attr<float>("threshold");
923
      }
924
    }
925

926 927 928 929 930
    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()));
931

932 933 934
    auto src_tz = framework::vectorize<int64_t>(in_x->dims());
    auto src_fmt = src_tz.size() == 2 ? MKLDNNMemoryFormat::nc : in_x->format();
    auto md =
935
        dnnl::memory::desc(src_tz, platform::MKLDNNGetDataType<T>(), src_fmt);
936

937
    this->AcquireForwardPrimitiveDescriptor(dnnl::prop_kind::forward_training,
938
                                            algorithm, md, alpha, beta);
939 940
  }

941
  ActivationMKLDNNHandler(dnnl::algorithm algorithm,
942
                          const framework::ExecutionContext& ctx,
943
                          const dnnl::engine engine, Place cpu_place,
944
                          const framework::Tensor* in_x, const Tensor* out_grad)
945 946 947
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                          dnnl::eltwise_backward>(engine,
                                                                  cpu_place) {
948 949 950 951
    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
952
    if (algorithm == dnnl::algorithm::eltwise_swish) {
953 954 955 956
      std::swap(alpha, beta);
    } else if (algorithm == dnnl::algorithm::eltwise_bounded_relu) {
      alpha = ctx.Attr<float>("threshold");
    }
957

958 959 960 961 962 963 964
    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");
    }

965
    auto diff_dst_tz = framework::vectorize<int64_t>(out_grad->dims());
966

967 968 969 970
    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();
971

972 973 974 975 976
    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);
977

978
    this->AcquireForwardPrimitiveDescriptor(dnnl::prop_kind::forward_training,
979 980 981
                                            algorithm, src_md, alpha, beta);
    this->AcquireBackwardPrimitiveDescriptor(algorithm, diff_dst_md, src_md,
                                             alpha, beta);
982
  }
983

984
  std::shared_ptr<dnnl::memory> AcquireBackwardSrcMemory(
985 986
      const framework::Tensor* input) {
    const T* input_data = input->data<T>();
A
Adam 已提交
987
    return this->AcquireMemoryFromPrimitive(this->bwd_pd_->src_desc(),
988
                                            to_void_cast<T>(input_data));
989 990 991
  }
};

992
class ReorderMKLDNNHandler {
993
 public:
A
Adam 已提交
994
  ReorderMKLDNNHandler(std::vector<int64_t>& dims,  // NOLINT
995
                       framework::proto::VarType::Type vtype,
996
                       dnnl::memory::data_type dtype, dnnl::engine engine)
997
      : dims_(dims),
998
        vtype_(vtype),
999 1000
        vtype_dst_(vtype),
        dtype_(dtype),
1001 1002
        dtype_dst_(dtype),
        engine_(engine) {}
1003 1004 1005

  ReorderMKLDNNHandler(std::vector<int64_t>& dims,  // NOLINT
                       framework::proto::VarType::Type vtype,
1006
                       dnnl::memory::data_type dtype,
1007
                       framework::proto::VarType::Type vtype_dst,
1008
                       dnnl::memory::data_type dtype_dst, dnnl::engine engine)
1009
      : dims_(dims),
1010 1011 1012
        vtype_(vtype),
        vtype_dst_(vtype_dst),
        dtype_(dtype),
1013 1014
        dtype_dst_(dtype_dst),
        engine_(engine) {}
1015

1016 1017 1018 1019
  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);
1020 1021
  }

1022
  std::shared_ptr<dnnl::memory> AcquireSubmemory(
1023
      const std::vector<int64_t>& dims, const std::vector<int64_t>& offset,
1024
      const std::shared_ptr<dnnl::memory>& mem_p) {
1025
    auto sub_md = mem_p->get_desc().submemory_desc(dims, {offset});
1026 1027
    auto sub_mem_p = std::make_shared<dnnl::memory>(sub_md, engine_,
                                                    mem_p->get_data_handle());
1028 1029 1030
    return sub_mem_p;
  }

1031 1032 1033
  std::shared_ptr<dnnl::memory> AcquireDstMemory(framework::Tensor* output,
                                                 const MKLDNNMemoryFormat& fmt,
                                                 platform::Place place) {
1034 1035
    auto dst_md = platform::MKLDNNMemDesc(dims_, dtype_dst_, fmt);
    auto dst_data = output->mutable_data(place, vtype_dst_, dst_md.get_size());
1036
    return std::make_shared<dnnl::memory>(dst_md, engine_, dst_data);
1037 1038
  }

1039
  std::shared_ptr<dnnl::memory> AcquireDstMemory(
1040
      framework::Tensor* output, const std::vector<int64_t>& dims,
1041 1042 1043
      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());
1044
    return std::make_shared<dnnl::memory>(dst_md, engine_, dst_data);
1045 1046
  }

1047 1048 1049 1050
  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));
1051 1052 1053
  }

 private:
A
Adam 已提交
1054
  std::vector<int64_t> dims_;
1055
  framework::proto::VarType::Type vtype_, vtype_dst_;
1056 1057
  dnnl::memory::data_type dtype_, dtype_dst_;
  dnnl::engine engine_;
1058 1059
};

1060 1061 1062
template <typename T>
static void SetDstMemoryQuantized(
    const framework::ExecutionContext& ctx, framework::Tensor* output,
1063 1064 1065
    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
1066
    MKLDNNMemoryFormat output_format) {
1067 1068
  T* output_data = output->mutable_data<T>(ctx.GetPlace());
  const size_t dst_dims = dst_tz.size();
1069
  MKLDNNMemoryFormat dst_fmt;
1070

G
GaoWei8 已提交
1071 1072 1073 1074
  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));
1075
  dst_fmt = platform::MKLDNNFormatForSize(dst_dims, output_format);
1076

A
Adam 已提交
1077
  auto tmp_dst_md = platform::MKLDNNMemDesc(
1078
      {dst_tz}, paddle::framework::ToMKLDNNDataType(
1079
                    framework::DataTypeTrait<T>::DataType()),
1080
      dst_fmt);
1081
  dst_md.reset(new dnnl::memory::desc(tmp_dst_md));
A
Adam 已提交
1082
  dst_memory.reset(
1083
      new dnnl::memory(*dst_md, engine, to_void_cast<T>(output_data)));
1084
}
A
Adam Osewski 已提交
1085

J
Jacek Czaja 已提交
1086 1087
}  // namespace platform
}  // namespace paddle