mkldnn_reuse.h 40.6 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
template <typename T>
776
class ActivationMKLDNNHandler
777 778
    : public MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                     dnnl::eltwise_backward> {
779
 public:
780
  ActivationMKLDNNHandler(dnnl::algorithm algorithm,
781
                          const framework::ExecutionContext& ctx,
782
                          const dnnl::engine engine, Place cpu_place,
783
                          const framework::Tensor* in_x)
784 785 786
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                          dnnl::eltwise_backward>(engine,
                                                                  cpu_place) {
787 788
    float alpha = ctx.HasAttr("alpha") ? ctx.Attr<float>("alpha") : 0;
    float beta = ctx.HasAttr("beta") ? ctx.Attr<float>("beta") : 0;
789 790

    if (ctx.Type() == "scale") {
791 792
      bool bias_after_scale = ctx.Attr<bool>("bias_after_scale");
      auto* scale_tensor = ctx.Input<Tensor>("ScaleTensor");
793 794 795
      alpha = (scale_tensor == nullptr)
                  ? ctx.Attr<float>("scale")
                  : static_cast<float>(*(scale_tensor->data<T>()));
796 797 798 799 800
      beta = ctx.Attr<float>("bias");
      // if bias_after_scale == true
      //   out = scale*X + bias
      // else
      //   out = scale*(X + bias) = scale*X + scale*bias
801 802 803 804 805 806 807 808
      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");
809 810
    } else {
      // paddle uses beta but mkldnn uses alpha for swish
811
      if (algorithm == dnnl::algorithm::eltwise_swish) {
812 813 814
        std::swap(alpha, beta);
      } else if (algorithm == dnnl::algorithm::eltwise_bounded_relu) {
        alpha = ctx.Attr<float>("threshold");
815
      }
816
    }
817

818 819 820 821 822
    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()));
823

824 825 826
    auto src_tz = framework::vectorize<int64_t>(in_x->dims());
    auto src_fmt = src_tz.size() == 2 ? MKLDNNMemoryFormat::nc : in_x->format();
    auto md =
827
        dnnl::memory::desc(src_tz, platform::MKLDNNGetDataType<T>(), src_fmt);
828

829
    this->AcquireForwardPrimitiveDescriptor(dnnl::prop_kind::forward_training,
830
                                            algorithm, md, alpha, beta);
831 832
  }

833
  ActivationMKLDNNHandler(dnnl::algorithm algorithm,
834
                          const framework::ExecutionContext& ctx,
835
                          const dnnl::engine engine, Place cpu_place,
836
                          const framework::Tensor* in_x, const Tensor* out_grad)
837 838 839
      : platform::MKLDNNHandlerNoCachingT<T, dnnl::eltwise_forward,
                                          dnnl::eltwise_backward>(engine,
                                                                  cpu_place) {
840 841 842 843
    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
844
    if (algorithm == dnnl::algorithm::eltwise_swish) {
845 846 847 848
      std::swap(alpha, beta);
    } else if (algorithm == dnnl::algorithm::eltwise_bounded_relu) {
      alpha = ctx.Attr<float>("threshold");
    }
849

850 851 852 853 854 855 856
    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");
    }

857
    auto diff_dst_tz = framework::vectorize<int64_t>(out_grad->dims());
858

859 860 861 862
    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();
863

864 865 866 867 868
    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);
869

870
    this->AcquireForwardPrimitiveDescriptor(dnnl::prop_kind::forward_training,
871 872 873
                                            algorithm, src_md, alpha, beta);
    this->AcquireBackwardPrimitiveDescriptor(algorithm, diff_dst_md, src_md,
                                             alpha, beta);
874
  }
875

876
  std::shared_ptr<dnnl::memory> AcquireBackwardSrcMemory(
877 878
      const framework::Tensor* input) {
    const T* input_data = input->data<T>();
A
Adam 已提交
879
    return this->AcquireMemoryFromPrimitive(this->bwd_pd_->src_desc(),
880
                                            to_void_cast<T>(input_data));
881 882 883
  }
};

884
class ReorderMKLDNNHandler {
885
 public:
A
Adam 已提交
886
  ReorderMKLDNNHandler(std::vector<int64_t>& dims,  // NOLINT
887
                       framework::proto::VarType::Type vtype,
888
                       dnnl::memory::data_type dtype, dnnl::engine engine)
889
      : dims_(dims),
890
        vtype_(vtype),
891 892
        vtype_dst_(vtype),
        dtype_(dtype),
893 894
        dtype_dst_(dtype),
        engine_(engine) {}
895 896 897

  ReorderMKLDNNHandler(std::vector<int64_t>& dims,  // NOLINT
                       framework::proto::VarType::Type vtype,
898
                       dnnl::memory::data_type dtype,
899
                       framework::proto::VarType::Type vtype_dst,
900
                       dnnl::memory::data_type dtype_dst, dnnl::engine engine)
901
      : dims_(dims),
902 903 904
        vtype_(vtype),
        vtype_dst_(vtype_dst),
        dtype_(dtype),
905 906
        dtype_dst_(dtype_dst),
        engine_(engine) {}
907

908 909 910 911
  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);
912 913
  }

914
  std::shared_ptr<dnnl::memory> AcquireSubmemory(
915
      const std::vector<int64_t>& dims, const std::vector<int64_t>& offset,
916
      const std::shared_ptr<dnnl::memory>& mem_p) {
917
    auto sub_md = mem_p->get_desc().submemory_desc(dims, {offset});
918 919
    auto sub_mem_p = std::make_shared<dnnl::memory>(sub_md, engine_,
                                                    mem_p->get_data_handle());
920 921 922
    return sub_mem_p;
  }

923 924 925
  std::shared_ptr<dnnl::memory> AcquireDstMemory(framework::Tensor* output,
                                                 const MKLDNNMemoryFormat& fmt,
                                                 platform::Place place) {
926 927
    auto dst_md = platform::MKLDNNMemDesc(dims_, dtype_dst_, fmt);
    auto dst_data = output->mutable_data(place, vtype_dst_, dst_md.get_size());
928
    return std::make_shared<dnnl::memory>(dst_md, engine_, dst_data);
929 930
  }

931
  std::shared_ptr<dnnl::memory> AcquireDstMemory(
932
      framework::Tensor* output, const std::vector<int64_t>& dims,
933 934 935
      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());
936
    return std::make_shared<dnnl::memory>(dst_md, engine_, dst_data);
937 938
  }

939 940 941 942
  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));
943 944 945
  }

 private:
A
Adam 已提交
946
  std::vector<int64_t> dims_;
947
  framework::proto::VarType::Type vtype_, vtype_dst_;
948 949
  dnnl::memory::data_type dtype_, dtype_dst_;
  dnnl::engine engine_;
950 951
};

952 953 954
template <typename T>
static void SetDstMemoryQuantized(
    const framework::ExecutionContext& ctx, framework::Tensor* output,
955 956 957
    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
958
    MKLDNNMemoryFormat output_format) {
959 960
  T* output_data = output->mutable_data<T>(ctx.GetPlace());
  const size_t dst_dims = dst_tz.size();
961
  MKLDNNMemoryFormat dst_fmt;
962

G
GaoWei8 已提交
963 964 965 966
  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));
967
  dst_fmt = platform::MKLDNNFormatForSize(dst_dims, output_format);
968

A
Adam 已提交
969
  auto tmp_dst_md = platform::MKLDNNMemDesc(
970
      {dst_tz}, paddle::framework::ToMKLDNNDataType(
971
                    framework::DataTypeTrait<T>::DataType()),
972
      dst_fmt);
973
  dst_md.reset(new dnnl::memory::desc(tmp_dst_md));
A
Adam 已提交
974
  dst_memory.reset(
975
      new dnnl::memory(*dst_md, engine, to_void_cast<T>(output_data)));
976
}
A
Adam Osewski 已提交
977

J
Jacek Czaja 已提交
978 979
}  // namespace platform
}  // namespace paddle