Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2883_GBTModelStorage/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs @ 15675

Last change on this file since 15675 was 15675, checked in by fholzing, 6 years ago

#2883: Changed from Boolean to Enum

File size: 14.4 KB
RevLine 
[12332]1#region License Information
2/* HeuristicLab
[15583]3 * Copyright (C) 2002-2018 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
23using System.Linq;
24using System.Threading;
[15675]25using HeuristicLab.Algorithms.DataAnalysis.GradientBoostedTrees;
[12332]26using HeuristicLab.Analysis;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33using HeuristicLab.PluginInfrastructure;
34using HeuristicLab.Problems.DataAnalysis;
35
36namespace HeuristicLab.Algorithms.DataAnalysis {
[13646]37  [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.")]
[12332]38  [StorableClass]
[12590]39  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 125)]
[14523]40  public class GradientBoostedTreesAlgorithm : FixedDataAnalysisAlgorithm<IRegressionProblem> {
[12332]41    #region ParameterNames
42    private const string IterationsParameterName = "Iterations";
[12632]43    private const string MaxSizeParameterName = "Maximum Tree Size";
[12332]44    private const string NuParameterName = "Nu";
45    private const string RParameterName = "R";
46    private const string MParameterName = "M";
47    private const string SeedParameterName = "Seed";
48    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
49    private const string LossFunctionParameterName = "LossFunction";
50    private const string UpdateIntervalParameterName = "UpdateInterval";
[12373]51    private const string CreateSolutionParameterName = "CreateSolution";
[12332]52    #endregion
53
54    #region ParameterProperties
[15675]55    public IFixedValueParameter<IntValue> IterationsParameter
56    {
[12332]57      get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
58    }
[15675]59    public IFixedValueParameter<IntValue> MaxSizeParameter
60    {
[12632]61      get { return (IFixedValueParameter<IntValue>)Parameters[MaxSizeParameterName]; }
[12332]62    }
[15675]63    public IFixedValueParameter<DoubleValue> NuParameter
64    {
[12332]65      get { return (IFixedValueParameter<DoubleValue>)Parameters[NuParameterName]; }
66    }
[15675]67    public IFixedValueParameter<DoubleValue> RParameter
68    {
[12332]69      get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
70    }
[15675]71    public IFixedValueParameter<DoubleValue> MParameter
72    {
[12332]73      get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
74    }
[15675]75    public IFixedValueParameter<IntValue> SeedParameter
76    {
[12332]77      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
78    }
[15675]79    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter
80    {
[12332]81      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
82    }
[15675]83    public IConstrainedValueParameter<ILossFunction> LossFunctionParameter
84    {
[12873]85      get { return (IConstrainedValueParameter<ILossFunction>)Parameters[LossFunctionParameterName]; }
[12332]86    }
[15675]87    public IFixedValueParameter<IntValue> UpdateIntervalParameter
88    {
[12332]89      get { return (IFixedValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
90    }
[15675]91    private IFixedValueParameter<EnumValue<ModelStorage>> CreateSolutionParameter
92    {
93      get { return (IFixedValueParameter<EnumValue<ModelStorage>>)Parameters[CreateSolutionParameterName]; }
[12373]94    }
[12332]95    #endregion
96
97    #region Properties
[15675]98    public int Iterations
99    {
[12332]100      get { return IterationsParameter.Value.Value; }
101      set { IterationsParameter.Value.Value = value; }
102    }
[15675]103    public int Seed
104    {
[12332]105      get { return SeedParameter.Value.Value; }
106      set { SeedParameter.Value.Value = value; }
107    }
[15675]108    public bool SetSeedRandomly
109    {
[12332]110      get { return SetSeedRandomlyParameter.Value.Value; }
111      set { SetSeedRandomlyParameter.Value.Value = value; }
112    }
[15675]113    public int MaxSize
114    {
[12632]115      get { return MaxSizeParameter.Value.Value; }
116      set { MaxSizeParameter.Value.Value = value; }
[12332]117    }
[15675]118    public double Nu
119    {
[12332]120      get { return NuParameter.Value.Value; }
121      set { NuParameter.Value.Value = value; }
122    }
[15675]123    public double R
124    {
[12332]125      get { return RParameter.Value.Value; }
126      set { RParameter.Value.Value = value; }
127    }
[15675]128    public double M
129    {
[12332]130      get { return MParameter.Value.Value; }
131      set { MParameter.Value.Value = value; }
132    }
[15675]133    public ModelStorage CreateSolution
134    {
[12373]135      get { return CreateSolutionParameter.Value.Value; }
136      set { CreateSolutionParameter.Value.Value = value; }
137    }
[12332]138    #endregion
139
140    #region ResultsProperties
[15675]141    private double ResultsBestQuality
142    {
[12332]143      get { return ((DoubleValue)Results["Best Quality"].Value).Value; }
144      set { ((DoubleValue)Results["Best Quality"].Value).Value = value; }
145    }
[15675]146    private DataTable ResultsQualities
147    {
[12332]148      get { return ((DataTable)Results["Qualities"].Value); }
149    }
150    #endregion
151
152    [StorableConstructor]
153    protected GradientBoostedTreesAlgorithm(bool deserializing) : base(deserializing) { }
154
155    protected GradientBoostedTreesAlgorithm(GradientBoostedTreesAlgorithm original, Cloner cloner)
156      : base(original, cloner) {
157    }
158
159    public override IDeepCloneable Clone(Cloner cloner) {
160      return new GradientBoostedTreesAlgorithm(this, cloner);
161    }
162
163    public GradientBoostedTreesAlgorithm() {
164      Problem = new RegressionProblem(); // default problem
165
166      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)));
167      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
168      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
[12632]169      Parameters.Add(new FixedValueParameter<IntValue>(MaxSizeParameterName, "Maximal size of the tree learned in each step (prefer smaller sizes if possible)", new IntValue(10)));
[12332]170      Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName, "Ratio of training rows selected randomly in each step (0 < R <= 1)", new DoubleValue(0.5)));
171      Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "Ratio of variables selected randomly in each step (0 < M <= 1)", new DoubleValue(0.5)));
172      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]173      Parameters.Add(new FixedValueParameter<IntValue>(UpdateIntervalParameterName, "", new IntValue(100)));
174      Parameters[UpdateIntervalParameterName].Hidden = true;
[15675]175      Parameters.Add(new FixedValueParameter<EnumValue<ModelStorage>>(CreateSolutionParameterName, "Flag that indicates what kind of solution should be produced at the end of the run", new EnumValue<ModelStorage>(ModelStorage.Parameter)));
[12373]176      Parameters[CreateSolutionParameterName].Hidden = true;
[12332]177
[12873]178      var lossFunctions = ApplicationManager.Manager.GetInstances<ILossFunction>();
179      Parameters.Add(new ConstrainedValueParameter<ILossFunction>(LossFunctionParameterName, "The loss function", new ItemSet<ILossFunction>(lossFunctions)));
180      LossFunctionParameter.Value = LossFunctionParameter.ValidValues.First(f => f.ToString().Contains("Squared")); // squared error loss is the default
[12332]181    }
182
[12873]183    [StorableHook(HookType.AfterDeserialization)]
184    private void AfterDeserialization() {
185      // BackwardsCompatibility3.4
186      #region Backwards compatible code, remove with 3.5
[15675]187
188      #region LossFunction
[12873]189      // parameter type has been changed
190      var lossFunctionParam = Parameters[LossFunctionParameterName] as ConstrainedValueParameter<StringValue>;
191      if (lossFunctionParam != null) {
192        Parameters.Remove(LossFunctionParameterName);
193        var selectedValue = lossFunctionParam.Value; // to be restored below
[12332]194
[12873]195        var lossFunctions = ApplicationManager.Manager.GetInstances<ILossFunction>();
196        Parameters.Add(new ConstrainedValueParameter<ILossFunction>(LossFunctionParameterName, "The loss function", new ItemSet<ILossFunction>(lossFunctions)));
197        // try to restore selected value
198        var selectedLossFunction =
199          LossFunctionParameter.ValidValues.FirstOrDefault(f => f.ToString() == selectedValue.Value);
200        if (selectedLossFunction != null) {
201          LossFunctionParameter.Value = selectedLossFunction;
202        } else {
203          LossFunctionParameter.Value = LossFunctionParameter.ValidValues.First(f => f.ToString().Contains("Squared")); // default: SE
204        }
205      }
206      #endregion
[15675]207
208      #region CreateSolution
209      // parameter type has been changed
210      var createSolutionParam = Parameters[CreateSolutionParameterName] as FixedValueParameter<BoolValue>;
211      if (createSolutionParam != null) {
212        Parameters.Remove(CreateSolutionParameterName);
213
214        ModelStorage value = createSolutionParam.Value.Value ? ModelStorage.Parameter : ModelStorage.Quality;
215        Parameters.Add(new FixedValueParameter<EnumValue<ModelStorage>>(CreateSolutionParameterName, "Flag that indicates what kind of solution should be produced at the end of the run", new EnumValue<ModelStorage>(value)));
216        Parameters[CreateSolutionParameterName].Hidden = true;
217      }
218      #endregion
219      #endregion
[12873]220    }
221
[12332]222    protected override void Run(CancellationToken cancellationToken) {
223      // Set up the algorithm
224      if (SetSeedRandomly) Seed = new System.Random().Next();
225
226      // Set up the results display
227      var iterations = new IntValue(0);
228      Results.Add(new Result("Iterations", iterations));
229
230      var table = new DataTable("Qualities");
231      table.Rows.Add(new DataRow("Loss (train)"));
232      table.Rows.Add(new DataRow("Loss (test)"));
[14841]233      table.Rows["Loss (train)"].VisualProperties.StartIndexZero = true;
234      table.Rows["Loss (test)"].VisualProperties.StartIndexZero = true;
235
[12332]236      Results.Add(new Result("Qualities", table));
237      var curLoss = new DoubleValue();
[12373]238      Results.Add(new Result("Loss (train)", curLoss));
[12332]239
240      // init
[12620]241      var problemData = (IRegressionProblemData)Problem.ProblemData.Clone();
[12873]242      var lossFunction = LossFunctionParameter.Value;
[12632]243      var state = GradientBoostedTreesAlgorithmStatic.CreateGbmState(problemData, lossFunction, (uint)Seed, MaxSize, R, M, Nu);
[12332]244
245      var updateInterval = UpdateIntervalParameter.Value.Value;
246      // Loop until iteration limit reached or canceled.
247      for (int i = 0; i < Iterations; i++) {
248        cancellationToken.ThrowIfCancellationRequested();
249
250        GradientBoostedTreesAlgorithmStatic.MakeStep(state);
251
252        // iteration results
253        if (i % updateInterval == 0) {
254          curLoss.Value = state.GetTrainLoss();
255          table.Rows["Loss (train)"].Values.Add(curLoss.Value);
256          table.Rows["Loss (test)"].Values.Add(state.GetTestLoss());
257          iterations.Value = i;
258        }
259      }
260
261      // final results
262      iterations.Value = Iterations;
263      curLoss.Value = state.GetTrainLoss();
264      table.Rows["Loss (train)"].Values.Add(curLoss.Value);
265      table.Rows["Loss (test)"].Values.Add(state.GetTestLoss());
266
267      // produce variable relevance
268      var orderedImpacts = state.GetVariableRelevance().Select(t => new { name = t.Key, impact = t.Value }).ToList();
269
270      var impacts = new DoubleMatrix();
271      var matrix = impacts as IStringConvertibleMatrix;
272      matrix.Rows = orderedImpacts.Count;
273      matrix.RowNames = orderedImpacts.Select(x => x.name);
274      matrix.Columns = 1;
275      matrix.ColumnNames = new string[] { "Relative variable relevance" };
276
277      int rowIdx = 0;
278      foreach (var p in orderedImpacts) {
279        matrix.SetValue(string.Format("{0:N2}", p.impact), rowIdx++, 0);
280      }
281
282      Results.Add(new Result("Variable relevance", impacts));
[12373]283      Results.Add(new Result("Loss (test)", new DoubleValue(state.GetTestLoss())));
[12332]284
285      // produce solution
[15675]286      if (CreateSolution == ModelStorage.Parameter) {
[13065]287        var model = state.GetModel();
[12868]288
[12611]289        // for logistic regression we produce a classification solution
290        if (lossFunction is LogisticRegressionLoss) {
[13065]291          var classificationModel = new DiscriminantFunctionClassificationModel(model,
[12611]292            new AccuracyMaximizationThresholdCalculator());
293          var classificationProblemData = new ClassificationProblemData(problemData.Dataset,
294            problemData.AllowedInputVariables, problemData.TargetVariable, problemData.Transformations);
[14780]295          classificationProblemData.TrainingPartition.Start = Problem.ProblemData.TrainingPartition.Start;
296          classificationProblemData.TrainingPartition.End = Problem.ProblemData.TrainingPartition.End;
297          classificationProblemData.TestPartition.Start = Problem.ProblemData.TestPartition.Start;
298          classificationProblemData.TestPartition.End = Problem.ProblemData.TestPartition.End;
299
[14841]300          classificationModel.SetThresholdsAndClassValues(new double[] { double.NegativeInfinity, 0.0 }, new[] { 0.0, 1.0 });
[12611]301
[14780]302
[13065]303          var classificationSolution = new DiscriminantFunctionClassificationSolution(classificationModel, classificationProblemData);
[12619]304          Results.Add(new Result("Solution", classificationSolution));
[12611]305        } else {
306          // otherwise we produce a regression solution
[14345]307          Results.Add(new Result("Solution", new GradientBoostedTreesSolution(model, problemData)));
[12611]308        }
309      }
[12332]310    }
311  }
312}
Note: See TracBrowser for help on using the repository browser.