// // ADAM.cpp // MNN // // Created by MNN on 2019/12/03. // Copyright © 2018, Alibaba Group Holding Limited // #include "ADAM.hpp" #include "OpGrad.hpp" using namespace MNN::Express; namespace MNN { namespace Train { ADAM::ADAM(std::shared_ptr module) : SGD(module) { auto train = ParameterOptimizer::trainable(); for (auto p : train) { mHistory2[p] = _Const(0.0f, p->getInfo()->dim, p->getInfo()->order); } } void ADAM::setMomentum2(float momentum2) { mMomentum2 = momentum2; } void ADAM::setEps(float eps) { mEps = eps; } float ADAM::getMomentum2() { return mMomentum2; } float ADAM::getEps() { return mEps; } Express::VARP ADAM::onComputeUpdateValue(Express::VARP param, Express::VARP grad) { auto lr = _Const(mLearningRate, {}, NCHW); auto step = _Const(currentStep(), {}, NCHW); auto beta1 = _Const(mMomentum, {}, NCHW); auto beta2 = _Const(mMomentum2, {}, NCHW); auto eps = _Const(mEps, {}, NCHW); // auto m = mHistory[param]; // auto v = mHistory2[param]; auto correction = _Sqrt(_Const(1.0f, {}, NCHW) - _Pow(beta2, step)) / (_Const(1.0f, {}, NCHW) - _Pow(beta1, step)); mHistory[param] = beta1 * mHistory[param] + (_Const(1.0f, {}, NCHW) - beta1) * grad; mHistory[param].fix(Express::VARP::CONSTANT); mHistory2[param] = beta2 * mHistory2[param] + (_Const(1.0f, {}, NCHW) - beta2) * _Square(grad); mHistory2[param].fix(Express::VARP::CONSTANT); auto updateValue = lr * correction * (mHistory[param] / (_Sqrt(mHistory2[param]) + eps)); updateValue.fix(Express::VARP::CONSTANT); return updateValue; } std::pair, std::vector> ADAM::onMakeParameterUpdateGraphByGrad(const std::vector& parameterGrads) { auto step = _Const(1.0f, {}, NCHW); auto beta1 = _Const(mMomentum, {}, NCHW); auto beta2 = _Const(mMomentum2, {}, NCHW); auto eps = _Const(mEps,{}, NCHW); beta1->setName("Beta1"); beta2->setName("Beta2"); eps->setName("Eps"); std::map varUpdateMap; step->setName("optimize_step"); auto stepPlus1 = step + _Scalar(1.0f); stepPlus1->setName("optimize_step+1"); varUpdateMap[step] = stepPlus1; auto correction = _Sqrt(_Const(1.0f, {}, NCHW) - _Pow(beta2, step)) / (_Const(1.0f, {}, NCHW) - _Pow(beta1, step)); correction->setName("correction"); auto weightDecay = _Const(mWeightDecay, {}, NCHW); for (auto iter : parameterGrads) { auto p = iter.parameter; MNN_PRINT("optimize variable: %s\n", p->name().c_str()); p.fix(VARP::TRAINABLE); auto grad = iter.parameterGrad; grad->setName(p->name()+"_grad"); #if 0 if (p->name().find("_BN_RunningMean_Weight") != string::npos) { varUpdateMap[p] = trainInfo[p->name()]; continue; // not update running stats } if (p->name().find("_BN_RunningVariance_Weight") != string::npos) { varUpdateMap[p] = trainInfo[p->name()]; continue; // not update running stats } if (p->name().find("_BN_Eps_Weight") != string::npos) { continue; // not update eps } #endif auto pInfo = p->getInfo(); auto pDims = pInfo->dim; auto l2grad = weightDecay * p; l2grad->setName(p->name() + "_l2grad"); VARP gradWithDecay = grad + l2grad; VARP history1 = _Const(0.0f, pDims, pInfo->order); history1->setName(p->name() + "_momentum1"); history1.fix(VARP::TRAINABLE); auto newHistory1 = beta1 * history1 + (_Scalar(1.0f) - beta1) * gradWithDecay; newHistory1->setName("update_" + history1->name()); VARP history2 = _Const(0.0f, pDims, pInfo->order); history2->setName(p->name() + "_momentum2"); history2.fix(VARP::TRAINABLE); auto newHistory2 = beta2 * history2 + (_Scalar(1.0f) - beta2) * _Square(gradWithDecay); newHistory2->setName("update_" + history2->name()); VARP localLearningRate = iter.learningRate; auto finalGrad = localLearningRate * correction * (history1 / (_Sqrt(history2 + _Scalar(1e-8)) + eps)); finalGrad->setName(p->name() + "_final_grad"); auto updateValue = _Subtract(p, finalGrad); updateValue->setName("update_" + p->name()); varUpdateMap[p] = updateValue; varUpdateMap[history1] = newHistory1; varUpdateMap[history2] = newHistory2; } std::vector res; std::vector resUpdate; for (auto& iter : varUpdateMap) { res.push_back(iter.first); resUpdate.push_back(iter.second); } return std::make_pair(res, resUpdate); } } // namespace Train } // namespace MNN