All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.learning.algorithm.InputOutputTransformedBatchLearner Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:            InputOutputTransformedLearner.java
 * Authors:         Justin Basilico
 * Project:         Cognitive Foundry
 * 
 * Copyright 2011 Cognitive Foundry. All rights reserved.
 */

package gov.sandia.cognition.learning.algorithm;

import gov.sandia.cognition.evaluator.CompositeEvaluatorTriple;
import gov.sandia.cognition.evaluator.Evaluator;
import gov.sandia.cognition.evaluator.IdentityEvaluator;
import gov.sandia.cognition.evaluator.ReversibleEvaluator;
import gov.sandia.cognition.learning.algorithm.baseline.ConstantLearner;
import gov.sandia.cognition.learning.data.DatasetUtil;
import gov.sandia.cognition.learning.data.DefaultInputOutputPair;
import gov.sandia.cognition.learning.data.DefaultWeightedInputOutputPair;
import gov.sandia.cognition.learning.data.InputOutputPair;
import gov.sandia.cognition.learning.data.WeightedInputOutputPair;
import gov.sandia.cognition.util.ObjectUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * An adapter class for performing supervised learning from data where both
 * the input and output have to be transformed before they are passed to the
 * learning algorithm. The typical use-case for this class is to make use of
 * some supervised learning algorithm on data that does not directly fit its
 * input and/or output types. Thus, the data must be transformed before the
 * learner is run on the data. It must also be transformed when the resulting
 * evaluator is applied to new data. Since both the inputs and outputs need
 * to be converted, unsupervised learning algorithms are to be provided to
 * learn those transforms from the collection of inputs and outputs,
 * respectively. While the input learner just needs to be an evaluator to
 * forward-transform the data, the output learner needs to be reversible so
 * that the training labels can be reversed from values that the supervised
 * learner can be trained on. Thus, the forward evaluation is used during 
 * training reverse evaluation of the output, while the reverse is used when
 * applying it to new data. The result of this learning adapter is the triple
 * containing the learned input, supervised, and output evaluators, which can
 * be applied to the same data types that the adapter was given in training.
 *
 * Note that this class can also be used in cases where only one side needs
 * to be converted, either by using the static {@code create} methods, or by
 * passing in {@code ConstantLearner}s that contain
 * {@code IdentityEvaluator}s. Thus, this class can act as a very flexible
 * adapter for many types of supervised learning problems.
 *
 * @param   
 *      The input type of the data to learn on. This is passed into the
 *      unsupervised learner for the input transform to create the evaluator
 *      that will then produce the {@code TransformedInputType}.
 * @param   
 *      The output type of the input transformer, which will be used as the
 *      input values to train the (middle) supervised learner.
 * @param   
 *      The input type of the output transformer, which will be used as the
 *      output values to train the (middle) supervised learner. It will be
 *      the output type of the output transformer (and input type of its
 *      reverse).
 * @param   
 *      The output type of the data to learn on. This is passed into the
 *      unsupervised learner for the output transform to create the reversible
 *      data converter for mapping the {@code OutputType} to the
 *      {@code TransformedOutputType}, or vice-versa.
 * @author  Justin Basilico
 * @since   3.3.3
 */
public class InputOutputTransformedBatchLearner
    extends AbstractBatchLearnerContainer>, ? extends Evaluator>>
    implements SupervisedBatchLearner>
{

    /** The unsupervised learning algorithm for creating the input
     *  transformation. */
    protected BatchLearner, ? extends Evaluator> inputLearner;

    /** The unsupervised learning algorithm for creating the output
     *  transformation, which must be reversible for evaluation. */
    protected BatchLearner, ? extends ReversibleEvaluator> outputLearner;

    /**
     * Creates a new, empty {@code InputOutputTransformedBatchLearner}.
     */
    public InputOutputTransformedBatchLearner()
    {
        this(null, null, null);
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} with the given
     * learners.
     *
     * @param   inputLearner
     *      The unsupervised learning algorithm for creating the input
     *      transformation.
     * @param   learner
     *      The supervised learner whose input and output are being
     *      adapted.
     * @param   outputLearner
     *      The unsupervised learning algorithm for creating the
     *      output transformation, which must be reversible for evaluation.
     */
    public InputOutputTransformedBatchLearner(
        final BatchLearner, ? extends Evaluator> inputLearner,
        final BatchLearner>, ? extends Evaluator> learner,
        final BatchLearner, ? extends ReversibleEvaluator> outputLearner)
    {
        super(learner);

        this.setInputLearner(inputLearner);
        this.setOutputLearner(outputLearner);
    }

    @Override
    public InputOutputTransformedBatchLearner clone()
    {
        @SuppressWarnings("unchecked")
        final InputOutputTransformedBatchLearner clone =
            (InputOutputTransformedBatchLearner)
            super.clone();

        clone.inputLearner = ObjectUtil.cloneSafe(this.inputLearner);
        clone.outputLearner = ObjectUtil.cloneSafe(this.outputLearner);
        
        return clone;
    }

    /**
     * Learn by first calling the input transformation learner on all the
     * input values and the output transformation on the output values. After
     * these are created, the adapted supervised data is constructed by
     * applying the learned input transformation to each input and the learned 
     * output transformation to each output. The third (middle) learner is then
     * trained on the transformed supervised learning problem.
     *
     * @param   data
     *      The training data.
     * @return
     *      The composite evaluator triple that applies the input transform,
     *      the learned function, and then the output transform.
     */
    @Override
    public CompositeEvaluatorTriple learn(
        final Collection> data)
    {
        // First learn the input transformer.
        final List originalInputs = DatasetUtil.inputsList(data);
        final Evaluator inputTransformer =
            this.inputLearner.learn(originalInputs);

        // Now learn the output transformer and get its reverse.
        final List originalOutputs = DatasetUtil.outputsList(data);
        final ReversibleEvaluator outputTransformer =
            this.outputLearner.learn(originalOutputs);
        final Evaluator outputReverseTransfomer =
            outputTransformer.reverse();

        // Now transform all the data.
        final ArrayList> transformedData =
            new ArrayList>(data.size());
        for (InputOutputPair originalExample : data)
        {
            final TransformedInputType transformedInput = inputTransformer.evaluate(
                originalExample.getInput());
            final TransformedOutputType transformedOutput = outputTransformer.evaluate(
                originalExample.getOutput());

            // Create the transformed input-output pair.
// TODO: We could put in a factory for input-output pairs to special-case this
// type of transform.
            if (originalExample instanceof WeightedInputOutputPair)
            {
                // Handle weighted examples.
                transformedData.add(DefaultWeightedInputOutputPair.create(
                    transformedInput, transformedOutput,
                    DatasetUtil.getWeight(originalExample)));
            }
            else
            {
                // Unweighted data.
                transformedData.add(DefaultInputOutputPair.create(
                    transformedInput, transformedOutput));
            }
        }

        // Finally, learn the real learner.
        final Evaluator learned =
            this.learner.learn(transformedData);

        return CompositeEvaluatorTriple.create(
            inputTransformer, learned, outputReverseTransfomer);
    }

    /**
     * Gets the unsupervised learning algorithm for creating the input
     * transformation.
     *
     * @return
     *      The input transformation learner.
     */
    public BatchLearner, ? extends Evaluator> getInputLearner()
    {
        return this.inputLearner;
    }

    /**
     * Sets the unsupervised learning algorithm for creating the input
     * transformation.
     *
     * @param   inputLearner
     *      The input transformation learner.
     */
    public void setInputLearner(
        final BatchLearner, ? extends Evaluator> inputLearner)
    {
        this.inputLearner = inputLearner;
    }

    /**
     * Gets the unsupervised learning algorithm for creating the
     * output transformation, which must be reversible for evaluation.
     *
     * @return
     *      The output transformation learner.
     */
    public BatchLearner, ? extends ReversibleEvaluator> getOutputLearner()
    {
        return this.outputLearner;
    }

    /**
     * Gets the unsupervised learning algorithm for creating the
     * output transformation, which must be reversible for evaluation.
     *
     * @param   outputLearner
     *      The output transformation learner.
     */
    public void setOutputLearner(
        final BatchLearner, ? extends ReversibleEvaluator> outputLearner)
    {
        this.outputLearner = outputLearner;
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the
     * three learners.
     *
     * @param   
     *      The input type of the data to learn on. This is passed into the
     *      unsupervised learner for the input transform to create the evaluator
     *      that will then produce the {@code TransformedInputType}.
     * @param   
     *      The output type of the input transformer, which will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The input type of the output transformer, which will be used as the
     *      output values to train the (middle) supervised learner. It will be
     *      the output type of the output transformer.
     * @param   
     *      The output type of the data to learn on. This is passed into the
     *      unsupervised learner for the output transform to create the reversible
     *      data converter for mapping the {@code OutputType} to the
     *      {@code TransformedOutputType} to the, or vice-versa.
     * @param   inputLearner
     *      The unsupervised learning algorithm for creating the input
     *      transformation.
     * @param   learner
     *      The supervised learner whose input and output are being
     *      adapted.
     * @param   outputLearner
     *      The unsupervised learning algorithm for creating the output
     *      transformation, which must be reversible for evaluation.
     * @return
     *      A new input-output transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner create(
        final BatchLearner, ? extends Evaluator> inputLearner,
        final BatchLearner>, ? extends Evaluator> learner,
        final BatchLearner, ? extends ReversibleEvaluator> outputLearner)
    {
        return new InputOutputTransformedBatchLearner(
            inputLearner, learner, outputLearner);
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the
     * input and supervised learners, performing no transformation on the
     * output type.
     *
     * @param   
     *      The input type of the data to learn on. This is passed into the
     *      unsupervised learner for the input transform to create the evaluator
     *      that will then produce the {@code TransformedInputType}.
     * @param   
     *      The output type of the input transformer, which will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The output type of the data to learn on. It will be used as the
     *      output values to train the (middle) supervised learner.
     * @param   inputLearner
     *      The unsupervised learning algorithm for creating the input
     *      transformation.
     * @param   learner
     *      The supervised learner whose input is being adapted.
     * @return
     *      A new input transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner createInputTransformed(
        final BatchLearner, ? extends Evaluator> inputLearner,
        final BatchLearner>, ? extends Evaluator> learner)
    {
        return create(inputLearner, learner,
            new IdentityEvaluator());
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the
     * supervised and output learners, performing no transformation on the
     * input type.
     *
     * @param   
     *      The input type of the data to learn on. It will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The input type of the output transformer, which will be used as the
     *      output values to train the (middle) supervised learner. It will be
     *      the output type of of the output transformer.
     * @param   
     *      The output type of the data to learn on. This is passed into the
     *      unsupervised learner for the output transform to create the reversible
     *      data converter for mapping the {@code OutputType} to the
     *      {@code TransformedOutputType} to the, or vice-versa.
     * @param   learner
     *      The supervised learner whose output is being adapted.
     * @param   outputLearner
     *      The unsupervised learning algorithm for creating the output
     *      transformation, which must be reversible for evaluation.
     * @return
     *      A new output transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner createOutputTransformed(
        final BatchLearner>, ? extends Evaluator> learner,
        final BatchLearner, ? extends ReversibleEvaluator> outputLearner)
    {
        return create(new IdentityEvaluator(),
            learner, outputLearner);
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the
     * predefined input and output transforms and the supervised learner.
     *
     * @param   
     *      The input type of the data to learn on. This is passed into the
     *      input transform to produce the {@code TransformedInputType}.
     * @param   
     *      The output type of the input transformer, which will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The input type of the output transformer, which will be used as the
     *      output values to train the (middle) supervised learner. It will be
     *      the output type of the output transformer.
     * @param   
     *      The output type of the data to learn on. This is passed into the
     *      reversible output data converter for mapping the {@code OutputType} 
     *      to the {@code TransformedOutputType} to the, or vice-versa.
     * @param   inputTransform
     *      The predefined input transformation.
     * @param   learner
     *      The supervised learner whose input and output are being
     *      adapted.
     * @param   outputTransform
     *      The predefined output transformation.
     * @return
     *      A new input-output transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner create(
        final Evaluator inputTransform,
        final BatchLearner>, ? extends Evaluator> learner,
        final ReversibleEvaluator outputTransform)
    {
        return create(
            ConstantLearner.create(inputTransform), learner,
            ConstantLearner.create(outputTransform));
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the
     * predefined input transform and the supervised learner. It uses no
     * output transformation.
     *
     * @param   
     *      The input type of the data to learn on. This is passed into the
     *      input transform to produce the {@code TransformedInputType}.
     * @param   
     *      The output type of the input transformer, which will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The output type of the data to learn on. It will be used as the
     *      output values to train the (middle) supervised learner.
     * @param   inputTransform
     *      The predefined input transformation.
     * @param   learner
     *      The supervised learner whose input and output are being
     *      adapted.
     * @return
     *      A new input transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner createInputTransformed(
        final Evaluator inputTransform,
        final BatchLearner>, ? extends Evaluator> learner)
    {
        return create(inputTransform, learner,
            new IdentityEvaluator());
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the
     * predefined output transforms and the supervised learner. It uses no
     * input transformation.
     *
     * @param   
     *      The input type of the data to learn on. It will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The input type of the output transformer, which will be used as the
     *      output values to train the (middle) supervised learner. It will be
     *      the output type of of the output transformer.
     * @param   
     *      The output type of the data to learn on. This is passed into the
     *      reversible output data converter for mapping the {@code OutputType}
     *      to the {@code TransformedOutputType} to the, or vice-versa.
     * @param   learner
     *      The supervised learner whose input and output are being
     *      adapted.
     * @param   outputTransform
     *      The predefined output transformation.
     * @return
     *      A new output transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner createOutputTransformed(
        final BatchLearner>, ? extends Evaluator> learner,
        final ReversibleEvaluator outputTransform)
    {
        return create(new IdentityEvaluator(),
            learner, outputTransform);
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the 
     * unsupervised input transform learner, supervised learners, and output
     * transform.
     *
     * @param   
     *      The input type of the data to learn on. This is passed into the
     *      unsupervised learner for the input transform to create the evaluator
     *      that will then produce the {@code TransformedInputType}.
     * @param   
     *      The output type of the input transformer, which will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The input type of the output transformer, which will be used as the
     *      output values to train the (middle) supervised learner. It will be
     *      the output type of the output transformer.
     * @param   
     *      The output type of the data to learn on. This is passed into the
     *      reversible output data converter for mapping the {@code OutputType}
     *      to the {@code TransformedOutputType} to the, or vice-versa.
     * @param   inputLearner
     *      The unsupervised learning algorithm for creating the input
     *      transformation.
     * @param   learner
     *      The supervised learner whose input and output are being
     *      adapted.
     * @param   outputTransform
     *      The predefined output transformation.
     * @return
     *      A new input-output transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner create(
        final BatchLearner, ? extends Evaluator> inputLearner,
        final BatchLearner>, ? extends Evaluator> learner,
        final ReversibleEvaluator outputTransform)
    {
        return create(inputLearner, learner,
            ConstantLearner.create(outputTransform));
    }

    /**
     * Creates a new {@code InputOutputTransformedBatchLearner} from the
     * input transform, supervised learner, and unsupervised output transform
     * learner.
     *
     * @param   
     *      The input type of the data to learn on. This is passed into the
     *      input transform to produce the {@code TransformedInputType}.
     * @param   
     *      The output type of the input transformer, which will be used as the
     *      input values to train the (middle) supervised learner.
     * @param   
     *      The input type of the output transformer, which will be used as the
     *      output values to train the (middle) supervised learner. It will be
     *      the output type of of the output transformer.
     * @param   
     *      The output type of the data to learn on. This is passed into the
     *      unsupervised learner for the output transform to create the reversible
     *      data converter for mapping the {@code OutputType} to the
     *      {@code TransformedOutputType} to the, or vice-versa.
     * @param   inputTransform
     *      The predefined input transformation.
     * @param   learner
     *      The supervised learner whose input and output are being
     *      adapted.
     * @param   outputLearner
     *      The unsupervised learning algorithm for creating the output
     *      transformation, which must be reversible for evaluation.
     * @return
     *      A new input-output transformed batch learner.
     */
    public static  InputOutputTransformedBatchLearner create(
        final Evaluator inputTransform,
        final BatchLearner>, ? extends Evaluator> learner,
        final BatchLearner, ? extends ReversibleEvaluator> outputLearner)
    {
        return create(ConstantLearner.create(inputTransform),
            learner, outputLearner);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy