// // ParameterOptimizer.cpp // MNN // // Created by MNN on 2019/11/22. // Copyright © 2018, Alibaba Group Holding Limited // #include #include "MNN_generated.h" #include "ParameterOptimizer.hpp" #include "SGD.hpp" #include "ADAM.hpp" using namespace MNN::Express; // TODO: need Refract static bool _ReNameTensor(std::unique_ptr& net) { auto& mNet = net; // Check dup name and modify std::set opnames; for (int i = 0; i < mNet->oplists.size(); ++i) { auto& op = mNet->oplists[i]; auto opName = op->name; if (opName.empty()) { std::ostringstream defaultName; defaultName << EnumNameOpType(op->type); defaultName << i; op->name = defaultName.str(); MNN_PRINT("%d op name is empty, set to %s\n", i, op->name.c_str()); } bool rename = false; do { if (opnames.find(op->name) == opnames.end()) { break; } op->name = op->name + "_"; rename = true; } while (true); opName = op->name; if (rename) { MNN_PRINT("%d op name is dup, set to %s\n", i, op->name.c_str()); } opnames.insert(opName); } std::set tensorNames; for (int i = 0; i < mNet->tensorName.size(); ++i) { auto tensorName = mNet->tensorName[i]; if (tensorName.empty()) { tensorName = std::to_string(i); } bool rename = false; do { if (tensorNames.find(tensorName) == tensorNames.end()) { break; } tensorName = tensorName + "_"; rename = true; } while (true); if (rename) { MNN_PRINT("%d tensor name is dup, set to %s\n", i, tensorName.c_str()); } mNet->tensorName[i] = tensorName; tensorNames.insert(tensorName); } return true; } namespace MNN { namespace Train { ParameterOptimizer::ParameterOptimizer(std::shared_ptr module) { mModule = module; if (nullptr == mModule) { mModule.reset(Module::createEmpty(std::vector{})); } auto parameters = mModule->parameters(); for (auto p : parameters) { if (nullptr == p.get()) { continue; } if (p->expr().first->get() != nullptr) { continue; } if (p->expr().first->inputType() == Express::VARP::TRAINABLE) { mTrainable.insert(p); } } } ParameterOptimizer* ParameterOptimizer::createSGD(std::shared_ptr module, float lr, float momentum, float weightDecay, RegularizationMethod method) { auto sgd = new SGD(module); sgd->setLearningRate(lr); sgd->setMomentum(momentum); sgd->setWeightDecay(weightDecay); sgd->setRegularizationMethod(method); return sgd; } std::pair, std::vector> ParameterOptimizer::makeParameterUpdateGraphByGrad(const std::vector& p, const std::vector& pd, const std::vector& lr) { if (p.size() != pd.size() || lr.size() != pd.size()) { MNN_ERROR("[ParameterOptimizer] makeParameterUpdateGraphByGrad: Size not match\n"); std::pair, std::vector> temp; return temp; } std::vector grads; for (int i=0; ionMakeParameterUpdateGraphByGrad(grads); } ParameterOptimizer* ParameterOptimizer::createADAM(std::shared_ptr module, float lr, float momentum, float momentum2, float weightDecay, float eps, RegularizationMethod method) { auto adam = new ADAM(module); adam->setLearningRate(lr); adam->setMomentum(momentum); adam->setMomentum2(momentum2); adam->setWeightDecay(weightDecay); adam->setEps(eps); adam->setRegularizationMethod(method); return adam; } std::pair, std::vector> ParameterOptimizer::onMakeParameterUpdateGraphByGrad(const std::vector& parameterGrads) { MNN_ERROR("[ParameterOptimizer]: Don't support make static graph for update parameters\n"); return std::make_pair(std::vector{}, std::vector{}); } bool ParameterOptimizer::step(Express::VARP loss) { mStep++; auto res = this->onGetNextParameter(loss); for (auto iter : res) { iter.second.fix(Express::VARP::TRAINABLE); } for (auto iter : res) { iter.first->input(iter.second); } return !res.empty(); } int ParameterOptimizer::currentStep() { return mStep; } void ParameterOptimizer::setCurrentStep(int step) { mStep = step; } static void _saveMNN(MNN::NetT* netStruct, const char* mnnFileName) { flatbuffers::FlatBufferBuilder builder(1024); auto offset = Net::Pack(builder, netStruct); builder.Finish(offset); // TODO, use FileWriter instead FILE* f = fopen(mnnFileName, "wb"); fwrite(builder.GetBufferPointer(), 1, builder.GetSize(), f); fclose(f); } void ParameterOptimizer::makeLoopModel(const char* mnnFileName, std::vector outputs, const std::pair, std::vector>& parameters) { if (parameters.first.size() != parameters.second.size()) { MNN_ERROR("[ParameterOptimizer] makeLoopModel Size not match\n"); return; } auto parameterSize = parameters.first.size(); for (int i=0; i netStruct(new MNN::NetT); Variable::save(outputs, netStruct.get()); _ReNameTensor(netStruct); if (parameterSize == 0) { _saveMNN(netStruct.get(), mnnFileName); return; } for (int i = 0; i < netStruct->oplists.size(); ++i) { auto& op = netStruct->oplists[i]; for (int v=0; vname() == op->name) { for (int j = 0; j < netStruct->oplists.size(); ++j) { auto& opSub = netStruct->oplists[j]; if (opSub->name == pi->name()) { auto indexOri = op->outputIndexes; op->outputIndexes = opSub->outputIndexes; if ((opSub->name.find("_BN_RunningMean_Weight") != std::string::npos) || (opSub->name.find("_BN_RunningVariance_Weight") != std::string::npos)) { for (int k = 0; k < netStruct->oplists.size(); ++k) { auto& opSubSub = netStruct->oplists[k]; if (opSubSub->inputIndexes.size() > 0) { for (int kk = 0; kk < opSubSub->inputIndexes.size(); kk++) { if (opSubSub->inputIndexes[kk] == indexOri[0]) { opSubSub->inputIndexes[kk] = opSub->outputIndexes[0]; } } } } } } } } } } _saveMNN(netStruct.get(), mnnFileName); } } // namespace Train } // namespace MNN