/* * Artificial Intelligence for Humans * Volume 3: Deep Learning and Neural Networks * Java Version * http://www.aifh.org * http://www.jeffheaton.com * * Code repository: * https://github.com/jeffheaton/aifh * * Copyright 2014-2015 by Jeff Heaton * * 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 com.heatonresearch.aifh.dbnn; import com.heatonresearch.aifh.error.ErrorCalculation; import com.heatonresearch.aifh.error.ErrorCalculationMSE; import com.heatonresearch.aifh.learning.LearningMethod; /** * Supervised training for the DBN. Used to train the output layer with labels. */ public class SupervisedTrainDBN implements LearningMethod { /** * The network to train. */ private final DeepBeliefNetwork network; /** * The input (x) for the training. */ private final double[][] trainingInput; /** * The expected output (y, or labels). */ private final double[][] trainingIdeal; /** * The learning rate. */ private final double learningRate; /** * The error calculation to use. */ private ErrorCalculation errorCalc = new ErrorCalculationMSE(); /** * Construct the supervised trainer for DBN. * @param theNetwork The network to train. * @param theTrainingInput The input (x) to train. * @param theTrainingIdeal The expected output (y, or labels) to train. * @param theLearningRate The learning rate. */ public SupervisedTrainDBN(DeepBeliefNetwork theNetwork, double[][] theTrainingInput, double[][] theTrainingIdeal, double theLearningRate) { this.network = theNetwork; this.trainingInput = theTrainingInput; this.learningRate = theLearningRate; this.trainingIdeal = theTrainingIdeal; } /** * {@inheritDoc} */ @Override public void iteration() { double[] layerInput = new double[0]; double[] prevLayerInput; this.errorCalc.clear(); for (int n = 0; n < this.trainingInput.length; n++) { for (int i = 0; i < this.network.getLayers().length; i++) { if (i == 0) { prevLayerInput = new double[this.network.getInputCount()]; System.arraycopy(this.trainingInput[n], 0, prevLayerInput, 0, this.network.getInputCount()); } else { prevLayerInput = new double[this.network.getLayers()[i].getInputCount()]; System.arraycopy(layerInput, 0, prevLayerInput, 0, this.network.getLayers()[i].getInputCount()); } layerInput = new double[this.network.getLayers()[i].getOutputCount()]; this.network.getLayers()[i].sampleHgivenV(prevLayerInput, layerInput); } trainLogisticLayer(layerInput, this.trainingIdeal[n]); } } /** * {@inheritDoc} */ @Override public double getLastError() { return this.errorCalc.calculate(); } /** * {@inheritDoc} */ @Override public boolean done() { return false; } /** * {@inheritDoc} */ @Override public String getStatus() { return ""; } /** * {@inheritDoc} */ @Override public void finishTraining() { } /** * Train the logistic layer, the output layer. * @param input The input (x). * @param ideal The expected output (y, or labels). */ private void trainLogisticLayer(double[] input, double[] ideal) { double[] pYgivenX = new double[this.network.getLogLayer().getOutputCount()]; double[] dy = new double[this.network.getLogLayer().getOutputCount()]; for(int i=0; i<this.network.getLogLayer().getOutputCount(); i++) { pYgivenX[i] = 0; for(int j=0; j<this.network.getLogLayer().getInputCount(); j++) { pYgivenX[i] += this.network.getLogLayer().getWeights()[i][j] * input[j]; } pYgivenX[i] += this.network.getLogLayer().getBias()[i]; } this.network.getLogLayer().softmax(pYgivenX); for(int i=0; i<this.network.getLogLayer().getOutputCount(); i++) { dy[i] = ideal[i] - pYgivenX[i]; this.errorCalc.updateError(ideal[i], pYgivenX[i]); for(int j=0; j<this.network.getLogLayer().getInputCount(); j++) { this.network.getLogLayer().getWeights()[i][j] += this.learningRate * dy[i] * input[j] / this.trainingInput.length; } this.network.getLogLayer().getBias()[i] += this.learningRate * dy[i] / this.trainingInput.length; } } /** * @return The error calculation method. */ public ErrorCalculation getErrorCalc() { return this.errorCalc; } /** * Set the error calculation method. * @param errorCalc The error calculation method. */ public void setErrorCalc(final ErrorCalculation errorCalc) { this.errorCalc = errorCalc; } }