diff --git a/benchmark/paddle/image/run_mkldnn.sh b/benchmark/paddle/image/run_mkldnn.sh index 5b0a0373448e5b81ff0718db3465a4694690ec37..b6cd6fe03b381d2b6529116f934ce7ce03d63546 100755 --- a/benchmark/paddle/image/run_mkldnn.sh +++ b/benchmark/paddle/image/run_mkldnn.sh @@ -9,11 +9,9 @@ function train() { bs=$2 use_mkldnn=$3 if [ $3 == "True" ]; then - use_mkldnn=$3 thread=1 log="logs/${topology}-mkldnn-${bs}.log" elif [ $3 == "False" ]; then - use_mkldnn=$3 thread=`nproc` log="logs/${topology}-${thread}mklml-${bs}.log" else @@ -39,8 +37,7 @@ if [ ! -d "logs" ]; then mkdir logs fi -#========= mkldnn =========# -# vgg +#========== mkldnn ==========# train vgg 64 True train vgg 128 True train vgg 256 True diff --git a/paddle/gserver/activations/MKLDNNActivation.cpp b/paddle/gserver/activations/MKLDNNActivation.cpp index ac50937ef3e28c1ac5aae651f9cf266ad07abcc4..18c5638100065109fba1f0647a1c5f91256f7b9d 100644 --- a/paddle/gserver/activations/MKLDNNActivation.cpp +++ b/paddle/gserver/activations/MKLDNNActivation.cpp @@ -27,31 +27,53 @@ static ClassRegistrar gMKLDNNActivationRegistrar; #define MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE) mkldnn_##ACT_TYPE##Activation /** - * @def DEFINE_MKLDNN_ELTWISE_ACTIVATION + * @def BEGIN_MKLDNN_ACTIVATION + */ +#define BEGIN_MKLDNN_ACTIVATION(ACT_TYPE, BASE_CLASS) \ + class MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE) : public BASE_CLASS { +/** + * @def END_MKLDNN_ACTIVATION */ -#define DEFINE_MKLDNN_ELTWISE_ACTIVATION(ACT_TYPE, ALPHA, BWD_ALPHA) \ - class MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE) \ - : public MKLDNNEltwiseActivation { \ - private: \ - static const std::string name; \ - static const float alpha; \ - static const float bwdAlpha; \ - \ - public: \ - const std::string& getName() const { return name; } \ - float getAlpha() const { return alpha; } \ - float getBwdAlpha() const { return bwdAlpha; } \ - }; \ - const std::string MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::name = \ - "mkldnn_" #ACT_TYPE; \ - const float MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::alpha = ALPHA; \ - const float MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::bwdAlpha = BWD_ALPHA; \ - static InitFunction __reg_activation__mkldnn_##ACT_TYPE([] { \ - gMKLDNNActivationRegistrar \ - .registerClass( \ - "mkldnn_" #ACT_TYPE); \ +#define END_MKLDNN_ACTIVATION(ACT_TYPE) \ +private: \ + static const std::string name; \ + \ +public: \ + const std::string& getName() const { return name; } \ + } \ + ; \ + const std::string MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::name = \ + "mkldnn_" #ACT_TYPE; \ + static InitFunction __reg_activation__mkldnn_##ACT_TYPE([] { \ + gMKLDNNActivationRegistrar \ + .registerClass( \ + "mkldnn_" #ACT_TYPE); \ }); +/** + * @def DEFINE_MKLDNN_ACTIVATION + */ +#define DEFINE_MKLDNN_ACTIVATION(ACT_TYPE, BASE_CLASS) \ + BEGIN_MKLDNN_ACTIVATION(ACT_TYPE, BASE_CLASS) \ + END_MKLDNN_ACTIVATION(ACT_TYPE) + +/** + * @def DEFINE_MKLDNN_ELTWISE_ACTIVATION + */ +#define DEFINE_MKLDNN_ELTWISE_ACTIVATION( \ + ACT_TYPE, BASE_CLASS, ALPHA, BWD_ALPHA) \ + BEGIN_MKLDNN_ACTIVATION(ACT_TYPE, BASE_CLASS) \ +private: \ + static const float alpha; \ + static const float bwdAlpha; \ + \ +public: \ + float getAlpha() const { return alpha; } \ + float getBwdAlpha() const { return bwdAlpha; } \ + END_MKLDNN_ACTIVATION(ACT_TYPE) \ + const float MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::alpha = ALPHA; \ + const float MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::bwdAlpha = BWD_ALPHA; + /** * @brief MKLDNN Relu Activation. * Actually mkldnn_relu is Leaky Relu. @@ -59,19 +81,129 @@ static ClassRegistrar gMKLDNNActivationRegistrar; * f(x) = negative_slope * x (x < 0) * @note the negative_slope should be -0.f in forward */ -DEFINE_MKLDNN_ELTWISE_ACTIVATION(relu, -0.f, 0.f) +DEFINE_MKLDNN_ELTWISE_ACTIVATION(relu, MKLDNNEltwiseActivation, -0.f, 0.f) /** * @brief MKLDNN Tanh Activation. */ -DEFINE_MKLDNN_ELTWISE_ACTIVATION(tanh, 0.f, 0.f) +DEFINE_MKLDNN_ELTWISE_ACTIVATION(tanh, MKLDNNEltwiseActivation, 0.f, 0.f) /** * @brief MKLDNN ELU(Exponential Linear Unit) Activation. * f(x) = x (x >= 0) * f(x) = negative_slope * (exp(x) - 1) (x < 0) */ -DEFINE_MKLDNN_ELTWISE_ACTIVATION(elu, 0.f, 0.f) +DEFINE_MKLDNN_ELTWISE_ACTIVATION(elu, MKLDNNEltwiseActivation, 0.f, 0.f) + +mkldnn::algorithm MKLDNNEltwiseActivation::getAlgo(std::string type) const { + const std::map algoMap = { + {"relu", algorithm::eltwise_relu}, + {"tanh", algorithm::eltwise_tanh}, + {"elu", algorithm::eltwise_elu}}; + type.erase(0, 7); // remove mkldnn_ + algorithm algo = (algorithm)0; + mapGet(type, algoMap, &algo); + return algo; +} + +void MKLDNNEltwiseActivation::resetFwd(Argument& act) { + if (cnt_ == act.value->getElementCnt()) { + return; + } + MKLDNNActivation::resetFwd(act); + // note: alpha represents the NegativeSlope when used in relu. + float alpha = getAlpha(); + float beta = getBeta(); + algorithm algo = getAlgo(this->getName()); + auto fwdDesc = eltwise_fwd::desc(mkldnn::prop_kind::forward_training, + algo, + val_->getMemoryDesc(), + alpha, + beta); + fwdPD_.reset(new eltwise_fwd::primitive_desc(fwdDesc, *engine_)); + // use inplace for forward but save input value before submit + inVal_ = val_; + copyInVal_ = nullptr; + if (act.grad && algo == algorithm::eltwise_tanh) { + // tanh need save src input for backward + inVal_ = MKLDNNMatrix::create(nullptr, val_->getPrimitiveDesc()); + copyInVal_ = std::make_shared(*val_, *inVal_); + CHECK(copyInVal_) << "should not be emptry"; + pipelineFwd_.push_back(*copyInVal_); + } + fwd_.reset(new eltwise_fwd(*fwdPD_, *val_, *val_)); + pipelineFwd_.push_back(*fwd_); + needResetBwd_ = true; +} + +void MKLDNNEltwiseActivation::resetBwd(Argument& act) { + if (!needResetBwd_) { + return; + } + VLOG(MKLDNN_BASE) << getName() << " reset mkldnn backward"; + needResetBwd_ = false; + algorithm algo = getAlgo(this->getName()); + float alpha = getBwdAlpha(); + float beta = getBeta(); + grad_ = MKLDNNMatrix::create(act.grad, val_->getPrimitiveDesc()); + auto eng = CPUEngine::Instance().getEngine(); + auto bwdDesc = eltwise_bwd::desc( + algo, grad_->getMemoryDesc(), val_->getMemoryDesc(), alpha, beta); + auto bwdPD = eltwise_bwd::primitive_desc(bwdDesc, eng, *fwdPD_); + CHECK(inVal_); + bwd_.reset(new eltwise_bwd(bwdPD, *inVal_, *grad_, *grad_)); + pipelineBwd_.clear(); + pipelineBwd_.push_back(*bwd_); +} + +/** + * @brief MKLDNN Softmax Activation + */ +DEFINE_MKLDNN_ACTIVATION(softmax, MKLDNNSoftmaxActivation) + +void MKLDNNSoftmaxActivation::resetFwd(Argument& act) { + if (cnt_ == act.value->getElementCnt()) { + return; + } + MKLDNNActivation::resetFwd(act); + int axis = 1; + auto fwdDesc = softmax_fwd::desc( + mkldnn::prop_kind::forward_scoring, val_->getMemoryDesc(), axis); + auto fwdPD = softmax_fwd::primitive_desc(fwdDesc, *engine_); + fwd_.reset(new softmax_fwd(fwdPD, *val_, *val_)); + pipelineFwd_.push_back(*fwd_); +} + +Error __must_check MKLDNNSoftmaxActivation::forward(Argument& act) { + resetFwd(act); + stream_->submit(pipelineFwd_); + real* v = act.value->getData(); + real threshold = exp(-64); +#pragma omp parallel for + for (size_t i = 0; i < act.value->getElementCnt(); ++i) { + v[i] = v[i] < threshold ? threshold : v[i]; + } + return Error(); +} + +Error __must_check MKLDNNSoftmaxActivation::backward(Argument& act) { + MatrixPtr outputV = act.value; + MatrixPtr outputG = act.grad; + Matrix::resizeOrCreate(sftMaxDot_, + outputG->getHeight(), + outputG->getWidth(), + /* trans */ false, + /* useGpu */ false); + Matrix::resizeOrCreate(sftMaxSum_, + outputG->getHeight(), + 1, + /* trans */ false, + /* useGpu */ false); + sftMaxDot_->dotMul(*outputG, *outputV); + sftMaxSum_->colMerge(*sftMaxDot_); + act.grad->softmaxDerivative(*act.value, *sftMaxSum_); + return Error(); +} ActivationFunction* MKLDNNActivation::create(const std::string& type) { return gMKLDNNActivationRegistrar.createByType(type); @@ -84,4 +216,34 @@ std::vector MKLDNNActivation::getAllRegisteredTypes() { return types; } +void MKLDNNActivation::resetFwd(Argument& act) { + VLOG(MKLDNN_BASE) << getName() << " reset mkldnn forward"; + cnt_ = act.value->getElementCnt(); + pipelineFwd_.clear(); + stream_.reset(new MKLDNNStream()); + engine_.reset(new mkldnn::engine(mkldnn::engine::cpu, 0)); + val_ = std::dynamic_pointer_cast(act.value); + if (val_ == nullptr) { + int bs = act.getBatchSize(); + int ih = act.getFrameHeight() > 0 ? act.getFrameHeight() : 1; + int iw = act.getFrameWidth() > 0 ? act.getFrameWidth() : 1; + int ic = cnt_ / bs / ih / iw; + CHECK_EQ(cnt_, (size_t)bs * ic * ih * iw); + val_ = MKLDNNMatrix::create( + act.value, {bs, ic, ih, iw}, mkldnn::memory::format::nchw, *engine_); + CHECK(val_); + val_->downSpatial(); + } +} + +Error __must_check MKLDNNActivation::forward(Argument& act) { + resetFwd(act); + stream_->submit(pipelineFwd_); + return Error(); +} +Error __must_check MKLDNNActivation::backward(Argument& act) { + resetBwd(act); + stream_->submit(pipelineBwd_); + return Error(); +} } // namespace paddle diff --git a/paddle/gserver/activations/MKLDNNActivation.h b/paddle/gserver/activations/MKLDNNActivation.h index 40dd8c618aa2b70d410130e12efc54520218afea..dd16421fd6e93b49c30b1d3b601f95980afec57b 100644 --- a/paddle/gserver/activations/MKLDNNActivation.h +++ b/paddle/gserver/activations/MKLDNNActivation.h @@ -36,6 +36,7 @@ protected: // mkldnn matrix, primitive, stream and pipeline MKLDNNMatrixPtr val_; MKLDNNMatrixPtr grad_; + std::shared_ptr engine_; std::shared_ptr stream_; std::shared_ptr fwd_; std::shared_ptr bwd_; @@ -48,8 +49,18 @@ public: static ActivationFunction* create(const std::string& type); static std::vector getAllRegisteredTypes(); virtual const std::string& getName() const = 0; - virtual Error __must_check forward(Argument& act) = 0; - virtual Error __must_check backward(Argument& act) = 0; + /** + * reset the forward primitives + */ + virtual void resetFwd(Argument& act); + /** + * reset the backward primitives, + * can not merge this functions into resetFwd as the grad data + * would be changing before backward. + */ + virtual void resetBwd(Argument& act) {} + virtual Error __must_check forward(Argument& act); + virtual Error __must_check backward(Argument& act); }; /** @@ -59,6 +70,7 @@ public: class MKLDNNEltwiseActivation : public MKLDNNActivation { typedef mkldnn::eltwise_forward eltwise_fwd; typedef mkldnn::eltwise_backward eltwise_bwd; + typedef mkldnn::algorithm algorithm; protected: // save the forward primitive desc, which can be used backward @@ -70,9 +82,7 @@ protected: public: MKLDNNEltwiseActivation() {} - ~MKLDNNEltwiseActivation() {} - virtual const std::string& getName() const = 0; // in common, the alpha of forward and backward should be equal. @@ -80,105 +90,30 @@ public: virtual float getAlpha() const = 0; virtual float getBwdAlpha() const = 0; virtual float getBeta() const { return 0.f; } - virtual mkldnn::algorithm getAlgo(const std::string& type) const { - if (type == "mkldnn_relu") { - return mkldnn::algorithm::eltwise_relu; - } else if (type == "mkldnn_tanh") { - return mkldnn::algorithm::eltwise_tanh; - } else if (type == "mkldnn_elu") { - return mkldnn::algorithm::eltwise_elu; - } else { - LOG(FATAL) << "Unkown eltwise activation type: " << type; - } - return (mkldnn::algorithm)0; - } - - /** - * reshape and reset the forward primitives - */ - void resetFwd(Argument& act) { - if (cnt_ == act.value->getElementCnt()) { - return; - } - VLOG(MKLDNN_BASE) << getName() << " reset mkldnn forward"; - cnt_ = act.value->getElementCnt(); - stream_.reset(new MKLDNNStream()); - auto eng = CPUEngine::Instance().getEngine(); - - // get algo setting - mkldnn::algorithm algo = getAlgo(this->getName()); - // note: alpha represents the NegativeSlope when used in relu. - float alpha = getAlpha(); - float beta = getBeta(); - - pipelineFwd_.clear(); - val_ = std::dynamic_pointer_cast(act.value); - if (val_ == nullptr) { - int bs = act.getBatchSize(); - int ih = act.getFrameHeight() > 0 ? act.getFrameHeight() : 1; - int iw = act.getFrameWidth() > 0 ? act.getFrameWidth() : 1; - int ic = cnt_ / bs / ih / iw; - CHECK_EQ(cnt_, (size_t)bs * ic * ih * iw); - val_ = MKLDNNMatrix::create( - act.value, {bs, ic, ih, iw}, mkldnn::memory::format::nchw, eng); - CHECK(val_); - } - auto fwdDesc = eltwise_fwd::desc(mkldnn::prop_kind::forward_training, - algo, - val_->getMemoryDesc(), - alpha, - beta); - fwdPD_.reset(new eltwise_fwd::primitive_desc(fwdDesc, eng)); - // use inplace for forward but save input value before submit - inVal_ = val_; - copyInVal_ = nullptr; - if (act.grad && algo == mkldnn::algorithm::eltwise_tanh) { - // tanh need save src input for backward - inVal_ = MKLDNNMatrix::create(nullptr, val_->getPrimitiveDesc()); - copyInVal_ = std::make_shared(*val_, *inVal_); - CHECK(copyInVal_) << "should not be emptry"; - pipelineFwd_.push_back(*copyInVal_); - } - fwd_.reset(new eltwise_fwd(*fwdPD_, *val_, *val_)); - pipelineFwd_.push_back(*fwd_); - needResetBwd_ = true; - } + virtual algorithm getAlgo(std::string type) const; + void resetFwd(Argument& act) override; + void resetBwd(Argument& act) override; +}; - /** - * reset the backward primitives, can not merge into resetFwd as the grad data - * would be changing before backward. - */ - void resetBwd(Argument& act) { - if (!needResetBwd_) { - return; - } - VLOG(MKLDNN_BASE) << getName() << " reset mkldnn backward"; - needResetBwd_ = false; - mkldnn::algorithm algo = getAlgo(this->getName()); - float alpha = getBwdAlpha(); - float beta = getBeta(); - grad_ = MKLDNNMatrix::create(act.grad, val_->getPrimitiveDesc()); - auto eng = CPUEngine::Instance().getEngine(); - auto bwdDesc = eltwise_bwd::desc( - algo, grad_->getMemoryDesc(), val_->getMemoryDesc(), alpha, beta); - auto bwdPD = eltwise_bwd::primitive_desc(bwdDesc, eng, *fwdPD_); - CHECK(inVal_); - bwd_.reset(new eltwise_bwd(bwdPD, *inVal_, *grad_, *grad_)); - pipelineBwd_.clear(); - pipelineBwd_.push_back(*bwd_); - } +/** + * @brief Base class of MKLDNN softmax Activation, + * only have mkldnn forward, use cpu implement for backward. + */ +class MKLDNNSoftmaxActivation : public MKLDNNActivation { + typedef mkldnn::softmax_forward softmax_fwd; - Error __must_check forward(Argument& act) { - resetFwd(act); - stream_->submit(pipelineFwd_); - return Error(); - } +private: + // for backward + MatrixPtr sftMaxSum_; + MatrixPtr sftMaxDot_; - Error __must_check backward(Argument& act) { - resetBwd(act); - stream_->submit(pipelineBwd_); - return Error(); - } +public: + MKLDNNSoftmaxActivation() {} + ~MKLDNNSoftmaxActivation() {} + virtual const std::string& getName() const = 0; + void resetFwd(Argument& act) override; + Error __must_check forward(Argument& act) override; + Error __must_check backward(Argument& act) override; }; } // namespace paddle diff --git a/paddle/gserver/tests/test_MKLDNN.cpp b/paddle/gserver/tests/test_MKLDNN.cpp index 1bfbbde4246a10eaf86693a6a2f237f390966db3..857d07df3e3088be28943d9e2fe58017e9e57f4a 100644 --- a/paddle/gserver/tests/test_MKLDNN.cpp +++ b/paddle/gserver/tests/test_MKLDNN.cpp @@ -222,8 +222,8 @@ static void getAddtoConfig(TestConfig& cfg, const testActDesc& pm) { } void testActivation(std::string& actType, const testActDesc& pm) { - // TODO(TJ): mkldnn_softmax not implemented, paddle do not have elu activation - if (actType == "mkldnn_softmax" || actType == "mkldnn_elu") { + // TODO(TJ): remove me when paddle support elu activation + if (actType == "mkldnn_elu") { return; } const std::string compareTypes[] = {actType, actType.erase(0, 7)}; diff --git a/python/paddle/trainer/config_parser.py b/python/paddle/trainer/config_parser.py index 0f57b81966647ca5c6f5cd2e5518d2d34942a549..098a51ab8791290d3e0ffa2c3703c724dd2387b9 100644 --- a/python/paddle/trainer/config_parser.py +++ b/python/paddle/trainer/config_parser.py @@ -1566,7 +1566,7 @@ class LayerBase(object): self.config = g_config.model_config.layers.add() assert isinstance(self.config, LayerConfig) use_mkldnn = bool(int(g_command_config_args.get("use_mkldnn", 0))) - mkldnn_acts = ['relu', 'tanh'] + mkldnn_acts = ['relu', 'tanh', 'softmax'] if use_mkldnn and active_type in mkldnn_acts: active_type = "mkldnn_" + active_type self.config.name = name