Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/TensorFlowConstantOptimizationEvaluator.cs @ 18240

Last change on this file since 18240 was 18240, checked in by pfleck, 2 years ago

#3040 smaller fixes and some code cleanup

File size: 11.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22//#define EXPORT_GRAPH
23//#define LOG_CONSOLE
24//#define LOG_FILE
25
26using System;
27using System.Collections;
28using System.Collections.Generic;
29#if LOG_CONSOLE
30using System.Diagnostics;
31#endif
32#if LOG_FILE
33using System.Globalization;
34using System.IO;
35#endif
36using System.Linq;
37using System.Threading;
38using HeuristicLab.Common;
39using HeuristicLab.Core;
40using HeuristicLab.Data;
41using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
42using HeuristicLab.Parameters;
43using HEAL.Attic;
44using Tensorflow;
45using Tensorflow.NumPy;
46using static Tensorflow.Binding;
47using static Tensorflow.KerasApi;
48using DoubleVector = MathNet.Numerics.LinearAlgebra.Vector<double>;
49
50namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
51  [StorableType("63944BF6-62E5-4BE4-974C-D30AD8770F99")]
52  [Item("TensorFlowConstantOptimizationEvaluator", "")]
53  public class TensorFlowConstantOptimizationEvaluator : SymbolicRegressionConstantOptimizationEvaluator {
54    private const string MaximumIterationsName = "MaximumIterations";
55    private const string LearningRateName = "LearningRate";
56
57    //private static readonly TF_DataType DataType = tf.float64;
58    //private static readonly TF_DataType DataType = tf.float32;
59
60    #region Parameter Properties
61    public IFixedValueParameter<IntValue> ConstantOptimizationIterationsParameter {
62      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumIterationsName]; }
63    }
64    public IFixedValueParameter<DoubleValue> LearningRateParameter {
65      get { return (IFixedValueParameter<DoubleValue>)Parameters[LearningRateName]; }
66    }
67    #endregion
68
69    #region Properties
70    public int ConstantOptimizationIterations {
71      get { return ConstantOptimizationIterationsParameter.Value.Value; }
72    }
73    public double LearningRate {
74      get { return LearningRateParameter.Value.Value; }
75    }
76    #endregion
77
78    public TensorFlowConstantOptimizationEvaluator()
79      : base() {
80      Parameters.Add(new FixedValueParameter<IntValue>(MaximumIterationsName, "Determines how many iterations should be calculated while optimizing the constant of a symbolic expression tree(0 indicates other or default stopping criterion).", new IntValue(10)));
81      Parameters.Add(new FixedValueParameter<DoubleValue>(LearningRateName, "", new DoubleValue(0.001)));
82    }
83
84    protected TensorFlowConstantOptimizationEvaluator(TensorFlowConstantOptimizationEvaluator original, Cloner cloner)
85      : base(original, cloner) { }
86
87    public override IDeepCloneable Clone(Cloner cloner) {
88      return new TensorFlowConstantOptimizationEvaluator(this, cloner);
89    }
90
91    [StorableConstructor]
92    protected TensorFlowConstantOptimizationEvaluator(StorableConstructorFlag _) : base(_) { }
93
94    protected override ISymbolicExpressionTree OptimizeConstants(
95      ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable<int> rows,
96      CancellationToken cancellationToken = default(CancellationToken), EvaluationsCounter counter = null) {
97      return OptimizeTree(tree,
98        problemData, rows,
99        ApplyLinearScalingParameter.ActualValue.Value, UpdateVariableWeights,
100        ConstantOptimizationIterations, LearningRate,
101        cancellationToken);
102    }
103
104    public static ISymbolicExpressionTree OptimizeTree(ISymbolicExpressionTree tree,
105      IRegressionProblemData problemData, IEnumerable<int> rows,
106      bool applyLinearScaling, bool updateVariableWeights, int maxIterations, double learningRate,
107      CancellationToken cancellationToken = default(CancellationToken), IProgress<double> progress = null) {
108
109      const bool eager = true;
110
111#if LOG_FILE
112      var directoryName = $"C:\\temp\\TFboard\\logdir\\TF_{DateTime.Now.ToString("yyyyMMddHHmmss")}_{maxIterations}_{learningRate.ToString(CultureInfo.InvariantCulture)}";
113      Directory.CreateDirectory(directoryName);
114      using var predictionTargetLossWriter = new StreamWriter(File.Create(Path.Combine(directoryName, "PredictionTargetLos.csv")));
115      using var weightsWriter = new StreamWriter(File.Create(Path.Combine(directoryName, "Weights.csv")));
116      using var treeGradsWriter = new StreamWriter(File.Create(Path.Combine(directoryName, "TreeGrads.csv")));
117      using var lossGradsWriter = new StreamWriter(File.Create(Path.Combine(directoryName, "LossGrads.csv")));
118
119      predictionTargetLossWriter.WriteLine(string.Join(";", "Prediction", "Target", "Loss"));
120      weightsWriter.WriteLine(string.Join(";", Enumerable.Range(0, 4).Select(i => $"w_{i}")));
121      treeGradsWriter.WriteLine(string.Join(";", Enumerable.Range(0, 4).Select(i => $"Tg_{i}")));
122      lossGradsWriter.WriteLine(string.Join(";", Enumerable.Range(0, 4).Select(i => $"Lg_{i}")));
123#endif
124
125      //foreach (var row in rows) {
126
127      bool prepared = TreeToTensorConverter.TryPrepareTree(
128        tree,
129        problemData, rows.ToList(),
130        //problemData, new List<int>(){ row },
131        updateVariableWeights, applyLinearScaling,
132        eager,
133        out Dictionary<string, Tensor> inputFeatures, out Tensor target,
134        out Dictionary<ISymbolicExpressionTreeNode, ResourceVariable[]> variables);
135      if (!prepared)
136        return (ISymbolicExpressionTree)tree.Clone();
137
138      var optimizer = keras.optimizers.Adam((float)learningRate);
139
140      for (int i = 0; i < maxIterations; i++) {
141        if (cancellationToken.IsCancellationRequested) break;
142
143#if LOG_FILE || LOG_CONSOLE
144        using var tape = tf.GradientTape(persistent: true);
145#else
146        using var tape = tf.GradientTape(persistent: false);
147#endif
148
149        bool success = TreeToTensorConverter.TryEvaluate(
150          tree,
151          inputFeatures, variables,
152          updateVariableWeights, applyLinearScaling,
153          eager,
154          out Tensor prediction);
155        if (!success)
156          return (ISymbolicExpressionTree)tree.Clone();
157
158        var loss = tf.reduce_mean(tf.square(target - prediction));
159
160        progress?.Report(loss.ToArray<float>()[0]);
161       
162        var variablesList = variables.Values.SelectMany(x => x).ToList();
163        var gradients = tape.gradient(loss, variablesList);
164
165#if LOG_FILE
166        predictionTargetLossWriter.WriteLine(string.Join(";", new[] { prediction.ToArray<float>()[0], target.ToArray<float>()[0], loss.ToArray<float>()[0] }));
167        weightsWriter.WriteLine(string.Join(";", variablesList.Select(v => v.numpy().ToArray<float>()[0])));
168        treeGradsWriter.WriteLine(string.Join(";", tape.gradient(prediction, variablesList).Select(t => t.ToArray<float>()[0])));
169        lossGradsWriter.WriteLine(string.Join(";", tape.gradient(loss, variablesList).Select(t => t.ToArray<float>()[0])));
170#endif
171
172
173        //break;
174
175        optimizer.apply_gradients(zip(gradients, variablesList));
176      }
177      //}
178
179      var cloner = new Cloner();
180      var newTree = cloner.Clone(tree);
181      var newConstants = variables.ToDictionary(
182        kvp => (ISymbolicExpressionTreeNode)cloner.GetClone(kvp.Key),
183        kvp => kvp.Value.Select(x => (double)(x.numpy().ToArray<float>()[0])).ToArray()
184      );
185      UpdateConstants(newTree, newConstants);
186
187
188
189
190      //var numRows = rows.Count();
191     
192      //var variablesFeed = new Hashtable();
193      //foreach (var kvp in inputFeatures) {
194      //  var variableName = kvp.Key;
195      //  var variablePlaceholder = kvp.Value;
196      //  if (problemData.Dataset.VariableHasType<double>(variableName)) {
197      //    var data = problemData.Dataset.GetDoubleValues(variableName, rows).Select(x => (float)x).ToArray();
198      //    variablesFeed.Add(variablePlaceholder, np.array(data).reshape(new Shape(numRows, 1)));
199      //  } else if (problemData.Dataset.VariableHasType<DoubleVector>(variableName)) {
200      //    var data = problemData.Dataset.GetDoubleVectorValues(variableName, rows).SelectMany(x => x.Select(y => (float)y)).ToArray();
201      //    variablesFeed.Add(variablePlaceholder, np.array(data).reshape(new Shape(numRows, -1)));
202      //  } else
203      //    throw new NotSupportedException($"Type of the variable is not supported: {variableName}");
204      //}
205      //var targetData = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows).Select(x => (float)x).ToArray();
206      //variablesFeed.Add(target, np.array(targetData));
207
208      //using var session = tf.Session();
209
210      //var loss2 = tf.constant(1.23f, TF_DataType.TF_FLOAT);
211
212      //var graphOptimizer = tf.train.AdamOptimizer((float)learningRate);
213      //var minimizationOperations = graphOptimizer.minimize(loss2);
214
215      //var init = tf.global_variables_initializer();
216      //session.run(init);
217
218      //session.run((minimizationOperations, loss2), variablesFeed);
219
220     
221     
222
223      return newTree;
224
225     
226//#if EXPORT_GRAPH
227//      //https://github.com/SciSharp/TensorFlow.NET/wiki/Debugging
228//      tf.train.export_meta_graph(@"C:\temp\TFboard\graph.meta", as_text: false,
229//        clear_devices: true, clear_extraneous_savers: false, strip_default_attrs: true);
230//#endif
231
232     
233
234//      //// features as feed items
235//      //var variablesFeed = new Hashtable();
236//      //foreach (var kvp in parameters) {
237//      //  var variable = kvp.Key;
238//      //  var variableName = kvp.Value;
239//      //  if (problemData.Dataset.VariableHasType<double>(variableName)) {
240//      //    var data = problemData.Dataset.GetDoubleValues(variableName, rows).Select(x => (float)x).ToArray();
241//      //    variablesFeed.Add(variable, np.array(data).reshape(new Shape(numRows, 1)));
242//      //  } else if (problemData.Dataset.VariableHasType<DoubleVector>(variableName)) {
243//      //    var data = problemData.Dataset.GetDoubleVectorValues(variableName, rows).SelectMany(x => x.Select(y => (float)y)).ToArray();
244//      //    variablesFeed.Add(variable, np.array(data).reshape(new Shape(numRows, -1)));
245//      //  } else
246//      //    throw new NotSupportedException($"Type of the variable is not supported: {variableName}");
247//      //}
248//      //var targetData = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows).Select(x => (float)x).ToArray();
249//      //variablesFeed.Add(target, np.array(targetData));
250
251    }
252
253    private static void UpdateConstants(ISymbolicExpressionTree tree, Dictionary<ISymbolicExpressionTreeNode, double[]> constants) {
254      foreach (var kvp in constants) {
255        var node = kvp.Key;
256        var value = kvp.Value;
257
258        switch (node) {
259          case ConstantTreeNode constantTreeNode:
260            constantTreeNode.Value = value[0];
261            break;
262          case VariableTreeNodeBase variableTreeNodeBase:
263            variableTreeNodeBase.Weight = value[0];
264            break;
265          case FactorVariableTreeNode factorVarTreeNode: {
266            for (int i = 0; i < factorVarTreeNode.Weights.Length; i++) {
267              factorVarTreeNode.Weights[i] = value[i];
268            }
269            break;
270          }
271        }
272      }
273    }
274
275    public static bool CanOptimizeConstants(ISymbolicExpressionTree tree) {
276      return TreeToTensorConverter.IsCompatible(tree);
277    }
278  }
279}
Note: See TracBrowser for help on using the repository browser.