/* * 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.energetic; import com.heatonresearch.aifh.randomize.GenerateRandom; import com.heatonresearch.aifh.randomize.MersenneTwisterGenerateRandom; /** * Implements a Boltzmann machine. * */ public class BoltzmannMachine extends EnergeticNetwork { /** * The current temperature of the neural network. The higher the * temperature, the more random the network will behave. */ private double temperature; /** * The thresholds. */ private double[] threshold; /** * Count used to internally determine if a neuron is "on". */ private transient int[] on; /** * Count used to internally determine if a neuron is "off". */ private transient int[] off; /** * The number of cycles to anneal for. */ private int annealCycles = 100; /** * The number of cycles to run the network through before annealing. */ private int runCycles = 1000; private GenerateRandom random = new MersenneTwisterGenerateRandom(); /** * Default constructors. */ public BoltzmannMachine() { super(); } /** * Construct a Boltzmann machine with the specified number of neurons. * @param neuronCount The number of neurons. */ public BoltzmannMachine(final int neuronCount) { super(neuronCount); this.threshold = new double[neuronCount]; } /** * Note: for Boltzmann networks, you will usually want to call the "run" * method to compute the output. * * This method can be used to copy the input data to the current state. A * single iteration is then run, and the new current state is returned. * * @param input * The input pattern. * @return The new current state. */ public double[] compute(final double[] input) { final double[] result = new double[input.length]; System.arraycopy(input, 0, getCurrentState(), 0, input.length); run(); System.arraycopy(getCurrentState(), 0, result, 0, result.length); return result; } /** * Decrease the temperature by the specified amount. * * @param d * The amount to decrease by, for example .8 to change to * 80% of current. */ public void decreaseTemperature(final double d) { this.temperature *= d; } public void establishEquilibrium() { final int count = getNeuronCount(); if (this.on == null) { this.on = new int[count]; this.off = new int[count]; } for (int i = 0; i < count; i++) { this.on[i] = 0; this.off[i] = 0; } for (int n = 0; n < this.runCycles * count; n++) { run((int) this.random.nextDouble(0, count - 1)); } for (int n = 0; n < this.annealCycles * count; n++) { final int i = (int) this.random.nextDouble(0, count - 1); run(i); if (getCurrentState()[i]>0) { this.on[i]++; } else { this.off[i]++; } } for (int i = 0; i < count; i++) { getCurrentState()[i] = this.on[i] > this.off[i]?1:0; } } /** * @return the annealCycles */ public int getAnnealCycles() { return this.annealCycles; } /** * {@inheritDoc} */ public int getInputCount() { return getNeuronCount(); } /** * {@inheritDoc} */ public int getOutputCount() { return getNeuronCount(); } /** * @return the runCycles */ public int getRunCycles() { return this.runCycles; } /** * @return The temperature the network is currently operating at. */ public double getTemperature() { return this.temperature; } /** * @return the threshold */ public double[] getThreshold() { return this.threshold; } /** * Run the network for all neurons present. */ public void run() { final int count = getNeuronCount(); for (int i = 0; i < count; i++) { run(i); } } /** * Run the network for the specified neuron. * * @param i * The neuron to run for. */ public void run(final int i) { int j; double sum, probability; final int count = getNeuronCount(); sum = 0; for (j = 0; j < count; j++) { sum += getWeight(i, j) * ((getCurrentState()[j]>0) ? 1 : 0); } sum -= this.threshold[i]; probability = 1 / (1 + Math.exp(-sum / this.temperature)); if (this.random.nextDouble() <= probability) { getCurrentState()[i] = 1.0; } else { getCurrentState()[i] = 0.0; } } /** * @param annealCycles * the annealCycles to set */ public void setAnnealCycles(final int annealCycles) { this.annealCycles = annealCycles; } /** * @param runCycles * the runCycles to set */ public void setRunCycles(final int runCycles) { this.runCycles = runCycles; } /** * Set the network temperature. * * @param temperature * The temperature to operate the network at. */ public void setTemperature(final double temperature) { this.temperature = temperature; } /** * Set the thresholds. * @param t The thresholds. */ public void setThreshold(final double[] t) { this.threshold = t; } /** * {@inheritDoc} */ public void updateProperties() { // nothing needed here } /** * @return The random number generator. */ public GenerateRandom getRandom() { return this.random; } /** * Set the random number generator. * @param random The random number generator. */ public void setRandom(final GenerateRandom random) { this.random = random; } /** * {@inheritDoc} */ @Override public double[] getLongTermMemory() { return new double[0]; //To change body of implemented methods use File | Settings | File Templates. } }