001/*
002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.tribuo.classification.sgd.kernel;
018
019import com.oracle.labs.mlrg.olcut.config.ArgumentException;
020import com.oracle.labs.mlrg.olcut.config.Option;
021import org.tribuo.Trainer;
022import org.tribuo.classification.ClassificationOptions;
023import org.tribuo.math.kernel.Kernel;
024import org.tribuo.math.kernel.Linear;
025import org.tribuo.math.kernel.Polynomial;
026import org.tribuo.math.kernel.RBF;
027import org.tribuo.math.kernel.Sigmoid;
028
029import java.util.logging.Logger;
030
031/**
032 * Options for using the KernelSVMTrainer.
033 * <p>
034 * See:
035 * <pre>
036 * Shalev-Shwartz S, Singer Y, Srebro N, Cotter A
037 * "Pegasos: Primal Estimated Sub-Gradient Solver for SVM"
038 * Mathematical Programming, 2011.
039 * </pre>
040 */
041public class KernelSVMOptions implements ClassificationOptions<KernelSVMTrainer> {
042    private static final Logger logger = Logger.getLogger(KernelSVMOptions.class.getName());
043
044    /**
045     * The kernel types.
046     */
047    public enum KernelEnum {
048        /**
049         * Uses a {@link Linear} kernel.
050         */
051        LINEAR,
052        /**
053         * Uses a {@link Polynomial} kernel.
054         */
055        POLYNOMIAL,
056        /**
057         * Uses a {@link Sigmoid} kernel.
058         */
059        SIGMOID,
060        /**
061         * Uses an {@link RBF} kernel.
062         */
063        RBF
064    }
065
066    /**
067     * Intercept in kernel function. Defaults to 1.0.
068     */
069    @Option(longName = "kernel-intercept", usage = "Intercept in kernel function. Defaults to 1.0.")
070    public double kernelIntercept = 1.0;
071    /**
072     * Degree in polynomial kernel function. Defaults to 1.0.
073     */
074    @Option(longName = "kernel-degree", usage = "Degree in polynomial kernel function. Defaults to 1.0.")
075    public double kernelDegree = 1.0;
076    /**
077     * Gamma value in kernel function. Defaults to 1.0.
078     */
079    @Option(longName = "kernel-gamma", usage = "Gamma value in kernel function. Defaults to 1.0.")
080    public double kernelGamma = 1.0;
081    /**
082     * Number of SGD epochs. Defaults to 5.
083     */
084    @Option(longName = "kernel-epochs", usage = "Number of SGD epochs. Defaults to 5.")
085    public int kernelEpochs = 5;
086    /**
087     * Kernel function. Defaults to LINEAR.
088     */
089    @Option(longName = "kernel-kernel", usage = "Kernel function. Defaults to LINEAR.")
090    public KernelEnum kernelKernel = KernelEnum.LINEAR; //TODO should the default be KernelEnum.RBF?
091    /**
092     * Lambda value in gradient optimisation. Defaults to 0.01.
093     */
094    @Option(longName = "kernel-lambda", usage = "Lambda value in gradient optimisation. Defaults to 0.01.")
095    public double kernelLambda = 0.01;
096    /**
097     * Log the objective after n examples. Defaults to 100.
098     */
099    @Option(longName = "kernel-logging-interval", usage = "Log the objective after <int> examples. Defaults to 100.")
100    public int kernelLoggingInterval = 100;
101    /**
102     * Sets the random seed for the Kernel SVM.
103     */
104    @Option(longName = "kernel-seed", usage = "Sets the random seed for the Kernel SVM.")
105    public long kernelSeed = Trainer.DEFAULT_SEED;
106
107    @Override
108    public KernelSVMTrainer getTrainer() {
109        logger.info("Configuring Kernel SVM Trainer");
110        Kernel kernelObj = null;
111        switch (kernelKernel) {
112            case LINEAR:
113                logger.info("Using a linear kernel");
114                kernelObj = new Linear();
115                break;
116            case POLYNOMIAL:
117                logger.info("Using a Polynomial kernel with gamma " + kernelGamma + ", intercept " + kernelIntercept + ", and degree " + kernelDegree);
118                kernelObj = new Polynomial(kernelGamma, kernelIntercept, kernelDegree);
119                break;
120            case RBF:
121                logger.info("Using an RBF kernel with gamma " + kernelGamma);
122                kernelObj = new RBF(kernelGamma);
123                break;
124            case SIGMOID:
125                logger.info("Using a tanh kernel with gamma " + kernelGamma + ", and intercept " + kernelIntercept);
126                kernelObj = new Sigmoid(kernelGamma, kernelIntercept);
127                break;
128            default:
129                logger.warning("Unknown kernel function " + kernelKernel);
130                throw new ArgumentException("kernel-kernel", "Unknown kernel function " + kernelKernel);
131        }
132        logger.info(String.format("Set logging interval to %d", kernelLoggingInterval));
133        return new KernelSVMTrainer(kernelObj, kernelLambda, kernelEpochs, kernelLoggingInterval, kernelSeed);
134    }
135}