Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs @ 17044

Last change on this file since 17044 was 17044, checked in by mkommend, 5 years ago

#2883: Initialized Lazy object in GBTModelSurrogate.

File size: 14.9 KB
RevLine 
[12332]1#region License Information
2/* HeuristicLab
[16565]3 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[12332]4 * and the BEACON Center for the Study of Evolution in Action.
5 *
6 * This file is part of HeuristicLab.
7 *
8 * HeuristicLab is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * HeuristicLab is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
20 */
21#endregion
22
[17030]23using System;
[12332]24using System.Linq;
25using System.Threading;
[17030]26using HeuristicLab.Algorithms.DataAnalysis.GradientBoostedTrees;
[12332]27using HeuristicLab.Analysis;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.Optimization;
32using HeuristicLab.Parameters;
[16565]33using HEAL.Attic;
[12332]34using HeuristicLab.PluginInfrastructure;
35using HeuristicLab.Problems.DataAnalysis;
36
37namespace HeuristicLab.Algorithms.DataAnalysis {
[13646]38  [Item("Gradient Boosted Trees (GBT)", "Gradient boosted trees algorithm. Specific implementation of gradient boosting for regression trees. Friedman, J. \"Greedy Function Approximation: A Gradient Boosting Machine\", IMS 1999 Reitz Lecture.")]
[16565]39  [StorableType("8CCB55BD-4935-4868-855F-D3E5D55127AA")]
[12590]40  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 125)]
[14523]41  public class GradientBoostedTreesAlgorithm : FixedDataAnalysisAlgorithm<IRegressionProblem> {
[12332]42    #region ParameterNames
43    private const string IterationsParameterName = "Iterations";
[12632]44    private const string MaxSizeParameterName = "Maximum Tree Size";
[12332]45    private const string NuParameterName = "Nu";
46    private const string RParameterName = "R";
47    private const string MParameterName = "M";
48    private const string SeedParameterName = "Seed";
49    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
50    private const string LossFunctionParameterName = "LossFunction";
51    private const string UpdateIntervalParameterName = "UpdateInterval";
[17030]52    private const string ModelCreationParameterName = "ModelCreation";
[12332]53    #endregion
54
55    #region ParameterProperties
56    public IFixedValueParameter<IntValue> IterationsParameter {
57      get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
58    }
[12632]59    public IFixedValueParameter<IntValue> MaxSizeParameter {
60      get { return (IFixedValueParameter<IntValue>)Parameters[MaxSizeParameterName]; }
[12332]61    }
62    public IFixedValueParameter<DoubleValue> NuParameter {
63      get { return (IFixedValueParameter<DoubleValue>)Parameters[NuParameterName]; }
64    }
65    public IFixedValueParameter<DoubleValue> RParameter {
66      get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
67    }
68    public IFixedValueParameter<DoubleValue> MParameter {
69      get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
70    }
71    public IFixedValueParameter<IntValue> SeedParameter {
72      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
73    }
74    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
75      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
76    }
[12873]77    public IConstrainedValueParameter<ILossFunction> LossFunctionParameter {
78      get { return (IConstrainedValueParameter<ILossFunction>)Parameters[LossFunctionParameterName]; }
[12332]79    }
80    public IFixedValueParameter<IntValue> UpdateIntervalParameter {
81      get { return (IFixedValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
82    }
[17030]83    private IFixedValueParameter<EnumValue<ModelCreation>> ModelCreationParameter {
84      get { return (IFixedValueParameter<EnumValue<ModelCreation>>)Parameters[ModelCreationParameterName]; }
[12373]85    }
[12332]86    #endregion
87
88    #region Properties
89    public int Iterations {
90      get { return IterationsParameter.Value.Value; }
91      set { IterationsParameter.Value.Value = value; }
92    }
93    public int Seed {
94      get { return SeedParameter.Value.Value; }
95      set { SeedParameter.Value.Value = value; }
96    }
97    public bool SetSeedRandomly {
98      get { return SetSeedRandomlyParameter.Value.Value; }
99      set { SetSeedRandomlyParameter.Value.Value = value; }
100    }
[12632]101    public int MaxSize {
102      get { return MaxSizeParameter.Value.Value; }
103      set { MaxSizeParameter.Value.Value = value; }
[12332]104    }
105    public double Nu {
106      get { return NuParameter.Value.Value; }
107      set { NuParameter.Value.Value = value; }
108    }
109    public double R {
110      get { return RParameter.Value.Value; }
111      set { RParameter.Value.Value = value; }
112    }
113    public double M {
114      get { return MParameter.Value.Value; }
115      set { MParameter.Value.Value = value; }
116    }
[17030]117    public ModelCreation ModelCreation {
118      get { return ModelCreationParameter.Value.Value; }
119      set { ModelCreationParameter.Value.Value = value; }
[12373]120    }
[12332]121    #endregion
122
123    #region ResultsProperties
124    private double ResultsBestQuality {
125      get { return ((DoubleValue)Results["Best Quality"].Value).Value; }
126      set { ((DoubleValue)Results["Best Quality"].Value).Value = value; }
127    }
128    private DataTable ResultsQualities {
129      get { return ((DataTable)Results["Qualities"].Value); }
130    }
131    #endregion
132
133    [StorableConstructor]
[16565]134    protected GradientBoostedTreesAlgorithm(StorableConstructorFlag _) : base(_) { }
[12332]135
136    protected GradientBoostedTreesAlgorithm(GradientBoostedTreesAlgorithm original, Cloner cloner)
137      : base(original, cloner) {
138    }
139
140    public override IDeepCloneable Clone(Cloner cloner) {
141      return new GradientBoostedTreesAlgorithm(this, cloner);
142    }
143
144    public GradientBoostedTreesAlgorithm() {
145      Problem = new RegressionProblem(); // default problem
146
147      Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName, "Number of iterations (set as high as possible, adjust in combination with nu, when increasing iterations also decrease nu)", new IntValue(1000)));
148      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
149      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
[17030]150      Parameters.Add(new FixedValueParameter<IntValue>(MaxSizeParameterName, "Maximal size of the tree learned in each step (prefer smaller sizes (3 to 10) if possible)", new IntValue(10)));
[12332]151      Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName, "Ratio of training rows selected randomly in each step (0 < R <= 1)", new DoubleValue(0.5)));
152      Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "Ratio of variables selected randomly in each step (0 < M <= 1)", new DoubleValue(0.5)));
153      Parameters.Add(new FixedValueParameter<DoubleValue>(NuParameterName, "Learning rate nu (step size for the gradient update, should be small 0 < nu < 0.1)", new DoubleValue(0.002)));
[12373]154      Parameters.Add(new FixedValueParameter<IntValue>(UpdateIntervalParameterName, "", new IntValue(100)));
155      Parameters[UpdateIntervalParameterName].Hidden = true;
[17030]156      Parameters.Add(new FixedValueParameter<EnumValue<ModelCreation>>(ModelCreationParameterName, "Defines the results produced at the end of the run (Surrogate => Less disk space, lazy recalculation of model)", new EnumValue<ModelCreation>(ModelCreation.Model)));
157      Parameters[ModelCreationParameterName].Hidden = true;
[12332]158
[12873]159      var lossFunctions = ApplicationManager.Manager.GetInstances<ILossFunction>();
160      Parameters.Add(new ConstrainedValueParameter<ILossFunction>(LossFunctionParameterName, "The loss function", new ItemSet<ILossFunction>(lossFunctions)));
161      LossFunctionParameter.Value = LossFunctionParameter.ValidValues.First(f => f.ToString().Contains("Squared")); // squared error loss is the default
[12332]162    }
163
[12873]164    [StorableHook(HookType.AfterDeserialization)]
165    private void AfterDeserialization() {
166      // BackwardsCompatibility3.4
167      #region Backwards compatible code, remove with 3.5
[17030]168
169      #region LossFunction
[12873]170      // parameter type has been changed
171      var lossFunctionParam = Parameters[LossFunctionParameterName] as ConstrainedValueParameter<StringValue>;
172      if (lossFunctionParam != null) {
173        Parameters.Remove(LossFunctionParameterName);
174        var selectedValue = lossFunctionParam.Value; // to be restored below
[12332]175
[12873]176        var lossFunctions = ApplicationManager.Manager.GetInstances<ILossFunction>();
177        Parameters.Add(new ConstrainedValueParameter<ILossFunction>(LossFunctionParameterName, "The loss function", new ItemSet<ILossFunction>(lossFunctions)));
178        // try to restore selected value
179        var selectedLossFunction =
180          LossFunctionParameter.ValidValues.FirstOrDefault(f => f.ToString() == selectedValue.Value);
181        if (selectedLossFunction != null) {
182          LossFunctionParameter.Value = selectedLossFunction;
183        } else {
184          LossFunctionParameter.Value = LossFunctionParameter.ValidValues.First(f => f.ToString().Contains("Squared")); // default: SE
185        }
186      }
187      #endregion
[17030]188
189      #region CreateSolution
190      // parameter type has been changed
191      if (Parameters.ContainsKey("CreateSolution")) {
192        var createSolutionParam = Parameters["CreateSolution"] as FixedValueParameter<BoolValue>;
193        Parameters.Remove(createSolutionParam);
194
195        ModelCreation value = createSolutionParam.Value.Value ? ModelCreation.Model : ModelCreation.QualityOnly;
196        Parameters.Add(new FixedValueParameter<EnumValue<ModelCreation>>(ModelCreationParameterName, "Defines the results produced at the end of the run (Surrogate => Less disk space, lazy recalculation of model)", new EnumValue<ModelCreation>(value)));
197        Parameters[ModelCreationParameterName].Hidden = true;
198      }
199      #endregion
200      #endregion
[12873]201    }
202
[12332]203    protected override void Run(CancellationToken cancellationToken) {
204      // Set up the algorithm
[16071]205      if (SetSeedRandomly) Seed = Random.RandomSeedGenerator.GetSeed();
[12332]206
207      // Set up the results display
208      var iterations = new IntValue(0);
209      Results.Add(new Result("Iterations", iterations));
210
211      var table = new DataTable("Qualities");
212      table.Rows.Add(new DataRow("Loss (train)"));
213      table.Rows.Add(new DataRow("Loss (test)"));
[14841]214      table.Rows["Loss (train)"].VisualProperties.StartIndexZero = true;
215      table.Rows["Loss (test)"].VisualProperties.StartIndexZero = true;
216
[12332]217      Results.Add(new Result("Qualities", table));
218      var curLoss = new DoubleValue();
[12373]219      Results.Add(new Result("Loss (train)", curLoss));
[12332]220
221      // init
[12620]222      var problemData = (IRegressionProblemData)Problem.ProblemData.Clone();
[12873]223      var lossFunction = LossFunctionParameter.Value;
[12632]224      var state = GradientBoostedTreesAlgorithmStatic.CreateGbmState(problemData, lossFunction, (uint)Seed, MaxSize, R, M, Nu);
[12332]225
226      var updateInterval = UpdateIntervalParameter.Value.Value;
227      // Loop until iteration limit reached or canceled.
228      for (int i = 0; i < Iterations; i++) {
229        cancellationToken.ThrowIfCancellationRequested();
230
231        GradientBoostedTreesAlgorithmStatic.MakeStep(state);
232
233        // iteration results
234        if (i % updateInterval == 0) {
235          curLoss.Value = state.GetTrainLoss();
236          table.Rows["Loss (train)"].Values.Add(curLoss.Value);
237          table.Rows["Loss (test)"].Values.Add(state.GetTestLoss());
238          iterations.Value = i;
239        }
240      }
241
242      // final results
243      iterations.Value = Iterations;
244      curLoss.Value = state.GetTrainLoss();
245      table.Rows["Loss (train)"].Values.Add(curLoss.Value);
246      table.Rows["Loss (test)"].Values.Add(state.GetTestLoss());
247
248      // produce variable relevance
249      var orderedImpacts = state.GetVariableRelevance().Select(t => new { name = t.Key, impact = t.Value }).ToList();
250
251      var impacts = new DoubleMatrix();
252      var matrix = impacts as IStringConvertibleMatrix;
253      matrix.Rows = orderedImpacts.Count;
254      matrix.RowNames = orderedImpacts.Select(x => x.name);
255      matrix.Columns = 1;
256      matrix.ColumnNames = new string[] { "Relative variable relevance" };
257
258      int rowIdx = 0;
259      foreach (var p in orderedImpacts) {
260        matrix.SetValue(string.Format("{0:N2}", p.impact), rowIdx++, 0);
261      }
262
263      Results.Add(new Result("Variable relevance", impacts));
[12373]264      Results.Add(new Result("Loss (test)", new DoubleValue(state.GetTestLoss())));
[12332]265
266      // produce solution
[17030]267      if (ModelCreation == ModelCreation.SurrogateModel || ModelCreation == ModelCreation.Model) {
268        IRegressionModel model = state.GetModel();
[12868]269
[17030]270        if (ModelCreation == ModelCreation.SurrogateModel) {
[17044]271          model = new GradientBoostedTreesModelSurrogate((GradientBoostedTreesModel)model, problemData, (uint)Seed, lossFunction, Iterations, MaxSize, R, M, Nu);
[17030]272        }
273
[12611]274        // for logistic regression we produce a classification solution
275        if (lossFunction is LogisticRegressionLoss) {
[13065]276          var classificationModel = new DiscriminantFunctionClassificationModel(model,
[12611]277            new AccuracyMaximizationThresholdCalculator());
278          var classificationProblemData = new ClassificationProblemData(problemData.Dataset,
279            problemData.AllowedInputVariables, problemData.TargetVariable, problemData.Transformations);
[14780]280          classificationProblemData.TrainingPartition.Start = Problem.ProblemData.TrainingPartition.Start;
281          classificationProblemData.TrainingPartition.End = Problem.ProblemData.TrainingPartition.End;
282          classificationProblemData.TestPartition.Start = Problem.ProblemData.TestPartition.Start;
283          classificationProblemData.TestPartition.End = Problem.ProblemData.TestPartition.End;
284
[14841]285          classificationModel.SetThresholdsAndClassValues(new double[] { double.NegativeInfinity, 0.0 }, new[] { 0.0, 1.0 });
[12611]286
[14780]287
[13065]288          var classificationSolution = new DiscriminantFunctionClassificationSolution(classificationModel, classificationProblemData);
[12619]289          Results.Add(new Result("Solution", classificationSolution));
[12611]290        } else {
291          // otherwise we produce a regression solution
[14345]292          Results.Add(new Result("Solution", new GradientBoostedTreesSolution(model, problemData)));
[12611]293        }
[17030]294      } else if (ModelCreation == ModelCreation.QualityOnly) {
295        //Do nothing
296      } else {
297        throw new NotImplementedException("Selected parameter for CreateSolution isn't implemented yet");
[12611]298      }
[12332]299    }
300  }
301}
Note: See TracBrowser for help on using the repository browser.