001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.ml.linear.learner;
031
032import java.io.IOException;
033import java.io.PrintWriter;
034import java.io.StringWriter;
035import java.util.HashSet;
036import java.util.Random;
037import java.util.Set;
038
039import org.openimaj.io.WriteableASCII;
040import org.openimaj.ml.linear.learner.init.CurrentUMean;
041import org.openimaj.ml.linear.learner.init.CurrentWMean;
042import org.openimaj.ml.linear.learner.init.SparseRandomInitStrategy;
043import org.openimaj.ml.linear.learner.init.SparseZerosInitStrategy;
044import org.openimaj.ml.linear.learner.loss.SquareMissingLossFunction;
045import org.openimaj.ml.linear.learner.regul.L1L2Regulariser;
046
047import ch.akuhn.matrix.SparseMatrix;
048
049/**
050 * Parameters used to control a {@link BilinearSparseOnlineLearner}
051 *
052 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
053 *
054 */
055public class BilinearLearnerParameters extends LearningParameters implements WriteableASCII {
056
057        /**
058         * whether a bias component is added to w and u. Default is false.
059         */
060        public static final String BIAS = "bias";
061        /**
062         * The random seed of any randomised components of this learner (usually
063         * initialisation). Defaults to -1 (i.e. no seed)
064         */
065        public static final String SEED = "seed";
066        /**
067         * The initialisation strategy for W. Defaults to a
068         * {@link SparseRandomInitStrategy} with sparsity set to 0.5
069         */
070        public static final String WINITSTRAT = "winitstrat";
071        /**
072         * The initialisation strategy for U. Defaults to a
073         * {@link SparseRandomInitStrategy} with sparsity set to 0.5
074         */
075        public static final String UINITSTRAT = "uinitstrat";
076        /**
077         * The initialisation strategy for W when it is expanded. Defaults to the
078         * context aware {@link CurrentWMean}
079         */
080        public static final String EXPANDEDWINITSTRAT = "expandedwinitstrat";
081        /**
082         * The initialisation strategy for U when it is expanded. Defaults to the
083         * context aware {@link CurrentUMean}
084         */
085        public static final String EXPANDEDUINITSTRAT = "expandeduinitstrat";
086        /**
087         * The initialisation strategy for BIAS. Defaults to a
088         * {@link SparseZerosInitStrategy}
089         */
090        public static final String BIASINITSTRAT = "biasinitstrat";
091        /**
092         * The maximum number of iterations in the biconvex iterative stage.
093         * defaults to 3
094         */
095        public static final String BICONVEX_MAXITER = "biconvex_maxiter";
096        /**
097         * The threshold of the ratio between the (sum(new_w - old_w) + sum(new_u -
098         * old_u)) / (sum(old_u) + sum(old_w)) i.e. some notion of normalised
099         * changed of the paramters. Defaults to 0.01
100         */
101        public static final String BICONVEX_TOL = "biconvex_tol";
102        /**
103         * The parameter of the regulariser for W, defaults to LAMBDA
104         */
105        public static final String LAMBDA_W = "lambda_w";
106        /**
107         * The parameter of the regulariser for U, defaults to LAMBDA
108         */
109        public static final String LAMBDA_U = "lambda_u";
110        /**
111         * The parameter of the regulariser for both W and U
112         */
113        public static final String LAMBDA = "lambda";
114        /**
115         * The weighting of the subgradient of U, weighted down each ETASTEPS number
116         * of iterations of the biconvex scheme, defaults to 0.05
117         */
118        public static final String ETA0_U = "eta0u";
119        /**
120         * The weighting of the subgradient of W, weighted down each ETASTEPS number
121         * of iterations of the biconvex scheme, defaults to 0.05
122         */
123        public static final String ETA0_W = "eta0w";
124        /**
125         * The weighting of the subgradient of BIAS, weighted down each ETASTEPS
126         * number of iterations of the biconvex scheme, defaults to eta0 (0.05)
127         */
128        public static final String ETA0_BIAS = "biaseta0";
129        /**
130         * The loss function, defaults to {@link SquareMissingLossFunction}
131         */
132        public static final String LOSS = "loss";
133        /**
134         * The regularisation function, defaults to {@link L1L2Regulariser}
135         */
136        public static final String REGUL = "regul";
137
138        /**
139         * The steps at which point the eta parameter is reduced, defaults to 3
140         */
141        public static final String ETASTEPS = "etasteps";
142        /**
143         * Should all parameter matricies be held {@link SparseMatrix} instances and
144         * therefore remain sparse. Forces a copy but could save a lot.
145         */
146        public static final String FORCE_SPARCITY = "forcesparcity";
147        /**
148         * The value of w, u and beta are updated each time data is added s.t. w = w
149         * * (1.0 - DAM PENING). The default value is 0
150         */
151        public static final String DAMPENING = "dampening";
152
153        /**
154         * Whether the Vprime and Dprime matrices should be zscore standardised
155         */
156        public static final String Z_STANDARDISE = "z_standardise";
157        /**
158         *
159         */
160        private static final long serialVersionUID = -2059819246888686435L;
161
162        /**
163         * The ammount by which ETA is made to increase each iteration
164         */
165        public static final String ETA_GAMMA = "gamma";
166
167        /**
168         * sets up the defaults
169         */
170        public BilinearLearnerParameters() {
171                this.defaults.put(REGUL, new L1L2Regulariser());
172                this.defaults.put(LOSS, new SquareMissingLossFunction());
173                this.defaults.put(ETA0_U, 0.05);
174                this.defaults.put(ETA0_W, 0.05);
175                this.defaults.put(LAMBDA, 0.001);
176                this.defaults.put(LAMBDA_W, new Placeholder(LAMBDA));
177                this.defaults.put(LAMBDA_U, new Placeholder(LAMBDA));
178                this.defaults.put(BICONVEX_TOL, 0.01);
179                this.defaults.put(BICONVEX_MAXITER, 3);
180                this.defaults.put(SEED, -1);
181                this.defaults.put(WINITSTRAT, new SparseRandomInitStrategy(0, 1, 0.5, new Random()));
182                this.defaults.put(UINITSTRAT, new SparseRandomInitStrategy(0, 1, 0.5, new Random()));
183                this.defaults.put(EXPANDEDWINITSTRAT, new CurrentWMean());
184                this.defaults.put(EXPANDEDUINITSTRAT, new CurrentUMean());
185                this.defaults.put(BIAS, false);
186                this.defaults.put(BIASINITSTRAT, new SparseZerosInitStrategy());
187                this.defaults.put(ETA0_BIAS, 0.05);
188                this.defaults.put(ETASTEPS, 3);
189                this.defaults.put(FORCE_SPARCITY, true);
190                this.defaults.put(DAMPENING, 0d);
191                this.defaults.put(Z_STANDARDISE, false);
192                this.defaults.put(ETA_GAMMA, 1.5);
193        }
194
195        @Override
196        public void writeASCII(PrintWriter out) throws IOException {
197                final Set<String> a = new HashSet<String>(this.keySet());
198                a.addAll(this.defaults.keySet());
199                for (final String key : a) {
200                        out.printf("%s: %s\n", key, this.getTyped(key));
201                }
202        }
203
204        @Override
205        public String toString() {
206                final StringWriter writer = new StringWriter();
207                final PrintWriter pw = new PrintWriter(writer, true);
208                try {
209                        writeASCII(pw);
210                } catch (final IOException e) {
211                }
212                pw.flush();
213                return writer.toString();
214        }
215
216        @Override
217        public String asciiHeader() {
218                return "Bilinear Learner Params";
219        }
220
221        @Override
222        public BilinearLearnerParameters clone() {
223                final BilinearLearnerParameters ret = new BilinearLearnerParameters();
224                for (final java.util.Map.Entry<String, Object> ent : this.entrySet()) {
225                        ret.put(ent.getKey(), ent.getValue());
226                }
227                return ret;
228        }
229
230}