// // SGD.cpp // MNN // // Created by MNN on 2019/11/22. // Copyright © 2018, Alibaba Group Holding Limited // #include "SGD.hpp" #include "OpGrad.hpp" using namespace MNN::Express; namespace MNN { namespace Train { SGD::SGD(std::shared_ptr module) : ParameterOptimizer(module) { auto train = ParameterOptimizer::trainable(); for (auto p : train) { mHistory[p] = _Const(0.0f, p->getInfo()->dim, p->getInfo()->order); } } void SGD::setLearningRate(float rate) { mLearningRate = rate; } void SGD::setMomentum(float momentum) { mMomentum = momentum; } void SGD::setWeightDecay(float decay) { mWeightDecay = decay; } void SGD::setRegularizationMethod(RegularizationMethod method) { mRegularizationMethod = method; } float SGD::currentLearningRate() { return mLearningRate; } float SGD::getMomentum() { return mMomentum; } float SGD::getWeightDecay() { return mWeightDecay; } SGD::RegularizationMethod SGD::getRegularizationMethod() { return mRegularizationMethod; } Express::VARP SGD::regularizeParameters(Express::VARP param, Express::VARP grad) { VARP addWeightDecayGrad; if (mRegularizationMethod == L1) { auto temp = _Sign(param); addWeightDecayGrad = _Const(mWeightDecay, {}, NCHW) * temp + grad; } else if (mRegularizationMethod == L2) { addWeightDecayGrad = _Const(mWeightDecay, {}, NCHW) * param + grad; } else if (mRegularizationMethod == L1L2) { auto temp = _Sign(param); auto L1 = _Const(mWeightDecay, {}, NCHW) * temp; auto L2 = _Const(mWeightDecay, {}, NCHW) * param; addWeightDecayGrad = L1 + L2 + grad; } return addWeightDecayGrad; } Express::VARP SGD::onComputeUpdateValue(Express::VARP param, Express::VARP grad) { auto lr = _Const(mLearningRate, {}, NCHW); mHistory[param] = lr * grad + _Const(mMomentum, {}, NCHW) * mHistory[param];; mHistory[param].fix(Express::VARP::CONSTANT); //FUNC_PRINT_ALL(_ReduceMax(grad)->readMap()[0], f); return mHistory[param]; } std::map SGD::onGetNextParameter(Express::VARP loss) { auto grad = OpGrad::grad(loss, trainable(), mGradBlockExprName); auto parameters = module()->parameters(); std::vector prepareCompute; for (auto iter : parameters) { if (iter->expr().first->get() != nullptr) { prepareCompute.emplace_back(iter); } } for (auto& iter : grad) { prepareCompute.emplace_back(iter.second); } Variable::prepareCompute(prepareCompute); std::vector replaceOp(prepareCompute.size()); for (int i=0; igetInfo(); auto ptr = prepareCompute[i]->readMap(); if (nullptr == ptr) { MNN_ERROR("Compute error in SGD\n"); return {}; } auto newVar = _Const(ptr, info->dim, info->order, info->type); replaceOp[i]= newVar; } for (int i=0; ionComputeUpdateValue(iter.first, addWeightDecayGrad); // apply update auto newParameter = iter.first - updateValue; iter.second = newParameter; } return grad; } std::pair, std::vector> SGD::onMakeParameterUpdateGraphByGrad(const std::vector& parameterGrads) { std::map varUpdateMap; auto momentum = _Const(mMomentum, {}, NCHW); auto weightDecay = _Const(mWeightDecay, {}, NCHW); for (int pIndex=0; pIndexname().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 history = _Const(0.0f, pDims, pInfo->order); history->setName(p->name() + "_momentum"); history.fix(VARP::TRAINABLE); auto newHistory = gradWithDecay + momentum * history; newHistory->setName("update_" + history->name()); VARP localLearningRate = parameterGrads[pIndex].learningRate; VARP finalGrad = localLearningRate * history; finalGrad->setName(p->name() + "_final_grad"); auto updateValue = _Subtract(p, finalGrad); updateValue->setName("update_" + p->name()); varUpdateMap[p] = updateValue; varUpdateMap[history] = newHistory; } 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