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 gov.sandia.cognition.math.matrix.mtj.SparseMatrix;
033
034import java.io.IOException;
035import java.io.PrintWriter;
036import java.io.StringWriter;
037import java.util.HashSet;
038import java.util.Random;
039import java.util.Set;
040
041import org.openimaj.io.WriteableASCII;
042import org.openimaj.ml.linear.learner.init.CurrentUMean;
043import org.openimaj.ml.linear.learner.init.CurrentWMean;
044import org.openimaj.ml.linear.learner.init.SparseRandomInitStrategy;
045import org.openimaj.ml.linear.learner.init.SparseZerosInitStrategy;
046import org.openimaj.ml.linear.learner.loss.SquareMissingLossFunction;
047import org.openimaj.ml.linear.learner.regul.L1L2Regulariser;
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
150         * PENING). The default value is 0
151         */
152        public static final String DAMPENING = "dampening";
153        
154        
155        /**
156         * Whether the Vprime and Dprime matrices should be zscore standardised
157         */
158        public static final String Z_STANDARDISE ="z_standardise";
159        /**
160         *
161         */
162        private static final long serialVersionUID = -2059819246888686435L;
163        
164        
165        /**
166         * The ammount by which ETA is made to increase each iteration 
167         */
168        public static final String ETA_GAMMA = "gamma";
169
170        /**
171         * sets up the defaults
172         */
173        public BilinearLearnerParameters() {
174                this.defaults.put(REGUL, new L1L2Regulariser());
175                this.defaults.put(LOSS, new SquareMissingLossFunction());
176                this.defaults.put(ETA0_U, 0.05);
177                this.defaults.put(ETA0_W, 0.05);
178                this.defaults.put(LAMBDA, 0.001);
179                this.defaults.put(LAMBDA_W, new Placeholder(LAMBDA));
180                this.defaults.put(LAMBDA_U, new Placeholder(LAMBDA));
181                this.defaults.put(BICONVEX_TOL, 0.01);
182                this.defaults.put(BICONVEX_MAXITER, 3);
183                this.defaults.put(SEED, -1);
184                this.defaults.put(WINITSTRAT, new SparseRandomInitStrategy(0, 1, 0.5, new Random()));
185                this.defaults.put(UINITSTRAT, new SparseRandomInitStrategy(0, 1, 0.5, new Random()));
186                this.defaults.put(EXPANDEDWINITSTRAT, new CurrentWMean());
187                this.defaults.put(EXPANDEDUINITSTRAT, new CurrentUMean());
188                this.defaults.put(BIAS, false);
189                this.defaults.put(BIASINITSTRAT, new SparseZerosInitStrategy());
190                this.defaults.put(ETA0_BIAS, 0.05);
191                this.defaults.put(ETASTEPS, 3);
192                this.defaults.put(FORCE_SPARCITY, true);
193                this.defaults.put(DAMPENING, 0d);
194                this.defaults.put(Z_STANDARDISE, false);
195                this.defaults.put(ETA_GAMMA,1.5);
196        }
197
198        @Override
199        public void writeASCII(PrintWriter out) throws IOException {
200                final Set<String> a = new HashSet<String>(this.keySet());
201                a.addAll(this.defaults.keySet());
202                for (final String key : a) {
203                        out.printf("%s: %s\n", key, this.getTyped(key));
204                }
205        }
206        
207        @Override
208        public String toString() {
209                StringWriter writer = new StringWriter();
210                PrintWriter pw = new PrintWriter(writer, true);
211                try {
212                        writeASCII(pw);
213                } catch (IOException e) {
214                }
215                pw.flush();
216                return writer.toString();
217        }
218
219        @Override
220        public String asciiHeader() {
221                return "Bilinear Learner Params";
222        }
223        
224        @Override
225        public BilinearLearnerParameters clone() {
226                BilinearLearnerParameters ret = new BilinearLearnerParameters();
227                for (java.util.Map.Entry<String, Object> ent : this.entrySet()) {
228                        ret.put(ent.getKey(), ent.getValue());
229                }
230                return ret;
231        }
232
233}