diff --git a/paddle/gserver/layers/MkldnnFcLayer.cpp b/paddle/gserver/layers/MkldnnFcLayer.cpp index f8220a2553d5ae81b89a93d8b2c0f8ec606a23be..5584b43ff17156b6a84609fd8c4985bb9299358f 100644 --- a/paddle/gserver/layers/MkldnnFcLayer.cpp +++ b/paddle/gserver/layers/MkldnnFcLayer.cpp @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ #include "MkldnnFcLayer.h" +#include "paddle/utils/Stat.h" namespace paddle { @@ -20,11 +21,82 @@ REGISTER_LAYER(mkldnn_fc, MkldnnFcLayer); bool MkldnnFcLayer::init(const LayerMap& layerMap, const ParameterMap& parameterMap) { - return MkldnnLayer::init(layerMap, parameterMap); + if (!MkldnnLayer::init(layerMap, parameterMap)) { + return false; + } + + CHECK_EQ(inputLayers_.size(), 1) << "Only support one input layer yet!"; + CHECK_EQ(inputLayers_.size(), parameters_.size()); + CHECK(!parameters_[0]->isSparse()) << "Do not support sparse yet"; + + // output size, cat not be changed + oc_ = getSize(); + oh_ = 1; + ow_ = 1; + + // input size can not change in FC + iLayerSize_ = inputLayers_[0]->getSize(); + CHECK_EQ(parameters_[0]->getSize(), iLayerSize_ * oc_); + + // create weight + weight_ = + std::unique_ptr(new Weight(oc_, iLayerSize_, parameters_[0], 0)); + + // create biases + if (biasParameter_.get() != NULL) { + biases_ = std::unique_ptr(new Weight(1, oc_, biasParameter_)); + } + return true; +} + +void MkldnnFcLayer::reshape() { + const Argument& input = getInput(0); + int batchSize = input.getBatchSize(); + if (bs_ == batchSize) { + return; + } + bs_ = batchSize; + ih_ = input.getFrameHeight(); + iw_ = input.getFrameWidth(); + if (ih_ == 0) { + ih_ = 1; + } + if (iw_ == 0) { + iw_ = 1; + } + CHECK_EQ(iLayerSize_, inputLayers_[0]->getSize()); + ic_ = iLayerSize_ / (ih_ * iw_); + CHECK_EQ(size_t(ic_ * ih_ * iw_), iLayerSize_) << "not divisible"; + CHECK_EQ(size_t(oc_), getSize()); + + // reset output + output_.setFrameHeight(oh_); + output_.setFrameWidth(ow_); + resetOutput(bs_, oc_); } -void MkldnnFcLayer::forward(PassType passType) {} +void MkldnnFcLayer::forward(PassType passType) { + Layer::forward(passType); + + reshape(); -void MkldnnFcLayer::backward(const UpdateCallback& callback) {} + { + REGISTER_TIMER_INFO("mkldnn_FwdTimer", getName().c_str()); + real* input = getInputValue(0)->getData(); + real* output = getOutputValue()->getData(); + real* wgt = weight_->getW()->getData(); + bool hasBias = biases_ && biases_->getW(); + real* bias = hasBias ? biases_->getW()->getData() : NULL; + mkldnnForwardFC(bs_, ic_, ih_, iw_, input, oc_, output, wgt, bias); + } + /* activation */ { + REGISTER_TIMER_INFO("FwActTimer", getName().c_str()); + forwardActivation(); + } +} + +void MkldnnFcLayer::backward(const UpdateCallback& callback) { + ; // bool hasBias = biases_ && biases_->getWGrad(); +} } // namespace paddle diff --git a/paddle/gserver/layers/MkldnnFcLayer.h b/paddle/gserver/layers/MkldnnFcLayer.h index 430567949d1661c269956c23e6e2d54afc468d3f..61677027718c58a5c8dc7d2e5d03b1fdedbf7a62 100644 --- a/paddle/gserver/layers/MkldnnFcLayer.h +++ b/paddle/gserver/layers/MkldnnFcLayer.h @@ -26,6 +26,13 @@ namespace paddle { */ class MkldnnFcLayer : public MkldnnLayer { protected: + // input layer size, can not be change after init + size_t iLayerSize_; // == ic * ih * iw + + // fc weight and bias + std::unique_ptr weight_; + std::unique_ptr biases_; + public: explicit MkldnnFcLayer(const LayerConfig& config) : MkldnnLayer(config) {} @@ -34,6 +41,8 @@ public: bool init(const LayerMap& layerMap, const ParameterMap& parameterMap) override; + void reshape(); + void forward(PassType passType) override; void backward(const UpdateCallback& callback) override; diff --git a/paddle/gserver/layers/MkldnnLayer.cpp b/paddle/gserver/layers/MkldnnLayer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d462e8694c268438431c5b66b36b48b7c7e13ef2 --- /dev/null +++ b/paddle/gserver/layers/MkldnnLayer.cpp @@ -0,0 +1,98 @@ +/* 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 "MkldnnLayer.h" + +// using namespace mkldnn; // NOLINT +using mem = mkldnn::memory; // NOLINT +typedef mem::format format; +typedef mkldnn::inner_product_forward fc_fwd; +typedef mkldnn::inner_product_backward_weights fc_bwdWgt; +typedef mkldnn::inner_product_backward_data fc_bwdData; + +namespace paddle { + +bool MkldnnLayer::init(const LayerMap& layerMap, + const ParameterMap& parameterMap) { + CHECK(FLAGS_use_mkldnn) << "MkldnnLayers only support use_mkldnn." + << "Please set WITH_MKLDNN=ON"; + // TODO(TJ): deivecId + return Layer::init(layerMap, parameterMap); +} + +void MkldnnLayer::resetForwardFC(int bs, + int ic, + int ih, + int iw, + real* botData, + int oc, + real* topData, + real* wgtData, + real* biasData) { + bool hasSpatial = ih == 1 && iw == 1 ? false : true; + engine_ = CpuEngine::Instance().getEngine(); + + mem::desc botMD = hasSpatial ? createMD({bs, ic, ih, iw}, format::nchw) + : createMD({bs, ic}, format::nc); + mem::desc wgtMD = hasSpatial ? createMD({oc, ic, ih, iw}, format::oihw) + : createMD({oc, ic}, format::oi); + mem::desc biasMD = biasData != NULL ? createMD({oc}, format::x) + : createMD({}, format::format_undef); + mem::desc topMD = createMD({bs, oc}, format::nc); + + mkldnn::prop_kind pk = mkldnn::prop_kind::forward; + fc_fwd::desc fwdDesc = biasData != NULL + ? fc_fwd::desc(pk, botMD, wgtMD, biasMD, topMD) + : fc_fwd::desc(pk, botMD, wgtMD, topMD); + fc_fwd::primitive_desc fwdPD = fc_fwd::primitive_desc(fwdDesc, engine_); + + mem bot = mem(mem::primitive_desc(botMD, engine_), botData); + mem wgt = mem(mem::primitive_desc(wgtMD, engine_), wgtData); + mem top = mem(mem::primitive_desc(topMD, engine_), topData); + + if (biasData != NULL) { + mem bias = mem(mem::primitive_desc(biasMD, engine_), biasData); + fwd_.reset(new fc_fwd(fwdPD, bot, wgt, bias, top)); + } else { + fwd_.reset(new fc_fwd(fwdPD, bot, wgt, top)); + } + pipelineFwd_.clear(); + pipelineFwd_.push_back(*fwd_); +} + +void MkldnnLayer::mkldnnForwardFC(int bs, + int ic, + int ih, + int iw, + real* botData, + int oc, + real* topData, + real* wgtData, + real* biasData) { + // if input size changed, reset it + resetForwardFC(bs, ic, ih, iw, botData, oc, topData, wgtData, biasData); + + // just forward + // update botdata + stream_->submit(pipelineFwd_); +} + +mem::desc MkldnnLayer::createMD(mem::dims dims, + mem::format fmt, + mem::data_type type) { + // TODO(TJ): isFmtSuppoted(fmt) + return mem::desc(dims, type, fmt); +} + +} // namespace paddle diff --git a/paddle/gserver/layers/MkldnnLayer.h b/paddle/gserver/layers/MkldnnLayer.h index e69c9d6a1acbbaad3e6729cdef82f3ce0c1d2a07..6e41ee4028e24e6b3c336abf3fbc10ad31aa0fef 100644 --- a/paddle/gserver/layers/MkldnnLayer.h +++ b/paddle/gserver/layers/MkldnnLayer.h @@ -29,20 +29,65 @@ typedef std::shared_ptr MkldnnLayerPtr; * */ class MkldnnLayer : public Layer { +protected: + // batch size + int bs_; + // input image channel, height and width + int ic_, ih_, iw_; + // output image channel, height and width + int oc_, oh_, ow_; + + // mkldnn engine, stream and primivtives + mkldnn::engine engine_; + std::shared_ptr stream_; + + std::shared_ptr fwd_; + std::vector pipelineFwd_; + std::vector pipelineBwd_; + public: - explicit MkldnnLayer(const LayerConfig& config) : Layer(config) {} + explicit MkldnnLayer(const LayerConfig& config) + : Layer(config), + bs_(0), + ic_(0), + ih_(0), + iw_(0), + oc_(0), + oh_(0), + ow_(0), + engine_(mkldnn::engine::cpu, 0), + stream_(nullptr) {} ~MkldnnLayer() {} - virtual bool init(const LayerMap& layerMap, - const ParameterMap& parameterMap) { - CHECK(FLAGS_use_mkldnn) << "MkldnnLayers only support use_mkldnn." - << "Please set WITH_MKLDNN=ON"; - // TODO(TJ): deivecId - return Layer::init(layerMap, parameterMap); - } + virtual bool init(const LayerMap& layerMap, const ParameterMap& parameterMap); + + void resetForwardFC(int bs, + int ic, + int ih, + int iw, + real* botData, + int oc, + real* topData, + real* wgtData, + real* biasData); + + void mkldnnForwardFC(int bs, + int ic, + int ih, + int iw, + real* botData, + int oc, + real* topData, + real* wgtData, + real* biasData); - void resetOutput(size_t height, size_t width) { ; } + // TODO(TJ): move to MkldnnMatrix + // create memory desc + inline mkldnn::memory::desc createMD( + mkldnn::memory::dims dims, + mkldnn::memory::format fmt, + mkldnn::memory::data_type type = mkldnn::memory::data_type::f32); }; } // namespace paddle