Skip to content

Commit

Permalink
Fix to issue #25537 (#27546)
Browse files Browse the repository at this point in the history
* - condidate fix to issue #25537

test=develop

* - UT for transpose NHWC

test=develop
  • Loading branch information
jczaja authored Oct 1, 2020
1 parent 966447e commit b9fda2f
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 1 deletion.
2 changes: 1 addition & 1 deletion paddle/fluid/framework/data_layout_transform.cc
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ void innerTransDataLayoutFromMKLDNN(DataLayout in_layout, DataLayout out_layout,
// As MKL-DNN description was in NCHW and paddle is expecting NHWC
platform::MatchShapeToLayout(out, in_layout, out_layout);

out->set_layout(out_layout);
out->set_layout(DataLayout::kNCHW);
// reset format since the out tensor will be feed to non-MKLDNN OPkernel
out->set_format(MKLDNNMemoryFormat::undef);
}
Expand Down
1 change: 1 addition & 0 deletions paddle/fluid/operators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,5 @@ cc_test(op_debug_string_test SRCS op_debug_string_test.cc DEPS elementwise_add_o

if(WITH_MKLDNN)
include(mkldnn/inplace_op_tests.cmake)
include(mkldnn/nhwc_op_tests.cmake)
endif()
2 changes: 2 additions & 0 deletions paddle/fluid/operators/mkldnn/nhwc_op_tests.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cc_test(test_mkldnn_op_nhwc SRCS mkldnn/test_mkldnn_op_nhwc.cc DEPS op_registry pool_op pooling transpose_op scope device_context enforce executor)

94 changes: 94 additions & 0 deletions paddle/fluid/operators/mkldnn/test_mkldnn_op_nhwc.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// 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>
#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"

USE_OP(pool2d);
USE_OP_DEVICE_KERNEL(pool2d, MKLDNN);
USE_OP(transpose);
USE_OP_DEVICE_KERNEL(transpose, MKLDNN);

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;
size_t numel = static_cast<size_t>(framework::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 transpose

auto ksize = std::vector<int>(2, 2);
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}}});

auto axis = std::vector<int>(4, 0);
axis[1] = 2;
axis[2] = 3;
axis[3] = 1;
auto op_transpose = framework::OpRegistry::CreateOp(
"transpose", {{"X", {"y"}}}, {{"Out", {"z"}}},
{{"axis", {axis}}, {"use_mkldnn", {true}}});

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

// Verify shape of output
PADDLE_ENFORCE_EQ(z->dims(), expected_dims,
platform::errors::InvalidArgument(
"Computed shape does not match expected shape"));
}

} // namespace operators
} // namespace paddle
13 changes: 13 additions & 0 deletions paddle/fluid/operators/transpose_op.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ class TransposeOp : public framework::OperatorWithKernel {
}

framework::DDim out_dims(x_dims);
#ifdef PADDLE_WITH_MKLDNN
// Here we need to match dims to paddle layout
// as we are producing non-oneDNN result
if ((x_dims.size() >= 3) &&
(paddle::platform::MKLDNNDeviceContext::tls()
.get_cur_paddle_data_layout() == framework::DataLayout::kNHWC)) {
auto dims = framework::vectorize<int>(x_dims);
std::rotate(dims.begin() + 1, dims.begin() + 2, dims.end());
x_dims = x_dims.reshape(dims);
VLOG(3)
<< "Rotating Shape in Transpose from: kMKLDNN to: kNHWC output_shape";
}
#endif
for (size_t i = 0; i < axis_size; i++) {
out_dims[i] = x_dims[axis[i]];
}
Expand Down
22 changes: 22 additions & 0 deletions paddle/fluid/platform/mkldnn_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ limitations under the License. */
#pragma once

#include <algorithm>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -81,19 +83,39 @@ inline void MatchShapeToLayout(framework::Tensor* tensor_in,
return;
}

auto print_dims = [](const std::vector<int>& dims) {
std::ostringstream oss;

if (!dims.empty()) {
oss << "[";
// Convert all but the last element to avoid a trailing ","
std::copy(dims.begin(), dims.end() - 1,
std::ostream_iterator<int>(oss, ","));

// Now add the last element with no delimiter
oss << dims.back() << "]";
}

return oss.str();
};

switch (from) {
case framework::DataLayout::kMKLDNN:
if (to == framework::DataLayout::kNHWC) {
auto dims = framework::vectorize<int>(tensor_in->dims());
std::rotate(dims.begin() + 1, dims.begin() + 2, dims.end());
tensor_in->Resize(framework::make_ddim(dims));
VLOG(3) << "Rotating Shape from: kMKLDNN to: kNHWC output_shape"
<< print_dims(dims);
}
break;
case framework::DataLayout::kNHWC:
if (to == framework::DataLayout::kMKLDNN) {
auto dims = framework::vectorize<int>(tensor_in->dims());
std::rotate(dims.begin() + 1, dims.end() - 1, dims.end());
tensor_in->Resize(framework::make_ddim(dims));
VLOG(3) << "Rotating Shape from: kNHWC to: kMKLDNN output_shape"
<< print_dims(dims);
}
break;
default:
Expand Down

0 comments on commit b9fda2f

Please sign in to comment.