test_mkldnn_op_nhwc.cc 10.6 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
#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"
25 26
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/enforce.h"
27
#include "paddle/phi/core/kernel_registry.h"
J
Jacek Czaja 已提交
28

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

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

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

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

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
55
  phi::CPUPlace p;
J
Jacek Czaja 已提交
56 57
  framework::Scope scope;

58
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
J
Jacek Czaja 已提交
59 60 61 62
  // Initialize input data
  std::uniform_real_distribution<float> dist(static_cast<float>(10.0),
                                             static_cast<float>(20.0));
  std::mt19937 engine;
63
  size_t numel = static_cast<size_t>(phi::product(dims));
J
Jacek Czaja 已提交
64 65 66 67 68 69
  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);
  }

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

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

  // Make pool2d followed by transpose

  auto ksize = std::vector<int>(2, 2);
78 79 80 81 82 83 84 85
  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 已提交
86 87 88 89 90 91

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

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

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

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

114
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
J
Jacek Czaja 已提交
115 116 117 118
  // Initialize input data
  std::uniform_real_distribution<float> dist(static_cast<float>(10.0),
                                             static_cast<float>(20.0));
  std::mt19937 engine;
119
  size_t numel = static_cast<size_t>(phi::product(dims));
J
Jacek Czaja 已提交
120 121 122 123 124 125
  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);
  }

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

  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);
136 137 138 139 140 141 142 143
  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 已提交
144 145 146 147 148 149

  auto axis = std::vector<int>(4, 0);
  axis[1] = 2;
  axis[2] = 3;
  axis[3] = 1;
  auto op_relu1 = framework::OpRegistry::CreateOp(
150 151 152
      "relu",
      {{"X", {"y"}}},
      {{"Out", {"u"}}},
J
Jacek Czaja 已提交
153 154 155 156 157 158 159 160 161 162 163 164
      {{"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
165 166
  PADDLE_ENFORCE_EQ(z->dims(),
                    expected_dims,
J
Jacek Czaja 已提交
167 168 169
                    platform::errors::InvalidArgument(
                        "Computed shape does not match expected shape"));
}
170 171 172 173

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
174
  phi::CPUPlace p;
175 176
  framework::Scope scope;

177
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
178 179 180 181 182 183 184 185 186 187 188
  // 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);
  }

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

  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);
198 199 200 201 202 203 204 205
  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}}});
206 207 208 209 210 211 212 213 214 215 216 217 218 219

  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
220 221
  PADDLE_ENFORCE_EQ(vzdata,
                    expected_dims,
222 223 224 225
                    platform::errors::InvalidArgument(
                        "Computed shape does not match expected shape"));
}

226 227 228
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
229
  phi::CPUPlace p;
230 231
  framework::Scope scope;

232
  InputVars input_name = {"x", scope.Var("x")->GetMutable<phi::DenseTensor>()};
233
  InputVars second_crop_input_name = {
234
      "v", scope.Var("v")->GetMutable<phi::DenseTensor>()};
235 236 237 238 239 240 241 242 243 244 245 246
  // 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);
247 248
  std::rotate(expected_dims_nchw.begin() + 1,
              expected_dims_nchw.end() - 1,
249 250 251
              expected_dims_nchw.end());
  second_crop_input_name.tensor->Resize(phi::make_ddim(expected_dims_nchw));
  const auto second_crop_input_md =
252 253
      dnnl::memory::desc(expected_dims_nchw,
                         dnnl::memory::data_type::f32,
254 255 256
                         dnnl::memory::format_tag::nhwc);
  second_crop_input_name.tensor->set_mem_desc(second_crop_input_md);

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

  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);
267 268 269 270 271 272 273 274
  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}}});
275 276

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

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

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

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

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