test_mkldnn_op_nhwc.cc 10.7 KB
Newer Older
J
Jacek Czaja 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cstdlib>
#include <memory>
#include <random>
19

J
Jacek Czaja 已提交
20 21 22 23 24 25 26 27
#include "gtest/gtest.h"
#include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/platform/device_context.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/fluid/platform/place.h"
28
#include "paddle/phi/core/kernel_registry.h"
J
Jacek Czaja 已提交
29

F
From00 已提交
30
USE_OP_ITSELF(pool2d);
31
USE_OP_DEVICE_KERNEL(pool2d, MKLDNN);
32
USE_OP_ITSELF(relu);
33
PD_DECLARE_KERNEL(relu, OneDNN, ONEDNN);
H
hong 已提交
34
USE_OP_ITSELF(transpose);
J
Jacek Czaja 已提交
35
USE_OP_DEVICE_KERNEL(transpose, MKLDNN);
36
USE_OP_ITSELF(shape);
37
PD_DECLARE_KERNEL(shape, OneDNN, ONEDNN);
38 39
USE_OP_ITSELF(crop);
USE_OP_DEVICE_KERNEL(crop, CPU);
J
Jacek Czaja 已提交
40

F
From00 已提交
41
PD_DECLARE_KERNEL(pool2d, CPU, ALL_LAYOUT);
42
PD_DECLARE_KERNEL(relu, CPU, ALL_LAYOUT);
43
PD_DECLARE_KERNEL(shape, CPU, ALL_LAYOUT);
44

J
Jacek Czaja 已提交
45 46 47 48 49
namespace paddle {
namespace operators {

struct InputVars {
  std::string name;
50
  phi::DenseTensor *tensor;
J
Jacek Czaja 已提交
51 52 53 54 55 56 57 58
};

TEST(test_pool2d_transpose_nhwc, cpu_place) {
  framework::DDim dims({1, 4, 8, 512});           // NHWC shape
  framework::DDim expected_dims({1, 7, 512, 3});  // NHWC expected shape
  platform::CPUPlace p;
  framework::Scope scope;

59
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
J
Jacek Czaja 已提交
60 61 62 63
  // Initialize input data
  std::uniform_real_distribution<float> dist(static_cast<float>(10.0),
                                             static_cast<float>(20.0));
  std::mt19937 engine;
64
  size_t numel = static_cast<size_t>(phi::product(dims));
J
Jacek Czaja 已提交
65 66 67 68 69 70
  input_name.tensor->Resize(dims);
  auto data_ptr = input_name.tensor->mutable_data<float>(p);
  for (size_t i = 0; i < numel; ++i) {
    data_ptr[i] = dist(engine);
  }

71 72
  scope.Var("y")->GetMutable<phi::DenseTensor>();
  auto *z = scope.Var("z")->GetMutable<phi::DenseTensor>();
J
Jacek Czaja 已提交
73 74 75 76 77 78

  auto &pool = platform::DeviceContextPool::Instance();

  // Make pool2d followed by transpose

  auto ksize = std::vector<int>(2, 2);
79 80 81 82 83 84 85 86
  auto op_pool =
      framework::OpRegistry::CreateOp("pool2d",
                                      {{"X", {"x"}}},
                                      {{"Out", {"y"}}},
                                      {{"pooling_type", {std::string("max")}},
                                       {"ksize", {ksize}},
                                       {"data_format", {std::string("NHWC")}},
                                       {"use_mkldnn", {true}}});
J
Jacek Czaja 已提交
87 88 89 90 91 92

  auto axis = std::vector<int>(4, 0);
  axis[1] = 2;
  axis[2] = 3;
  axis[3] = 1;
  auto op_transpose = framework::OpRegistry::CreateOp(
93 94 95
      "transpose",
      {{"X", {"y"}}},
      {{"Out", {"z"}}},
J
Jacek Czaja 已提交
96 97 98 99 100 101 102
      {{"axis", {axis}}, {"use_mkldnn", {true}}});

  op_pool->Run(scope, p);
  op_transpose->Run(scope, p);
  pool.Get(p)->Wait();

  // Verify shape of output
103 104
  PADDLE_ENFORCE_EQ(z->dims(),
                    expected_dims,
J
Jacek Czaja 已提交
105 106 107 108
                    platform::errors::InvalidArgument(
                        "Computed shape does not match expected shape"));
}

J
Jacek Czaja 已提交
109 110
TEST(test_pool2d_relu_relu_nhwc, cpu_place) {
  framework::DDim dims({1, 4, 8, 512});           // NHWC shape
J
Jacek Czaja 已提交
111
  framework::DDim expected_dims({1, 512, 3, 7});  // NCHW expected shape
J
Jacek Czaja 已提交
112 113 114
  platform::CPUPlace p;
  framework::Scope scope;

115
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
J
Jacek Czaja 已提交
116 117 118 119
  // Initialize input data
  std::uniform_real_distribution<float> dist(static_cast<float>(10.0),
                                             static_cast<float>(20.0));
  std::mt19937 engine;
120
  size_t numel = static_cast<size_t>(phi::product(dims));
J
Jacek Czaja 已提交
121 122 123 124 125 126
  input_name.tensor->Resize(dims);
  auto data_ptr = input_name.tensor->mutable_data<float>(p);
  for (size_t i = 0; i < numel; ++i) {
    data_ptr[i] = dist(engine);
  }

127 128 129
  scope.Var("y")->GetMutable<phi::DenseTensor>();
  scope.Var("u")->GetMutable<phi::DenseTensor>();
  auto *z = scope.Var("z")->GetMutable<phi::DenseTensor>();
J
Jacek Czaja 已提交
130 131 132 133 134 135 136

  auto &pool = platform::DeviceContextPool::Instance();

  // Make pool2d(oneDNN) followed by relu(CPU paddle) followed by
  // relu(oneDNN). Second relu should make a shape rotation to NCHW

  auto ksize = std::vector<int>(2, 2);
137 138 139 140 141 142 143 144
  auto op_pool =
      framework::OpRegistry::CreateOp("pool2d",
                                      {{"X", {"x"}}},
                                      {{"Out", {"y"}}},
                                      {{"pooling_type", {std::string("max")}},
                                       {"ksize", {ksize}},
                                       {"data_format", {std::string("NHWC")}},
                                       {"use_mkldnn", {true}}});
J
Jacek Czaja 已提交
145 146 147 148 149 150

  auto axis = std::vector<int>(4, 0);
  axis[1] = 2;
  axis[2] = 3;
  axis[3] = 1;
  auto op_relu1 = framework::OpRegistry::CreateOp(
151 152 153
      "relu",
      {{"X", {"y"}}},
      {{"Out", {"u"}}},
J
Jacek Czaja 已提交
154 155 156 157 158 159 160 161 162 163 164 165
      {{"axis", {axis}}, {"use_mkldnn", {false}}});

  auto op_relu2 = framework::OpRegistry::CreateOp(
      "relu", {{"X", {"u"}}}, {{"Out", {"z"}}}, {{"use_mkldnn", {true}}});

  op_pool->Run(scope, p);
  op_relu1->Run(scope, p);
  op_relu2->Run(scope, p);

  pool.Get(p)->Wait();

  // Verify shape of output
166 167
  PADDLE_ENFORCE_EQ(z->dims(),
                    expected_dims,
J
Jacek Czaja 已提交
168 169 170
                    platform::errors::InvalidArgument(
                        "Computed shape does not match expected shape"));
}
171 172 173 174 175 176 177

TEST(test_pool2d_shape_nhwc, cpu_place) {
  framework::DDim dims({1, 4, 8, 512});              // NHWC shape
  std::vector<int32_t> expected_dims{1, 3, 7, 512};  // NHWC expected shape
  platform::CPUPlace p;
  framework::Scope scope;

178
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
179 180 181 182 183 184 185 186 187 188 189
  // Initialize input data
  std::uniform_real_distribution<float> dist(static_cast<float>(10.0),
                                             static_cast<float>(20.0));
  std::mt19937 engine;
  size_t numel = static_cast<size_t>(phi::product(dims));
  input_name.tensor->Resize(dims);
  auto data_ptr = input_name.tensor->mutable_data<float>(p);
  for (size_t i = 0; i < numel; ++i) {
    data_ptr[i] = dist(engine);
  }

190 191
  scope.Var("y")->GetMutable<phi::DenseTensor>();
  auto *z = scope.Var("z")->GetMutable<phi::DenseTensor>();
192 193 194 195 196 197 198

  auto &pool = platform::DeviceContextPool::Instance();

  // Make pool2d followed by shape. shape for NHWC should return
  // as output tensor not-rotated shape of Pool (

  auto ksize = std::vector<int>(2, 2);
199 200 201 202 203 204 205 206
  auto op_pool =
      framework::OpRegistry::CreateOp("pool2d",
                                      {{"X", {"x"}}},
                                      {{"Out", {"y"}}},
                                      {{"pooling_type", {std::string("max")}},
                                       {"ksize", {ksize}},
                                       {"data_format", {std::string("NHWC")}},
                                       {"use_mkldnn", {true}}});
207 208 209 210 211 212 213 214 215 216 217 218 219 220

  auto op_shape = framework::OpRegistry::CreateOp(
      "shape", {{"Input", {"y"}}}, {{"Out", {"z"}}}, {{"use_mkldnn", {true}}});

  op_pool->Run(scope, p);
  op_shape->Run(scope, p);

  pool.Get(p)->Wait();

  // repack tensor data into vector for easy comparison
  auto *zdata = z->data<int32_t>();
  std::vector<int32_t> vzdata(zdata, zdata + z->numel());

  // Verify shape of output
221 222
  PADDLE_ENFORCE_EQ(vzdata,
                    expected_dims,
223 224 225 226
                    platform::errors::InvalidArgument(
                        "Computed shape does not match expected shape"));
}

227 228 229 230 231 232
TEST(test_pool2d_crop_nhwc, cpu_place) {
  framework::DDim dims({1, 4, 8, 512});           // NHWC shape
  framework::DDim expected_dims({1, 3, 7, 512});  // NCHW expected shape
  platform::CPUPlace p;
  framework::Scope scope;

233
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
234
  InputVars second_crop_input_name = {
235
      "v", scope.Var("v")->GetMutable<phi::DenseTensor>()};
236 237 238 239 240 241 242 243 244 245 246 247
  // Initialize input data
  std::uniform_real_distribution<float> dist(10.0f, 20.0f);
  std::mt19937 engine;
  size_t numel = static_cast<size_t>(phi::product(dims));
  input_name.tensor->Resize(dims);
  auto data_ptr = input_name.tensor->mutable_data<float>(p);
  for (size_t i = 0; i < numel; ++i) {
    data_ptr[i] = dist(engine);
  }
  // Second input (Y) to crop is having no buffer
  // but as it is MKLDNN then its shape order should be NCHW
  auto expected_dims_nchw = phi::vectorize<int64_t>(expected_dims);
248 249
  std::rotate(expected_dims_nchw.begin() + 1,
              expected_dims_nchw.end() - 1,
250 251 252
              expected_dims_nchw.end());
  second_crop_input_name.tensor->Resize(phi::make_ddim(expected_dims_nchw));
  const auto second_crop_input_md =
253 254
      dnnl::memory::desc(expected_dims_nchw,
                         dnnl::memory::data_type::f32,
255 256 257
                         dnnl::memory::format_tag::nhwc);
  second_crop_input_name.tensor->set_mem_desc(second_crop_input_md);

258 259
  scope.Var("y")->GetMutable<phi::DenseTensor>();
  auto *z = scope.Var("z")->GetMutable<phi::DenseTensor>();
260 261 262 263 264 265 266 267

  auto &pool = platform::DeviceContextPool::Instance();

  // Make pool2d followed by crop. crop may have Y input as
  // non buffered so the path to be executed is handling oneDNN kernel
  // that is followed by CPU kernel with non-buffered Input

  auto ksize = std::vector<int>(2, 2);
268 269 270 271 272 273 274 275
  auto op_pool =
      framework::OpRegistry::CreateOp("pool2d",
                                      {{"X", {"x"}}},
                                      {{"Out", {"y"}}},
                                      {{"pooling_type", {std::string("max")}},
                                       {"ksize", {ksize}},
                                       {"data_format", {std::string("NHWC")}},
                                       {"use_mkldnn", {true}}});
276 277

  std::vector<int> offsets{0, 0, 0, 0};
278 279 280 281
  auto op_crop = framework::OpRegistry::CreateOp("crop",
                                                 {{"X", {"y"}}, {"Y", {"v"}}},
                                                 {{"Out", {"z"}}},
                                                 {{"offsets", {offsets}}});
282 283 284 285 286 287 288

  op_pool->Run(scope, p);
  op_crop->Run(scope, p);

  pool.Get(p)->Wait();

  // Verify shape of output
289 290
  PADDLE_ENFORCE_EQ(z->dims(),
                    expected_dims,
291 292 293 294
                    platform::errors::InvalidArgument(
                        "Output shape does not match expected output shape"));
}

J
Jacek Czaja 已提交
295 296
}  // namespace operators
}  // namespace paddle