19template<
typename FunctionType>
21template<
typename FunctionType>
24template<
typename FunctionType,
typename ConstantType>
25ConstantType GradientDescentInstantiationSearcher<FunctionType, ConstantType>::doStep(
28 const ConstantType precisionAsConstant =
35 ConstantType projectedGradient;
38 ConstantType newPlainPosition = oldPosAsConstant + precisionAsConstant * gradient.at(steppingParameter);
43 if (newPlainPosition < lower || newPlainPosition > upper) {
44 projectedGradient = 0;
46 projectedGradient = gradient.at(steppingParameter);
53 if (oldPosAsConstant < precisionAsConstant) {
54 projectedGradient = 1000;
56 projectedGradient = -1000;
58 projectedGradient = gradient.at(steppingParameter);
70 projectedGradient = gradient.at(steppingParameter) + logarithmicBarrierTerm / (oldPosAsConstant - precisionAsConstant);
73 gradient.at(steppingParameter) - logarithmicBarrierTerm / (
utility::one<ConstantType>() - precisionAsConstant - oldPosAsConstant);
76 if (oldPosAsConstant < precisionAsConstant) {
83 projectedGradient = gradient.at(steppingParameter);
88 if (Adam* adam = boost::get<Adam>(&gradientDescentType)) {
91 adam->decayingStepAverage[steppingParameter] =
92 adam->averageDecay * adam->decayingStepAverage[steppingParameter] + (
utility::one<ConstantType>() - adam->averageDecay) * projectedGradient;
93 adam->decayingStepAverageSquared[steppingParameter] = adam->squaredAverageDecay * adam->decayingStepAverageSquared[steppingParameter] +
96 const ConstantType correctedGradient =
98 const ConstantType correctedSquaredGradient =
101 const ConstantType toSqrt = correctedSquaredGradient;
102 ConstantType sqrtResult = constantTypeSqrt(toSqrt);
104 step = (adam->learningRate / (sqrtResult + precisionAsConstant)) * correctedGradient;
105 }
else if (RAdam* radam = boost::get<RAdam>(&gradientDescentType)) {
113 radam->decayingStepAverageSquared[steppingParameter] = radam->squaredAverageDecay * radam->decayingStepAverageSquared[steppingParameter] +
116 radam->decayingStepAverage[steppingParameter] =
117 radam->averageDecay * radam->decayingStepAverage[steppingParameter] + (
utility::one<ConstantType>() - radam->averageDecay) * projectedGradient;
119 const ConstantType biasCorrectedMovingAverage =
121 const ConstantType squaredAverageDecayPow =
utility::pow(radam->squaredAverageDecay, stepNum + 1);
123 const ConstantType lengthApproxSMA =
127 if (lengthApproxSMA > 4) {
129 const ConstantType adaptiveLearningRate =
130 constantTypeSqrt((
utility::one<ConstantType>() - squaredAverageDecayPow) / radam->decayingStepAverageSquared[steppingParameter]);
132 const ConstantType varianceRectification =
133 constantTypeSqrt(((lengthApproxSMA - 4) / (maxLengthApproxSMA - 4)) * ((lengthApproxSMA - 2) / (maxLengthApproxSMA - 2)) *
134 ((maxLengthApproxSMA) / (lengthApproxSMA)));
136 step = radam->learningRate * varianceRectification * biasCorrectedMovingAverage * adaptiveLearningRate;
139 step = radam->learningRate * biasCorrectedMovingAverage;
141 }
else if (RmsProp* rmsProp = boost::get<RmsProp>(&gradientDescentType)) {
142 rmsProp->rootMeanSquare[steppingParameter] = rmsProp->averageDecay * rmsProp->rootMeanSquare[steppingParameter] +
145 const ConstantType toSqrt = rmsProp->rootMeanSquare[steppingParameter] + precisionAsConstant;
146 ConstantType sqrtResult = constantTypeSqrt(toSqrt);
148 step = (rmsProp->learningRate / sqrtResult) * projectedGradient;
149 }
else if (Plain* plain = boost::get<Plain>(&gradientDescentType)) {
152 step = -plain->learningRate;
154 step = plain->learningRate;
159 step = plain->learningRate * projectedGradient;
161 }
else if (Momentum* momentum = boost::get<Momentum>(&gradientDescentType)) {
164 step = -momentum->learningRate;
166 step = momentum->learningRate;
171 step = momentum->learningRate * projectedGradient;
173 step += momentum->momentumTerm * momentum->pastStep.at(steppingParameter);
174 momentum->pastStep[steppingParameter] = step;
175 }
else if (Nesterov* nesterov = boost::get<Nesterov>(&gradientDescentType)) {
178 step = -nesterov->learningRate;
180 step = nesterov->learningRate;
185 step = nesterov->learningRate * projectedGradient;
187 step += nesterov->momentumTerm * nesterov->pastStep.at(steppingParameter);
188 nesterov->pastStep[steppingParameter] = step;
195 position[steppingParameter] = newPos;
201 position[steppingParameter] =
utility::max(lower, position[steppingParameter]);
202 position[steppingParameter] =
utility::min(upper, position[steppingParameter]);
207template<
typename FunctionType,
typename ConstantType>
208ConstantType GradientDescentInstantiationSearcher<FunctionType, ConstantType>::stochasticGradientDescent(
210 uint_fast64_t initialStateModel = model.getStates(
"init").getNextSetIndex(0);
212 ConstantType currentValue;
213 switch (this->synthesisTask->getBound().comparisonType) {
225 uint64_t tinyChangeIterations = 0;
227 std::map<VariableType<FunctionType>, ConstantType> deltaVector;
229 std::vector<VariableType<FunctionType>> parameterEnumeration;
230 for (
auto parameter : this->parameters) {
231 parameterEnumeration.push_back(parameter);
234 utility::Stopwatch printUpdateStopwatch;
235 printUpdateStopwatch.start();
239 uint_fast64_t parameterNum = 0;
240 for (uint_fast64_t stepNum = 0;
true; ++stepNum) {
241 if (printUpdateStopwatch.getTimeInSeconds() >= 15) {
242 printUpdateStopwatch.restart();
246 std::vector<VariableType<FunctionType>> miniBatch;
247 for (uint_fast64_t i = parameterNum;
i < std::min((uint_fast64_t)parameterEnumeration.size(), parameterNum + miniBatchSize);
i++) {
248 miniBatch.push_back(parameterEnumeration[i]);
251 ConstantType oldValue = currentValue;
257 if (Nesterov* nesterov = boost::get<Nesterov>(&gradientDescentType)) {
259 for (
auto const& parameter : miniBatch) {
260 ConstantType
const addedTerm = nesterov->momentumTerm * nesterov->pastStep[parameter];
262 nesterovPredictedPosition[parameter] =
utility::max(precision, nesterovPredictedPosition[parameter]);
263 nesterovPredictedPosition[parameter] =
utility::min(upperBound, nesterovPredictedPosition[parameter]);
268 for (
auto const& parameter : parameters) {
269 nesterovPredictedPosition[parameter] =
286 bool stochasticPosition =
true;
287 for (
auto const& parameter : parameters) {
288 if (nesterovPredictedPosition[parameter] < 0 + precision || nesterovPredictedPosition[parameter] > 1 - precision) {
289 stochasticPosition =
false;
294 bool computeValue =
true;
296 if (!stochasticPosition) {
297 computeValue =
false;
302 std::unique_ptr<storm::modelchecker::CheckResult> intermediateResult = instantiationModelChecker->check(env, nesterovPredictedPosition);
303 std::vector<ConstantType> valueVector = intermediateResult->asExplicitQuantitativeCheckResult<ConstantType>().getValueVector();
304 if (boost::get<Nesterov>(&gradientDescentType)) {
307 for (
auto const& parameter : parameters) {
308 modelCheckPosition[parameter] =
314 std::unique_ptr<storm::modelchecker::CheckResult> terminationResult = instantiationModelChecker->check(env, modelCheckPosition);
315 std::vector<ConstantType> terminationValueVector = terminationResult->asExplicitQuantitativeCheckResult<ConstantType>().getValueVector();
316 currentValue = terminationValueVector[initialStateModel];
318 currentValue = valueVector[initialStateModel];
321 if (synthesisTask->getBound().isSatisfied(currentValue) && stochasticPosition) {
325 for (
auto const& parameter : miniBatch) {
326 auto checkResult = derivativeEvaluationHelper->check(env, nesterovPredictedPosition, parameter, valueVector);
327 ConstantType delta = checkResult->getValueVector()[derivativeEvaluationHelper->getInitialState()];
332 deltaVector[parameter] = delta;
345 VisualizationPoint point;
346 point.position = nesterovPredictedPosition;
347 point.value = currentValue;
348 walk.push_back(point);
355 for (
auto const& parameter : miniBatch) {
356 doStep(parameter, position, deltaVector, stepNum);
360 tinyChangeIterations += miniBatch.size();
361 if (tinyChangeIterations > parameterEnumeration.size()) {
365 tinyChangeIterations = 0;
369 parameterNum = parameterNum + miniBatchSize;
370 if (parameterNum >= parameterEnumeration.size()) {
375 STORM_LOG_WARN(
"Aborting Gradient Descent, returning non-optimal value.");
382template<
typename FunctionType,
typename ConstantType>
385 STORM_LOG_ASSERT(this->synthesisTask,
"Call setup before calling gradientDescent.");
387 resetDynamicValues();
389 STORM_LOG_ASSERT(this->synthesisTask->isBoundSet(),
"Task does not involve a bound.");
393 std::optional<ConstantType> bestValue;
395 std::random_device device;
396 std::default_random_engine engine(device());
397 std::uniform_real_distribution<> dist(0, 1);
398 bool initialGuess =
true;
403 STORM_LOG_PROGRESS(
"Trying initial guess (p->0.5 for every parameter p or set start point)\n");
406 for (
auto const& param : this->parameters) {
410 point[param] = (*startPoint)[param];
422 initialGuess =
false;
426 stochasticWatch.start();
428 ConstantType prob = stochasticGradientDescent(point);
429 stochasticWatch.stop();
431 bool isFoundPointBetter = !bestValue;
433 switch (this->synthesisTask->getBound().comparisonType) {
436 isFoundPointBetter = prob > *bestValue;
440 isFoundPointBetter = prob < *bestValue;
444 if (isFoundPointBetter) {
445 bestInstantiation = point;
449 if (synthesisTask->getBound().isSatisfied(*bestValue)) {
456 logarithmicBarrierTerm = logarithmicBarrierTerm / 10;
457 STORM_LOG_PROGRESS(
"Smaller term\n" << *bestValue <<
"\n" << logarithmicBarrierTerm <<
"\n");
460 STORM_LOG_PROGRESS(
"Sorry, couldn't satisfy the bound (yet). Best found value so far: " << *bestValue <<
"\n");
467 for (
auto const& parameter : parameters) {
468 bestInstantiation[parameter] =
475 STORM_LOG_ASSERT(bestValue.has_value(),
"Expected at least one evaluated instantiation.");
476 return std::make_pair(bestInstantiation, *bestValue);
479template<
typename FunctionType,
typename ConstantType>
480void GradientDescentInstantiationSearcher<FunctionType, ConstantType>::resetDynamicValues() {
481 if (Adam* adam = boost::get<Adam>(&gradientDescentType)) {
482 for (
auto const& parameter : this->parameters) {
486 }
else if (RAdam* radam = boost::get<RAdam>(&gradientDescentType)) {
487 for (
auto const& parameter : this->parameters) {
491 }
else if (RmsProp* rmsProp = boost::get<RmsProp>(&gradientDescentType)) {
492 for (
auto const& parameter : this->parameters) {
495 }
else if (Momentum* momentum = boost::get<Momentum>(&gradientDescentType)) {
496 for (
auto const& parameter : this->parameters) {
499 }
else if (Nesterov* nesterov = boost::get<Nesterov>(&gradientDescentType)) {
500 for (
auto const& parameter : this->parameters) {
506template<
typename FunctionType,
typename ConstantType>
510 for (
auto s = walk.begin(); s != walk.end(); ++s) {
512 auto point = s->position;
513 for (
auto iter = point.begin(); iter != point.end(); ++iter) {
514 std::cout <<
"\"" << iter->first.name() <<
"\"";
517 std::cout <<
"\"value\":" << s->value <<
"}";
518 if (std::next(s) != walk.end()) {
524 std::cout << storm::utility::convertNumber<double>(walk.at(walk.size() - 1).value) <<
"\n";
527template<
typename FunctionType,
typename ConstantType>
528std::vector<typename GradientDescentInstantiationSearcher<FunctionType, ConstantType>::VisualizationPoint>
void printRunAsJson()
Print the previously done run as JSON.
std::vector< VisualizationPoint > getVisualizationWalk()
Get the visualization walk that is recorded if recordRun is set to true in the constructor (false by ...
std::pair< std::map< typename utility::parametric::VariableType< FunctionType >::type, typename utility::parametric::CoefficientType< FunctionType >::type >, ConstantType > gradientDescent()
Perform Gradient Descent.
#define STORM_LOG_WARN(message)
#define STORM_LOG_PROGRESS(message)
#define STORM_LOG_ERROR(message)
#define STORM_LOG_ASSERT(cond, message)
typename utility::parametric::CoefficientType< FunctionType >::type CoefficientType
typename utility::parametric::VariableType< FunctionType >::type VariableType
SettingsType const & getModule()
Get module.
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
ValueType max(ValueType const &first, ValueType const &second)
ValueType min(ValueType const &first, ValueType const &second)
ValueType abs(ValueType const &number)
ValueType pow(ValueType const &value, int_fast64_t exponent)
TargetType convertNumber(SourceType const &number)