From 2a77418668985bb4d9acdc7cd521a14d08b764ce Mon Sep 17 00:00:00 2001 From: tensor-tang Date: Thu, 2 Nov 2017 21:34:04 +0800 Subject: [PATCH 1/4] refine reset input buffers, make it support more than one input. --- paddle/gserver/layers/MKLDNNLayer.cpp | 12 +++++++----- paddle/gserver/layers/MKLDNNLayer.h | 7 +++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/paddle/gserver/layers/MKLDNNLayer.cpp b/paddle/gserver/layers/MKLDNNLayer.cpp index 663a10509857e..4347ab821d8ce 100644 --- a/paddle/gserver/layers/MKLDNNLayer.cpp +++ b/paddle/gserver/layers/MKLDNNLayer.cpp @@ -171,14 +171,16 @@ void MKLDNNLayer::resetWithMatrix(MKLDNNMatrixPtr& dnn, } void MKLDNNLayer::resetInValue( - MKLDNNMatrixPtr& in, const std::shared_ptr& intPD) { + MKLDNNMatrixPtr& in, + const std::shared_ptr& intPD, + size_t inputIdx) { cvtInVal_ = nullptr; extInVal_ = nullptr; in = nullptr; CHECK_GT(bs_ * ic_ * ih_ * iw_, 0); auto extPD = MKLDNNMatrix::createPrimitiveDesc( {bs_, ic_, ih_, iw_}, format::nchw, engine_); - const MatrixPtr& inMat = inputLayers_[0]->getOutputValue(); + const MatrixPtr& inMat = inputLayers_[inputIdx]->getOutputValue(); in = std::dynamic_pointer_cast(inMat); CHECK_EQ(inputIsOnlyMKLDNN(), in != nullptr); if (in == nullptr || in->getFormat() == format::nc) { @@ -216,11 +218,12 @@ void MKLDNNLayer::resetOutValue(MKLDNNMatrixPtr& out, } void MKLDNNLayer::resetInGrad(MKLDNNMatrixPtr& in, - memory::primitive_desc intPD) { + memory::primitive_desc intPD, + size_t inputIdx) { cvtInGrad_ = nullptr; extInGrad_ = nullptr; in = nullptr; - LayerPtr& input = inputLayers_[0]; + LayerPtr& input = inputLayers_[inputIdx]; if (input->getOutputGrad() == nullptr) { // no need input grad return; @@ -245,7 +248,6 @@ void MKLDNNLayer::resetInGrad(MKLDNNMatrixPtr& in, return; } // need create reorder - // TODO(TJ): add macro definition to simplify it CHECK(extInVal_ != nullptr && isPaddleFormat(extInVal_->getFormat())) << "should have external input value and the format must be nchw(nc)"; extInGrad_ = MKLDNNMatrix::create(extInVal_->getPrimitiveDesc(), inMat); diff --git a/paddle/gserver/layers/MKLDNNLayer.h b/paddle/gserver/layers/MKLDNNLayer.h index 2c21a5b2aaecb..7479c34c92b52 100644 --- a/paddle/gserver/layers/MKLDNNLayer.h +++ b/paddle/gserver/layers/MKLDNNLayer.h @@ -199,7 +199,8 @@ class MKLDNNLayer : public Layer { */ void resetInValue( MKLDNNMatrixPtr& in, - const std::shared_ptr& intPD = nullptr); + const std::shared_ptr& intPD = nullptr, + size_t inputIdx = 0); /** * reset output value from internal primitive desc. @@ -212,7 +213,9 @@ class MKLDNNLayer : public Layer { * reset input grad from internal primitive desc. * reset both internal and external buffer and create reorder if necessary. */ - void resetInGrad(MKLDNNMatrixPtr& in, mkldnn::memory::primitive_desc intPD); + void resetInGrad(MKLDNNMatrixPtr& in, + mkldnn::memory::primitive_desc intPD, + size_t inputIdx = 0); /** * reset output grad from internal primitive desc. From 8ff34368291c55123e328f12d08d8d25b4c1c10b Mon Sep 17 00:00:00 2001 From: tensor-tang Date: Thu, 2 Nov 2017 21:51:48 +0800 Subject: [PATCH 2/4] add MKLDNNAddtoLayer files --- paddle/gserver/layers/MKLDNNAddtoLayer.cpp | 154 +++++++++++++++++++++ paddle/gserver/layers/MKLDNNAddtoLayer.h | 110 +++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 paddle/gserver/layers/MKLDNNAddtoLayer.cpp create mode 100644 paddle/gserver/layers/MKLDNNAddtoLayer.h diff --git a/paddle/gserver/layers/MKLDNNAddtoLayer.cpp b/paddle/gserver/layers/MKLDNNAddtoLayer.cpp new file mode 100644 index 0000000000000..8eb700723f2cf --- /dev/null +++ b/paddle/gserver/layers/MKLDNNAddtoLayer.cpp @@ -0,0 +1,154 @@ +/* Copyright (c) 2017 PaddlePaddle Authors. All Rights Reserve. + +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 "MKLDNNAddtoLayer.h" + +using namespace mkldnn; // NOLINT + +namespace paddle { + +REGISTER_LAYER(mkldnn_addto, MKLDNNAddtoLayer); + +bool MKLDNNAddtoLayer::init(const LayerMap& layerMap, + const ParameterMap& parameterMap) { + if (!MKLDNNLayer::init(layerMap, parameterMap)) { + return false; + } + + layerSize_ = getSize(); + for (size_t i = 0; i < inputLayers_.size(); i++) { + CHECK_EQ(layerSize_, inputLayers_[i]->getSize()) << "input size must equal"; + } + if (biasParameter_.get() != NULL) { + biases_ = + std::unique_ptr(new Weight(1, layerSize_, biasParameter_, 0)); + } + return true; +} + +void MKLDNNAddtoLayer::reshape( + int& bs, int& ic, int& ih, int& iw, int oc, int& oh, int& ow) { + CHECK_EQ(layerSize_, getSize()) << "this layer size can not be changed"; + reshapeInput(bs, ih, iw); + ic = inputLayers_[0]->getSize() / ih / iw; + CHECK_EQ((size_t)ic * ih * iw, inputLayers_[0]->getSize()); + CHECK_EQ(inputElemenCnt_, (size_t)bs * ic * ih * iw); + for (size_t i = 0; i < inputLayers_.size(); i++) { + CHECK_EQ(int64_t(bs), inputLayers_[i]->getOutput().getBatchSize()); + CHECK_EQ(layerSize_, inputLayers_[i]->getSize()); + } + + oc = ic; + oh = ih; + ow = iw; + reshapeOutput(oh, ow); + resizeOutput(bs, oc * oh * ow); + printSizeInfo(); +} + +void MKLDNNAddtoLayer::resetFwd(std::vector& pipeline, + MKLDNNMatrixPtr& in, + MKLDNNMatrixPtr& wgt, + MKLDNNMatrixPtr& bias, + MKLDNNMatrixPtr& out) { + if (biases_) { + LOG(FATAL) << "not implemented yet"; + } + resetFwdBuffers(inVals_, out); + in = inVals_[0]; + + std::shared_ptr fwdPD; + resetFwdPD(fwdPD, inVals_, out); + + resetFwdPipeline(pipeline, fwdPD, inVals_, out); +} + +void MKLDNNAddtoLayer::resetBwd(std::vector& pipeline, + MKLDNNMatrixPtr& in, + MKLDNNMatrixPtr& wgt, + MKLDNNMatrixPtr& bias, + MKLDNNMatrixPtr& out) { + resetBwdBuffers(inGrads_, out); + in = inGrads_[0]; + + // backward only need share output grad to input grad + for (size_t i = 0; i < inGrads_.size(); i++) { + if (inGrads_[i] != nullptr) { + inGrads_[i] = out; + inputLayers_[i]->getOutputGrad()->setData(inGrads_[i]->getData()); + } + } +} + +void MKLDNNAddtoLayer::updateWeights(const UpdateCallback& callback) { + if (biases_ && biases_->getWGrad()) { + biases_->getParameterPtr()->incUpdate(callback); + } +} + +void MKLDNNAddtoLayer::resetFwdBuffers(std::vector& inputs, + MKLDNNMatrixPtr& out) { + inputs.resize(inputLayers_.size()); + for (size_t i = 0; i < inputs.size(); i++) { + resetInValue(inputs[i], nullptr, i); + CHECK(inputs[i]); + inputs[i]->downSpatial(); + } + for (size_t i = 1; i < inputs.size(); i++) { + CHECK_PRIMITIVE_DESC_EQ(inputs[i], inputs[0]->getPrimitiveDesc()); + } + + resetOutValue(out, inputs[0]->getPrimitiveDesc()); +} + +void MKLDNNAddtoLayer::resetFwdPD(std::shared_ptr& pd, + std::vector& inputs, + MKLDNNMatrixPtr out) { + std::vector scales(inputs.size(), 1.0); + std::vector srcPDs; + for (size_t i = 0; i < inputs.size(); i++) { + srcPDs.push_back(inputs[i]->getPrimitiveDesc()); + } + CHECK(out); + pd.reset(new sum::primitive_desc(out->getMemoryDesc(), scales, srcPDs)); + CHECK_PRIMITIVE_DESC_EQ(out, pd->dst_primitive_desc()); +} + +void MKLDNNAddtoLayer::resetFwdPipeline( + std::vector& pipeline, + std::shared_ptr& pd, + std::vector& inputs, + MKLDNNMatrixPtr& out) { + std::vector srcs; + for (size_t i = 0; i < inputs.size(); i++) { + srcs.push_back(*(inputs[i])); + } + fwd_.reset(new sum(*pd, srcs, *out)); + pipeline.push_back(*fwd_); +} + +void MKLDNNAddtoLayer::resetBwdBuffers(std::vector& inputs, + MKLDNNMatrixPtr& out) { + CHECK(outVal_); + resetOutGrad(out, outVal_->getPrimitiveDesc()); + CHECK(out); + + inputs.resize(inputLayers_.size()); + for (size_t i = 0; i < inputs.size(); i++) { + resetInGrad(inputs[i], inVal_->getPrimitiveDesc(), i); + CHECK_PRIMITIVE_DESC_EQ(inputs[i], out->getPrimitiveDesc()); + } +} + +} // namespace paddle diff --git a/paddle/gserver/layers/MKLDNNAddtoLayer.h b/paddle/gserver/layers/MKLDNNAddtoLayer.h new file mode 100644 index 0000000000000..15f74ec5bdf3d --- /dev/null +++ b/paddle/gserver/layers/MKLDNNAddtoLayer.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2017 PaddlePaddle Authors. All Rights Reserve. + +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 + +#include "MKLDNNLayer.h" +#include "mkldnn.hpp" + +namespace paddle { + +/** + * @brief A subclass of MKLDNNLayer Addto layer. + * + * The config file api is mkldnn_addto + */ +class MKLDNNAddtoLayer : public MKLDNNLayer { +protected: + std::vector inVals_; + std::vector inGrads_; + + // layer size == ic * ih * iw == oc * oh *ow, and can not be changed + size_t layerSize_; + + // TODO(TJ): this part has not been optimized by MKL-DNN + std::unique_ptr biases_; + +public: + explicit MKLDNNAddtoLayer(const LayerConfig& config) : MKLDNNLayer(config) {} + + ~MKLDNNAddtoLayer() {} + + bool init(const LayerMap& layerMap, + const ParameterMap& parameterMap) override; + + void reshape( + int& bs, int& ic, int& ih, int& iw, int oc, int& oh, int& ow) override; + + void resetFwd(std::vector& pipeline, + MKLDNNMatrixPtr& in, + MKLDNNMatrixPtr& wgt, + MKLDNNMatrixPtr& bias, + MKLDNNMatrixPtr& out) override; + + void resetBwd(std::vector& pipeline, + MKLDNNMatrixPtr& in, + MKLDNNMatrixPtr& wgt, + MKLDNNMatrixPtr& bias, + MKLDNNMatrixPtr& out) override; + + void updateWeights(const UpdateCallback& callback) override; + + void printValueFormat() override { + for (size_t i = 0; i < inVals_.size(); ++i) { + VLOG(MKLDNN_FMTS) << i << " input: " << inVals_[i]->getFormat() << " >>>"; + } + if (outVal_) { + VLOG(MKLDNN_FMTS) << outVal_->getFormat() << " >>> "; + } + if (extOutVal_) { + VLOG(MKLDNN_FMTS) << extOutVal_->getFormat(); + } + } + + void printGradFormat() override { + if (extOutGrad_) { + VLOG(MKLDNN_FMTS) << extOutGrad_->getFormat(); + } + if (outGrad_) { + VLOG(MKLDNN_FMTS) << outGrad_->getFormat() << " <<< "; + } + for (size_t i = 0; i < inGrads_.size(); ++i) { + VLOG(MKLDNN_FMTS) << i << " input: " << inGrads_[i]->getFormat() << "<<<"; + } + } + +protected: + /** + * Forward functions: reset buffers(inputs, output, bias), + * reset primitive descriptor, + * reset pipeline. + */ + void resetFwdBuffers(std::vector& inputs, + MKLDNNMatrixPtr& out); + void resetFwdPD(std::shared_ptr& pd, + std::vector& inputs, + MKLDNNMatrixPtr out); + void resetFwdPipeline(std::vector& pipeline, + std::shared_ptr& pd, + std::vector& inputs, + MKLDNNMatrixPtr& out); + + /** + * Backward functions: reset buffers(inputs, output, bias) + */ + void resetBwdBuffers(std::vector& inputs, + MKLDNNMatrixPtr& out); +}; + +} // namespace paddle From 3fb6451c3a387854d10f59a75cd4106e84f007de Mon Sep 17 00:00:00 2001 From: tensor-tang Date: Thu, 2 Nov 2017 22:00:03 +0800 Subject: [PATCH 3/4] add mkldnn_addto unit test and pass it --- paddle/gserver/layers/MKLDNNLayer.cpp | 2 +- paddle/gserver/tests/MKLDNNTester.cpp | 6 ++-- paddle/gserver/tests/test_MKLDNN.cpp | 43 +++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/paddle/gserver/layers/MKLDNNLayer.cpp b/paddle/gserver/layers/MKLDNNLayer.cpp index 4347ab821d8ce..5fd62f4f73b18 100644 --- a/paddle/gserver/layers/MKLDNNLayer.cpp +++ b/paddle/gserver/layers/MKLDNNLayer.cpp @@ -77,7 +77,7 @@ void MKLDNNLayer::forward(PassType passType) { needResetBwd_ = true; } - if (inputLayers_[0]->getType() == "data") { + if (inputLayers_[0]->getType() == "data" && inputLayers_.size() == 1) { // Update input value data when input layer is "data" type, // since the input value data address might be changed. CHECK(extInVal_); diff --git a/paddle/gserver/tests/MKLDNNTester.cpp b/paddle/gserver/tests/MKLDNNTester.cpp index 7670cb88fb67d..afe1608eab8ea 100644 --- a/paddle/gserver/tests/MKLDNNTester.cpp +++ b/paddle/gserver/tests/MKLDNNTester.cpp @@ -132,7 +132,7 @@ void MKLDNNTester::checkForward() { VLOG(MKLDNN_TESTS) << "Check Forward"; printTopDatas(); double delta = - compareMatrix(dnnLayer_->getOutputValue(), refLayer_->getOutputValue()); + compareMatrix(refLayer_->getOutputValue(), dnnLayer_->getOutputValue()); EXPECT_LE(fabs(delta), eps_); } @@ -147,7 +147,7 @@ void MKLDNNTester::checkBackwardData() { VLOG(MKLDNN_ALL) << "Reference Backward Result: InputGrad " << i; printMatrix(refDiff); - double delta = compareMatrix(dnnDiff, refDiff); + double delta = compareMatrix(refDiff, dnnDiff); EXPECT_LE(fabs(delta), eps_); if (isBN) { // the other two inputs in batch norm are for moving mean and var @@ -177,7 +177,7 @@ void MKLDNNTester::checkBackwardWgts() { << parameters_[REF][i]->getName(); printVector(ref); - double delta = compareVector(dnn, ref); + double delta = compareVector(ref, dnn); EXPECT_LE(fabs(delta), eps_); } diff --git a/paddle/gserver/tests/test_MKLDNN.cpp b/paddle/gserver/tests/test_MKLDNN.cpp index d60b0f04a1613..2e8d9f3333b36 100644 --- a/paddle/gserver/tests/test_MKLDNN.cpp +++ b/paddle/gserver/tests/test_MKLDNN.cpp @@ -271,20 +271,53 @@ TEST(MKLDNNLayer, BatchNormLayer) { testBatchNormLayer({16, 32, 16, 16}); } -struct testActDesc { +struct testImageDesc { int bs, ic, ih, iw; }; -static void getAddtoConfig(TestConfig& cfg, const testActDesc& pm) { +static void getAddtoConfig(TestConfig& cfg, + const testImageDesc& pm, + const size_t nInputs = 1) { cfg.biasSize = 0; cfg.layerConfig.set_type("addto"); size_t layerSize = pm.ic * pm.ih * pm.iw; cfg.layerConfig.set_size(layerSize); - cfg.inputDefs.push_back({INPUT_DATA, "layer_0", layerSize, 0}); - cfg.layerConfig.add_inputs(); + cfg.layerConfig.set_active_type("relu"); + for (size_t i = 0; i < nInputs; ++i) { + std::stringstream ss; + ss << "layer_" << i; + cfg.inputDefs.push_back({INPUT_DATA, ss.str(), layerSize, 0}); + LayerInputConfig* input = cfg.layerConfig.add_inputs(); + ImageConfig* img_conf = input->mutable_image_conf(); + img_conf->set_channels(pm.ic); + img_conf->set_img_size_y(pm.ih); + img_conf->set_img_size(pm.iw); + } +} + +void testAddtoLayer(const testImageDesc& pm, const size_t nInputs) { + CHECK_GE(nInputs, 1); + TestConfig dnnConfig; + getAddtoConfig(dnnConfig, pm, nInputs); + dnnConfig.layerConfig.set_type("mkldnn_addto"); + // TODO(TJ): test with bias + for (auto withBias : {false}) { + if (withBias) { + dnnConfig.biasSize = pm.ic * pm.ih * pm.iw; + } else { + dnnConfig.biasSize = 0; + } + RUN_MKLDNN_TEST_LAYER(dnnConfig, "addto", pm) + } +} + +TEST(MKLDNNLayer, AddtoLayer) { + testAddtoLayer({16, 5, 14, 14}, 1); + testAddtoLayer({8, 10, 8, 8}, 2); + testAddtoLayer({4, 12, 1, 1}, 3); } -void testActivation(std::string actType, const testActDesc& pm) { +void testActivation(std::string actType, const testImageDesc& pm) { // TODO(TJ): remove me when paddle support elu activation if (actType == "mkldnn_elu") { return; From 9bf99c21fd636a6db29f23f88d6f123e3ab50e00 Mon Sep 17 00:00:00 2001 From: tensor-tang Date: Thu, 2 Nov 2017 22:03:02 +0800 Subject: [PATCH 4/4] add mkldnn_addto python interface --- python/paddle/trainer/config_parser.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/python/paddle/trainer/config_parser.py b/python/paddle/trainer/config_parser.py index e88e962cff5bb..0e65598485d87 100644 --- a/python/paddle/trainer/config_parser.py +++ b/python/paddle/trainer/config_parser.py @@ -2775,9 +2775,15 @@ def __init__(self, @config_layer('addto') class AddToLayer(LayerBase): + layer_type = 'addto' + def __init__(self, name, inputs, bias=True, **xargs): + use_mkldnn = bool(int(g_command_config_args.get("use_mkldnn", 0))) + if self.layer_type == "mkldnn_addto": + config_assert(use_mkldnn, "mkldnn_addto only support MKLDNN") + self.layer_type = 'mkldnn_addto' if use_mkldnn else 'addto' super(AddToLayer, self).__init__( - name, 'addto', 0, inputs=inputs, **xargs) + name, self.layer_type, 0, inputs=inputs, **xargs) config_assert(len(inputs) > 0, 'inputs cannot be empty for AddToLayer') if len(self.inputs) > 1: @@ -2796,6 +2802,11 @@ def __init__(self, name, inputs, bias=True, **xargs): self.create_bias_parameter(bias, self.config.size) +@config_layer('mkldnn_addto') +class MKLDNNAddtoLayer(AddToLayer): + layer_type = 'mkldnn_addto' + + @config_layer('agent') class AgentLayer(LayerBase): def __init__(self, name, size, device=None):