提交 0cc85d79 编写于 作者: T Tao Luo 提交者: GitHub

Merge pull request #4331 from tensor-tang/mkldnn_softmax

Add mkldnn_softmax
...@@ -9,11 +9,9 @@ function train() { ...@@ -9,11 +9,9 @@ function train() {
bs=$2 bs=$2
use_mkldnn=$3 use_mkldnn=$3
if [ $3 == "True" ]; then if [ $3 == "True" ]; then
use_mkldnn=$3
thread=1 thread=1
log="logs/${topology}-mkldnn-${bs}.log" log="logs/${topology}-mkldnn-${bs}.log"
elif [ $3 == "False" ]; then elif [ $3 == "False" ]; then
use_mkldnn=$3
thread=`nproc` thread=`nproc`
log="logs/${topology}-${thread}mklml-${bs}.log" log="logs/${topology}-${thread}mklml-${bs}.log"
else else
...@@ -39,8 +37,7 @@ if [ ! -d "logs" ]; then ...@@ -39,8 +37,7 @@ if [ ! -d "logs" ]; then
mkdir logs mkdir logs
fi fi
#========= mkldnn =========# #========== mkldnn ==========#
# vgg
train vgg 64 True train vgg 64 True
train vgg 128 True train vgg 128 True
train vgg 256 True train vgg 256 True
......
...@@ -27,31 +27,53 @@ static ClassRegistrar<ActivationFunction> gMKLDNNActivationRegistrar; ...@@ -27,31 +27,53 @@ static ClassRegistrar<ActivationFunction> gMKLDNNActivationRegistrar;
#define MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE) mkldnn_##ACT_TYPE##Activation #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) \ #define END_MKLDNN_ACTIVATION(ACT_TYPE) \
class MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE) \ private: \
: public MKLDNNEltwiseActivation { \ static const std::string name; \
private: \ \
static const std::string name; \ public: \
static const float alpha; \ const std::string& getName() const { return name; } \
static const float bwdAlpha; \ } \
\ ; \
public: \ const std::string MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::name = \
const std::string& getName() const { return name; } \ "mkldnn_" #ACT_TYPE; \
float getAlpha() const { return alpha; } \ static InitFunction __reg_activation__mkldnn_##ACT_TYPE([] { \
float getBwdAlpha() const { return bwdAlpha; } \ gMKLDNNActivationRegistrar \
}; \ .registerClass<MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)>( \
const std::string MKLDNN_ACTIVATION_CLASS_NAME(ACT_TYPE)::name = \ "mkldnn_" #ACT_TYPE); \
"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_ACTIVATION_CLASS_NAME(ACT_TYPE)>( \
"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. * @brief MKLDNN Relu Activation.
* Actually mkldnn_relu is Leaky Relu. * Actually mkldnn_relu is Leaky Relu.
...@@ -59,19 +81,129 @@ static ClassRegistrar<ActivationFunction> gMKLDNNActivationRegistrar; ...@@ -59,19 +81,129 @@ static ClassRegistrar<ActivationFunction> gMKLDNNActivationRegistrar;
* f(x) = negative_slope * x (x < 0) * f(x) = negative_slope * x (x < 0)
* @note the negative_slope should be -0.f in forward * @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. * @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. * @brief MKLDNN ELU(Exponential Linear Unit) Activation.
* f(x) = x (x >= 0) * f(x) = x (x >= 0)
* f(x) = negative_slope * (exp(x) - 1) (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<std::string, mkldnn::algorithm> 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<mkldnn::reorder>(*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) { ActivationFunction* MKLDNNActivation::create(const std::string& type) {
return gMKLDNNActivationRegistrar.createByType(type); return gMKLDNNActivationRegistrar.createByType(type);
...@@ -84,4 +216,34 @@ std::vector<std::string> MKLDNNActivation::getAllRegisteredTypes() { ...@@ -84,4 +216,34 @@ std::vector<std::string> MKLDNNActivation::getAllRegisteredTypes() {
return types; 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<MKLDNNMatrix>(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 } // namespace paddle
...@@ -36,6 +36,7 @@ protected: ...@@ -36,6 +36,7 @@ protected:
// mkldnn matrix, primitive, stream and pipeline // mkldnn matrix, primitive, stream and pipeline
MKLDNNMatrixPtr val_; MKLDNNMatrixPtr val_;
MKLDNNMatrixPtr grad_; MKLDNNMatrixPtr grad_;
std::shared_ptr<mkldnn::engine> engine_;
std::shared_ptr<MKLDNNStream> stream_; std::shared_ptr<MKLDNNStream> stream_;
std::shared_ptr<mkldnn::primitive> fwd_; std::shared_ptr<mkldnn::primitive> fwd_;
std::shared_ptr<mkldnn::primitive> bwd_; std::shared_ptr<mkldnn::primitive> bwd_;
...@@ -48,8 +49,18 @@ public: ...@@ -48,8 +49,18 @@ public:
static ActivationFunction* create(const std::string& type); static ActivationFunction* create(const std::string& type);
static std::vector<std::string> getAllRegisteredTypes(); static std::vector<std::string> getAllRegisteredTypes();
virtual const std::string& getName() const = 0; 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: ...@@ -59,6 +70,7 @@ public:
class MKLDNNEltwiseActivation : public MKLDNNActivation { class MKLDNNEltwiseActivation : public MKLDNNActivation {
typedef mkldnn::eltwise_forward eltwise_fwd; typedef mkldnn::eltwise_forward eltwise_fwd;
typedef mkldnn::eltwise_backward eltwise_bwd; typedef mkldnn::eltwise_backward eltwise_bwd;
typedef mkldnn::algorithm algorithm;
protected: protected:
// save the forward primitive desc, which can be used backward // save the forward primitive desc, which can be used backward
...@@ -70,9 +82,7 @@ protected: ...@@ -70,9 +82,7 @@ protected:
public: public:
MKLDNNEltwiseActivation() {} MKLDNNEltwiseActivation() {}
~MKLDNNEltwiseActivation() {} ~MKLDNNEltwiseActivation() {}
virtual const std::string& getName() const = 0; virtual const std::string& getName() const = 0;
// in common, the alpha of forward and backward should be equal. // in common, the alpha of forward and backward should be equal.
...@@ -80,105 +90,30 @@ public: ...@@ -80,105 +90,30 @@ public:
virtual float getAlpha() const = 0; virtual float getAlpha() const = 0;
virtual float getBwdAlpha() const = 0; virtual float getBwdAlpha() const = 0;
virtual float getBeta() const { return 0.f; } virtual float getBeta() const { return 0.f; }
virtual mkldnn::algorithm getAlgo(const std::string& type) const { virtual algorithm getAlgo(std::string type) const;
if (type == "mkldnn_relu") { void resetFwd(Argument& act) override;
return mkldnn::algorithm::eltwise_relu; void resetBwd(Argument& act) override;
} 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<MKLDNNMatrix>(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<mkldnn::reorder>(*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;
}
/** /**
* reset the backward primitives, can not merge into resetFwd as the grad data * @brief Base class of MKLDNN softmax Activation,
* would be changing before backward. * only have mkldnn forward, use cpu implement for backward.
*/ */
void resetBwd(Argument& act) { class MKLDNNSoftmaxActivation : public MKLDNNActivation {
if (!needResetBwd_) { typedef mkldnn::softmax_forward softmax_fwd;
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_);
}
Error __must_check forward(Argument& act) { private:
resetFwd(act); // for backward
stream_->submit(pipelineFwd_); MatrixPtr sftMaxSum_;
return Error(); MatrixPtr sftMaxDot_;
}
Error __must_check backward(Argument& act) { public:
resetBwd(act); MKLDNNSoftmaxActivation() {}
stream_->submit(pipelineBwd_); ~MKLDNNSoftmaxActivation() {}
return Error(); 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 } // namespace paddle
...@@ -222,8 +222,8 @@ static void getAddtoConfig(TestConfig& cfg, const testActDesc& pm) { ...@@ -222,8 +222,8 @@ static void getAddtoConfig(TestConfig& cfg, const testActDesc& pm) {
} }
void testActivation(std::string& actType, const testActDesc& pm) { void testActivation(std::string& actType, const testActDesc& pm) {
// TODO(TJ): mkldnn_softmax not implemented, paddle do not have elu activation // TODO(TJ): remove me when paddle support elu activation
if (actType == "mkldnn_softmax" || actType == "mkldnn_elu") { if (actType == "mkldnn_elu") {
return; return;
} }
const std::string compareTypes[] = {actType, actType.erase(0, 7)}; const std::string compareTypes[] = {actType, actType.erase(0, 7)};
......
...@@ -1566,7 +1566,7 @@ class LayerBase(object): ...@@ -1566,7 +1566,7 @@ class LayerBase(object):
self.config = g_config.model_config.layers.add() self.config = g_config.model_config.layers.add()
assert isinstance(self.config, LayerConfig) assert isinstance(self.config, LayerConfig)
use_mkldnn = bool(int(g_command_config_args.get("use_mkldnn", 0))) 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: if use_mkldnn and active_type in mkldnn_acts:
active_type = "mkldnn_" + active_type active_type = "mkldnn_" + active_type
self.config.name = name self.config.name = name
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册