test_mkldnn_op_nhwc.cc 10.9 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);
J
Jacek Czaja 已提交
31
USE_OP_DEVICE_KERNEL(pool2d, MKLDNN);
32
USE_OP_ITSELF(relu);
J
Jacek Czaja 已提交
33
USE_OP_DEVICE_KERNEL(relu, MKLDNN);
H
hong 已提交
34
USE_OP_ITSELF(transpose);
J
Jacek Czaja 已提交
35
USE_OP_DEVICE_KERNEL(transpose, MKLDNN);
36 37
USE_OP_ITSELF(shape);
USE_OP_DEVICE_KERNEL(shape, MKLDNN);
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
namespace paddle {
namespace operators {

struct InputVars {
  std::string name;
  framework::LoDTensor *tensor;
};

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;

  InputVars input_name = {"x",
                          scope.Var("x")->GetMutable<framework::LoDTensor>()};
  // Initialize input data
  std::uniform_real_distribution<float> dist(static_cast<float>(10.0),
                                             static_cast<float>(20.0));
  std::mt19937 engine;
65
  size_t numel = static_cast<size_t>(phi::product(dims));
J
Jacek Czaja 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79
  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);
  }

  scope.Var("y")->GetMutable<framework::LoDTensor>();
  auto *z = scope.Var("z")->GetMutable<framework::LoDTensor>();

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

  // Make pool2d followed by transpose

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

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

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

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

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

  InputVars input_name = {"x",
                          scope.Var("x")->GetMutable<framework::LoDTensor>()};
  // Initialize input data
  std::uniform_real_distribution<float> dist(static_cast<float>(10.0),
                                             static_cast<float>(20.0));
  std::mt19937 engine;
122
  size_t numel = static_cast<size_t>(phi::product(dims));
J
Jacek Czaja 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
  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);
  }

  scope.Var("y")->GetMutable<framework::LoDTensor>();
  scope.Var("u")->GetMutable<framework::LoDTensor>();
  auto *z = scope.Var("z")->GetMutable<framework::LoDTensor>();

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

  auto axis = std::vector<int>(4, 0);
  axis[1] = 2;
  axis[2] = 3;
  axis[3] = 1;
  auto op_relu1 = framework::OpRegistry::CreateOp(
153 154 155
      "relu",
      {{"X", {"y"}}},
      {{"Out", {"u"}}},
J
Jacek Czaja 已提交
156 157 158 159 160 161 162 163 164 165 166 167
      {{"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
168 169
  PADDLE_ENFORCE_EQ(z->dims(),
                    expected_dims,
J
Jacek Czaja 已提交
170 171 172
                    platform::errors::InvalidArgument(
                        "Computed shape does not match expected shape"));
}
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

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;

  InputVars input_name = {"x",
                          scope.Var("x")->GetMutable<framework::LoDTensor>()};
  // 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);
  }

  scope.Var("y")->GetMutable<framework::LoDTensor>();
  auto *z = scope.Var("z")->GetMutable<framework::LoDTensor>();

  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);
202 203 204 205 206 207 208 209
  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}}});
210 211 212 213 214 215 216 217 218 219 220 221 222 223

  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
224 225
  PADDLE_ENFORCE_EQ(vzdata,
                    expected_dims,
226 227 228 229
                    platform::errors::InvalidArgument(
                        "Computed shape does not match expected shape"));
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
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;

  InputVars input_name = {"x",
                          scope.Var("x")->GetMutable<framework::LoDTensor>()};
  InputVars second_crop_input_name = {
      "v", scope.Var("v")->GetMutable<framework::LoDTensor>()};
  // 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);
252 253
  std::rotate(expected_dims_nchw.begin() + 1,
              expected_dims_nchw.end() - 1,
254 255 256
              expected_dims_nchw.end());
  second_crop_input_name.tensor->Resize(phi::make_ddim(expected_dims_nchw));
  const auto second_crop_input_md =
257 258
      dnnl::memory::desc(expected_dims_nchw,
                         dnnl::memory::data_type::f32,
259 260 261 262 263 264 265 266 267 268 269 270 271
                         dnnl::memory::format_tag::nhwc);
  second_crop_input_name.tensor->set_mem_desc(second_crop_input_md);

  scope.Var("y")->GetMutable<framework::LoDTensor>();
  auto *z = scope.Var("z")->GetMutable<framework::LoDTensor>();

  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);
272 273 274 275 276 277 278 279
  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}}});
280 281

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

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

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

  // Verify shape of output
293 294
  PADDLE_ENFORCE_EQ(z->dims(),
                    expected_dims,
295 296 297 298
                    platform::errors::InvalidArgument(
                        "Output shape does not match expected output shape"));
}

J
Jacek Czaja 已提交
299 300
}  // namespace operators
}  // namespace paddle