/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.mahout.classifier.rbm.model;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.mahout.classifier.rbm.layer.Layer;
import org.apache.mahout.common.distance.DistanceMeasure;
import org.apache.mahout.common.distance.EuclideanDistanceMeasure;
import org.apache.mahout.math.Vector;
import com.google.common.io.Closeables;
/**
* The Class RBMModel.
*/
public abstract class RBMModel {
/** The visible layer. */
protected Layer visibleLayer;
/** The hidden layer. */
protected Layer hiddenLayer;
/**
* Gets the visible layer.
*
* @return the visible layer
*/
public Layer getVisibleLayer() {
return visibleLayer;
}
/**
* Gets the hidden layer.
*
* @return the hidden layer
*/
public Layer getHiddenLayer() {
return hiddenLayer;
}
/**
* Excite hidden layer.
*
* @param inputFactor factor which should be multiplied with the inputs of the units, usually 1
* @param addInput true if input should be added to the input of the hidden layer
*/
public abstract void exciteHiddenLayer(double inputFactor, boolean addInput);
/**
* Excite visible layer.
*
* @param inputFactor factor which should be multiplied with the inputs of the units, usually 1
* @param addInput true if input should be added to the input of the hidden layer
*/
public abstract void exciteVisibleLayer(double inputFactor, boolean addInput);
/**
* Serialize.
*
* @param output output path where the model should be serialized to
* @param conf the conf
* @throws IOException Signals that an I/O exception has occurred.
*/
public abstract void serialize(Path output, Configuration conf) throws IOException;
/**
* Materialize.
*
* @param input the path to the model
* @param conf the hadoop configuration
* @return the model
* @throws IOException Signals that an I/O exception has occurred.
*/
public static RBMModel materialize(Path input, Configuration conf) throws IOException {
FileSystem fs = input.getFileSystem(conf);
String rbmType = "";
FSDataInputStream in = fs.open(input);
try {
char chr;
while((chr=in.readChar())!=' ')
rbmType += chr;
} finally {
Closeables.closeQuietly(in);
}
try {
return (RBMModel)Class.forName(rbmType).
getMethod("materialize",Path.class, Configuration.class).invoke(null,input, conf);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Sets the visible layer.
*
* @param visibleLayer the new visible layer
*/
public void setVisibleLayer(Layer visibleLayer) {
this.visibleLayer = visibleLayer;
}
/**
* Gets the reconstruction error by doing one time gibbs sampling and computing the euclidean distance
* between the input and the reconstruction.
*
* @param input the input
* @return the reconstruction error
*/
public double getReconstructionError(Vector input) {
this.visibleLayer.setActivations(input);
exciteHiddenLayer(1,false);
getHiddenLayer().updateNeurons();
exciteVisibleLayer(1,false);
DistanceMeasure dm = new EuclideanDistanceMeasure();
return dm.distance(input, visibleLayer.getExcitations());
}
/**
* Update hidden layer according to their excitations.
*/
public void updateHiddenLayer() {
hiddenLayer.updateNeurons();
}
/**
* Update visible layer.according to their excitations
*/
public void updateVisibleLayer() {
visibleLayer.updateNeurons();
}
/**
* Gets the reconstruction error of the current visible layers data.
*
* @return the reconstruction error
*/
public double getReconstructionError() {
Vector input = this.visibleLayer.getActivations().clone();
exciteHiddenLayer(1,false);
updateHiddenLayer();
exciteVisibleLayer(1,false);
DistanceMeasure dm = new EuclideanDistanceMeasure();
return dm.distance(input, visibleLayer.getExcitations());
}
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
public abstract RBMModel clone();
}