/*
* Encog(tm) Core v3.4 - Java Version
* http://www.heatonresearch.com/encog/
* https://github.com/encog/encog-java-core
* Copyright 2008-2016 Heaton Research, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package org.encog.ml.train.strategy;
import org.encog.ml.train.MLTrain;
import org.encog.util.logging.EncogLogging;
/**
* A hybrid stragey allows a secondary training algorithm to be used. Once the
* primary algorithm is no longer improving by much, the secondary will be used.
* Using simulated annealing in as a secondary to one of the propagation methods
* is often a very efficient combination as it can help the propagation method
* escape a local minimum. This is particularly true with backpropagation.
*
* @author jheaton
*
*/
public class HybridStrategy implements Strategy {
/**
* The default minimum improvement before we switch to the alternate
* training method.
*/
public static final double DEFAULT_MIN_IMPROVEMENT = 0.00001;
/**
* The default number of cycles to tolerate bad improvement for.
*/
public static final int DEFAULT_TOLERATE_CYCLES = 10;
/**
* The default number of cycles to use the alternate training for.
*/
public static final int DEFAULT_ALTERNATE_CYCLES = 5;
/**
* The primary training method.
*/
private MLTrain mainTrain;
/**
* The alternate training method.
*/
private final MLTrain altTrain;
/**
* The last improvement.
*/
private double lastImprovement;
/**
* The error rate from the previous iteration.
*/
private double lastError;
/**
* Has one iteration passed, and we are now ready to start
* evaluation.
*/
private boolean ready;
/**
* The last time the alternate training algorithm was used.
*/
private int lastHybrid;
/**
* The minimum improvement before the alternate training
* algorithm is considered.
*/
private final double minImprovement;
/**
* The number of minimal improvement to tolerate before the
* alternate training algorithm is used.
*/
private final int tolerateMinImprovement;
/**
* How many cycles to engage the alternate algorithm for.
*/
private final int alternateCycles;
/**
* Construct a hybrid strategy with the default minimum improvement
* and toleration cycles.
* @param altTrain The alternative training strategy.
*/
public HybridStrategy(final MLTrain altTrain) {
this(altTrain, HybridStrategy.DEFAULT_MIN_IMPROVEMENT,
HybridStrategy.DEFAULT_TOLERATE_CYCLES,
HybridStrategy.DEFAULT_ALTERNATE_CYCLES);
}
/**
* Create a hybrid strategy.
* @param altTrain The alternate training algorithm.
* @param minImprovement The minimum improvement to switch algorithms.
* @param tolerateMinImprovement The number of cycles to tolerate the
* minimum improvement for.
* @param alternateCycles How many cycles should the alternate
* training algorithm be used for.
*/
public HybridStrategy(final MLTrain altTrain, final double minImprovement,
final int tolerateMinImprovement, final int alternateCycles) {
this.altTrain = altTrain;
this.ready = false;
this.lastHybrid = 0;
this.minImprovement = minImprovement;
this.tolerateMinImprovement = tolerateMinImprovement;
this.alternateCycles = alternateCycles;
}
/**
* Initialize this strategy.
*
* @param train
* The training algorithm.
*/
public void init(final MLTrain train) {
this.mainTrain = train;
}
/**
* Called just after a training iteration.
*/
public void postIteration() {
if (this.ready) {
final double currentError = this.mainTrain.getError();
this.lastImprovement = (currentError - this.lastError)
/ this.lastError;
EncogLogging.log(EncogLogging.LEVEL_DEBUG, "Last improvement: " + this.lastImprovement);
if ((this.lastImprovement > 0)
|| (Math.abs(this.lastImprovement) < this.minImprovement)) {
this.lastHybrid++;
if (this.lastHybrid > this.tolerateMinImprovement) {
this.lastHybrid = 0;
EncogLogging.log(EncogLogging.LEVEL_DEBUG, "Performing hybrid cycle");
for (int i = 0; i < this.alternateCycles; i++) {
this.altTrain.iteration();
}
}
}
} else {
this.ready = true;
}
}
/**
* Called just before a training iteration.
*/
public void preIteration() {
this.lastError = this.mainTrain.getError();
}
}