Changeset 16660


Ignore:
Timestamp:
03/07/19 17:00:39 (3 months ago)
Author:
gkronber
Message:

#2925: re-introduced partial support for latent variables

Location:
branches/2925_AutoDiffForDynamicalModels/HeuristicLab.Problems.DynamicalSystemsModelling/3.3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/2925_AutoDiffForDynamicalModels/HeuristicLab.Problems.DynamicalSystemsModelling/3.3/Problem.cs

    r16653 r16660  
    187187      InitAllParameters();
    188188
    189       // TODO: UI hangs when selecting / deselecting input variables because the encoding is updated on each item
    190189      // TODO: use training range as default training episode
    191       // TODO: write back optimized parameters to solution?
    192190      // TODO: optimization of starting values for latent variables in CVODES solver
    193191      // TODO: allow to specify the name for the time variable in the dataset and allow variable step-sizes
    194       // TODO: check grammars (input variables) after cloning
    195 
    196192    }
    197193
     
    235231      string odeSolver) {
    236232
    237       // extract constants from tree
    238       var constantNodes = trees.Select(t => t.IterateNodesPrefix().OfType<ConstantTreeNode>().ToArray()).ToArray();
     233      // extract constants from trees (without trees for latent variables)
     234      var targetVariableTrees = trees.Take(targetVars.Length).ToArray();
     235      var latentVariableTrees = trees.Skip(targetVars.Length).ToArray();
     236      var constantNodes = targetVariableTrees.Select(t => t.IterateNodesPrefix().OfType<ConstantTreeNode>().ToArray()).ToArray();
    239237      var initialTheta = constantNodes.Select(nodes => nodes.Select(n => n.Value).ToArray()).ToArray();
    240238
     
    242240      double nmse = PreTuneParameters(trees, problemData, targetVars, latentVariables, random, episodes, maxParameterOptIterations,
    243241        initialTheta, out double[] pretunedParameters);
     242
     243      // extend parameter vector to include parameters for latent variable trees
     244      pretunedParameters = pretunedParameters
     245        .Concat(latentVariableTrees
     246        .SelectMany(t => t.IterateNodesPrefix().OfType<ConstantTreeNode>().Select(n => n.Value)))
     247        .ToArray();
    244248
    245249      // optimize parameters using integration of f(x,y) to calculate y(t)
     
    276280      var maxTreeNmse = 100 * episodes.Sum(ep => ep.Size);
    277281
     282      var targetTrees = trees.Take(targetVars.Length).ToArray();
     283      var latentTrees = trees.Take(latentVariables.Length).ToArray();
     284
     285      {
     286        // first calculate values of latent variables by integration
     287        var inputVariables = targetVars.Concat(latentTrees.SelectMany(t => t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName))).Except(latentVariables).Distinct();
     288        var myState = new OptimizationData(latentTrees, targetVars, inputVariables.ToArray(), problemData, null, episodes.ToArray(), 10, latentVariables, "HeuristicLab");
     289
     290        var fi = new double[myState.rows.Length * targetVars.Length];
     291        var jac = new double[myState.rows.Length * targetVars.Length, myState.nodeValueLookup.ParameterCount];
     292        var latentValues = new double[myState.rows.Length, latentVariables.Length];
     293        Integrate(myState, fi, jac, latentValues);
     294
     295        // add integrated latent variables to dataset
     296        var modifiedDataset = ((Dataset)problemData.Dataset).ToModifiable();
     297        foreach (var variable in latentVariables) {
     298          modifiedDataset.AddVariable(variable, Enumerable.Repeat(0.0, modifiedDataset.Rows).ToList()); // empty column
     299        }
     300        int predIdx = 0;
     301        foreach (var ep in episodes) {
     302          for (int r = ep.Start; r < ep.End; r++) {
     303            for (int latVarIdx = 0; latVarIdx < latentVariables.Length; latVarIdx++) {
     304              modifiedDataset.SetVariableValue(latentValues[predIdx, latVarIdx], latentVariables[latVarIdx], r);
     305            }
     306            predIdx++;
     307          }
     308        }
     309
     310        problemData = new RegressionProblemData(modifiedDataset, problemData.AllowedInputVariables, problemData.TargetVariable);
     311      }
    278312      // NOTE: the order of values in parameter matches prefix order of constant nodes in trees
    279       for (int treeIdx = 0; treeIdx < trees.Length; treeIdx++) {
    280         var t = trees[treeIdx];
     313      for (int treeIdx = 0; treeIdx < targetTrees.Length; treeIdx++) {
     314        var t = targetTrees[treeIdx];
    281315
    282316        var targetValuesDiff = new List<double>();
     
    290324        // data for input variables is assumed to be known
    291325        // input variables in pretuning are all target variables and all variable names that occur in the tree
    292         var inputVariables = targetVars.Concat(t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName));
     326        var inputVariables = targetVars.Concat(t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName)).Distinct();
    293327
    294328        var myState = new OptimizationData(new[] { t },
     
    345379      IEnumerable<IntRange> episodes, int maxParameterOptIterations, double[] initialTheta, int numericIntegrationSteps, string odeSolver, out double[] optTheta) {
    346380      var rowsForDataExtraction = episodes.SelectMany(e => Enumerable.Range(e.Start, e.Size)).ToArray();
    347       var targetValues = new double[trees.Length][];
    348       for (int treeIdx = 0; treeIdx < trees.Length; treeIdx++) {
     381      var targetValues = new double[targetVars.Length][];
     382      for (int treeIdx = 0; treeIdx < targetVars.Length; treeIdx++) {
    349383        var t = trees[treeIdx];
    350384
     
    354388      // data for input variables is assumed to be known
    355389      // input variables are all variable names that occur in the trees except for target variables (we assume that trees have been generated correctly)
    356       var inputVariables = trees.SelectMany(t => t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName)).Except(targetVars);
     390      var inputVariables = trees.SelectMany(t => t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName))
     391        .Except(targetVars)
     392        .Except(latentVariables)
     393        .Distinct();
    357394
    358395      var myState = new OptimizationData(trees, targetVars, inputVariables.ToArray(), problemData, targetValues, episodes.ToArray(), numericIntegrationSteps, latentVariables, odeSolver);
     
    495532      nodeValueLookup.UpdateParamValues(x);
    496533
    497       Integrate(optimizationData, fi, jac);
     534      Integrate(optimizationData, fi, jac, null);
    498535      var trees = optimizationData.trees;
    499536
    500537      // update result with error
    501538      for (int trainIdx = 0; trainIdx < rows.Length; trainIdx++) {
    502         for (int i = 0; i < trees.Length; i++) {
     539        for (int i = 0; i < optimizationData.targetVariables.Length; i++) {
    503540          var tree = trees[i];
    504541          var y = optimizationData.targetValues[i][trainIdx];
     
    583620        // data for input variables is assumed to be known
    584621        // input variables are all variable names that occur in the trees except for target variables (we assume that trees have been generated correctly)
    585         var inputVariables = trees.SelectMany(t => t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName)).Except(targetVars);
     622        var inputVariables = trees
     623          .SelectMany(t => t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName))
     624          .Except(targetVars)
     625          .Except(latentVariables)
     626          .Distinct();
    586627
    587628        var optimizationData = new OptimizationData(trees, targetVars, inputVariables.ToArray(), problemData, null, TrainingEpisodes.ToArray(), NumericIntegrationSteps, latentVariables, OdeSolver);
    588         var trainingPrediction = Integrate(optimizationData).ToArray();
    589 
    590 
    591629        var numParams = optimizationData.nodeValueLookup.ParameterCount;
     630
     631        var fi = new double[optimizationData.rows.Length * targetVars.Length];
     632        var jac = new double[optimizationData.rows.Length * targetVars.Length, numParams];
     633        var latentValues = new double[optimizationData.rows.Length, latentVariables.Length];
     634        Integrate(optimizationData, fi, jac, latentValues);
     635
     636
    592637        // for target values and latent variables
    593638        var trainingRows = optimizationData.rows;
     
    598643            var trainingDataTable = new DataTable(targetVar + " prediction (training)");
    599644            var actualValuesRow = new DataRow(targetVar, "The values of " + targetVar, problemData.Dataset.GetDoubleValues(targetVar, trainingRows));
    600             var predictedValuesRow = new DataRow(targetVar + " pred.", "Predicted values for " + targetVar, trainingPrediction.Select(arr => arr[colIdx].Item1).ToArray());
     645            var idx = Enumerable.Range(0, trainingRows.Length).Select(i => i * targetVars.Length + colIdx);
     646            var pred = idx.Select(i => fi[i]);
     647            var predictedValuesRow = new DataRow(targetVar + " pred.", "Predicted values for " + targetVar, pred.ToArray());
    601648            trainingDataTable.Rows.Add(actualValuesRow);
    602649            trainingDataTable.Rows.Add(predictedValuesRow);
    603650
    604651            for (int paramIdx = 0; paramIdx < numParams; paramIdx++) {
    605               var paramSensitivityRow = new DataRow($"∂{targetVar}/∂θ{paramIdx}", $"Sensitivities of parameter {paramIdx}", trainingPrediction.Select(arr => arr[colIdx].Item2[paramIdx]).ToArray());
     652              var paramSensitivityRow = new DataRow($"∂{targetVar}/∂θ{paramIdx}", $"Sensitivities of parameter {paramIdx}", idx.Select(i => jac[i, paramIdx]).ToArray());
    606653              paramSensitivityRow.VisualProperties.SecondYAxis = true;
    607654              trainingDataTable.Rows.Add(paramSensitivityRow);
     
    611658            var latentVar = latentVariables[colIdx - targetVars.Length];
    612659            var trainingDataTable = new DataTable(latentVar + " prediction (training)");
    613             var predictedValuesRow = new DataRow(latentVar + " pred.", "Predicted values for " + latentVar, trainingPrediction.Select(arr => arr[colIdx].Item1).ToArray());
     660            var idx = Enumerable.Range(0, trainingRows.Length);
     661            var pred = idx.Select(i => latentValues[i, colIdx - targetVars.Length]);
     662            var predictedValuesRow = new DataRow(latentVar + " pred.", "Predicted values for " + latentVar, pred.ToArray());
    614663            var emptyRow = new DataRow(latentVar);
    615664            trainingDataTable.Rows.Add(emptyRow);
     
    630679        int r = 0;
    631680
    632         foreach (var y_pred in trainingPrediction) {
    633           // calculate objective function gradient
    634           double f_i = 0.0;
    635           Vector g_i = Vector.CreateNew(new double[numParams]);
    636           for (int colIdx = 0; colIdx < targetVars.Length; colIdx++) {
    637             var y_pred_f = y_pred[colIdx].Item1;
    638             var y = targetValues[colIdx][r];
    639 
    640             var res = (y - y_pred_f) * optimizationData.inverseStandardDeviation[colIdx];
    641             var ressq = res * res;
    642             f_i += ressq;
    643             g_i.Add(y_pred[colIdx].Item2.Scale(-2.0 * res));
    644           }
    645           seRow.Values.Add(f_i);
    646           for (int j = 0; j < g_i.Length; j++) gradientRows[j].Values.Add(g_i[j]);
    647           r++;
    648         }
    649         results["Squared error and gradient"].Value = errorTable;
     681        // foreach (var y_pred in trainingPrediction) {
     682        //   // calculate objective function gradient
     683        //   double f_i = 0.0;
     684        //   Vector g_i = Vector.CreateNew(new double[numParams]);
     685        //   for (int colIdx = 0; colIdx < targetVars.Length; colIdx++) {
     686        //     var y_pred_f = y_pred[colIdx].Item1;
     687        //     var y = targetValues[colIdx][r];
     688        //
     689        //     var res = (y - y_pred_f) * optimizationData.inverseStandardDeviation[colIdx];
     690        //     var ressq = res * res;
     691        //     f_i += ressq;
     692        //     g_i.Add(y_pred[colIdx].Item2.Scale(-2.0 * res));
     693        //   }
     694        //   seRow.Values.Add(f_i);
     695        //   for (int j = 0; j < g_i.Length; j++) gradientRows[j].Values.Add(g_i[j]);
     696        //   r++;
     697        // }
     698        // results["Squared error and gradient"].Value = errorTable;
    650699
    651700        // TODO: DRY for training and test
     
    667716
    668717          } else {
    669             var latentVar = latentVariables[colIdx - targetVars.Length];
    670             var testDataTable = new DataTable(latentVar + " prediction (test)");
    671             var predictedValuesRow = new DataRow(latentVar + " pred.", "Predicted values for " + latentVar, testPrediction.Select(arr => arr[colIdx].Item1).ToArray());
    672             var emptyRow = new DataRow(latentVar);
    673             testDataTable.Rows.Add(emptyRow);
    674             testDataTable.Rows.Add(predictedValuesRow);
    675             testList.Add(testDataTable);
     718            // var latentVar = latentVariables[colIdx - targetVars.Length];
     719            // var testDataTable = new DataTable(latentVar + " prediction (test)");
     720            // var predictedValuesRow = new DataRow(latentVar + " pred.", "Predicted values for " + latentVar, testPrediction.Select(arr => arr[colIdx].Item1).ToArray());
     721            // var emptyRow = new DataRow(latentVar);
     722            // testDataTable.Rows.Add(emptyRow);
     723            // testDataTable.Rows.Add(predictedValuesRow);
     724            // testList.Add(testDataTable);
    676725          }
    677726        }
     
    742791      double[] fi = new double[n];
    743792      double[,] jac = new double[n, d];
    744       Integrate(optimizationData, fi, jac);
     793      Integrate(optimizationData, fi, jac, null);
    745794      for (int i = 0; i < optimizationData.rows.Length; i++) {
    746795        var res = new Tuple<double, Vector>[nTargets];
     
    752801    }
    753802
    754     public static void Integrate(OptimizationData optimizationData, double[] fi, double[,] jac) {
     803    public static void Integrate(OptimizationData optimizationData, double[] fi, double[,] jac, double[,] latentValues) {
    755804      var trees = optimizationData.trees;
    756805      var dataset = optimizationData.problemData.Dataset;
     
    795844          outputRowIdx++;
    796845        }
     846
     847        var latentValueRowIdx = 0;
     848        var latentValueColIdx = 0;
     849        foreach (var varName in latentVariables) {
     850          var y0 = 0.0; // assume we start at zero
     851          nodeValues.SetVariableValue(varName, y0, Vector.Zero);
     852
     853          if (latentValues != null) {
     854            latentValues[latentValueRowIdx, latentValueColIdx++] = y0;
     855          }
     856        }
     857        latentValueColIdx = 0; latentValueRowIdx++;
    797858
    798859        { // CODE BELOW DOESN'T WORK ANYMORE
     
    822883          prevT = t;
    823884
    824           for (int i = 0; i < calculatedVariables.Length; i++) {
    825             var targetVar = calculatedVariables[i];
     885          // update output for target variables (TODO: if we want to visualize the latent variables then we need to provide a separate output)
     886          for (int i = 0; i < targetVariables.Length; i++) {
     887            var targetVar = targetVariables[i];
    826888            var yt = nodeValues.GetVariableValue(targetVar);
    827889
     
    829891            if (double.IsNaN(yt.Item1) || double.IsInfinity(yt.Item1)) {
    830892              for (; outputRowIdx < fi.Length; outputRowIdx++) {
    831                 var prevIdx = outputRowIdx - calculatedVariables.Length;
     893                var prevIdx = outputRowIdx - targetVariables.Length;
    832894                fi[outputRowIdx] = fi[prevIdx]; // current <- prev
    833895                if (jac != null) for (int j = 0; j < jac.GetLength(1); j++) jac[outputRowIdx, j] = jac[prevIdx, j];
     
    840902            g.CopyTo(jac, outputRowIdx);
    841903            outputRowIdx++;
     904          }
     905          if (latentValues != null) {
     906            foreach (var latentVariable in latentVariables) {
     907              var lt = nodeValues.GetVariableValue(latentVariable).Item1;
     908              latentValues[latentValueRowIdx, latentValueColIdx++] = lt;
     909            }
     910            latentValueRowIdx++; latentValueColIdx = 0;
    842911          }
    843912
     
    14511520
    14521521    #region  helper
     1522
     1523    private static IEnumerable<T> EveryNth<T>(IEnumerable<T> xs, int step) {
     1524      var e = xs.GetEnumerator();
     1525      while (e.MoveNext()) {
     1526        for (int i = 0; i < step; i++) {
     1527          if (!e.MoveNext()) yield break;
     1528        }
     1529        yield return e.Current;
     1530      }
     1531    }
    14531532
    14541533    private void InitAllParameters() {
  • branches/2925_AutoDiffForDynamicalModels/HeuristicLab.Problems.DynamicalSystemsModelling/3.3/Solution.cs

    r16653 r16660  
    8686    }
    8787
    88     public IEnumerable<double[]> Predict(IntRange episode, int forecastHorizon, out double snmse) {
     88    public IEnumerable<double[]> Predict(IntRange episode, int forecastHorizon) {
    8989      var forecastEpisode = new IntRange(episode.Start, episode.End + forecastHorizon);
    9090      //
     
    9292      // snmse = Problem.OptimizeForEpisodes(trees, problemData, targetVars, latentVariables, random, new[] { forecastEpisode }, 100, numericIntegrationSteps, odeSolver);
    9393
    94       var inputVariables = trees.SelectMany(t => t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName)).Except(targetVars);
     94      var inputVariables = trees.SelectMany(t => t.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName))
     95        .Except(targetVars)
     96        .Except(latentVariables)
     97        .Distinct();
    9598
    9699      var optimizationData = new Problem.OptimizationData(trees, targetVars, inputVariables.ToArray(), problemData, null, new[] { forecastEpisode }, numericIntegrationSteps, latentVariables, odeSolver);
     
    99102      // var theta = Problem.ExtractParametersFromTrees(trees);
    100103
    101       snmse = 0.0; // TODO
    102       return Problem.Integrate(optimizationData).Select(p => p.Select(pi => pi.Item1).ToArray()).ToArray();
     104
     105      var fi = new double[forecastEpisode.Size * targetVars.Length];
     106      var jac = new double[forecastEpisode.Size * targetVars.Length, optimizationData.nodeValueLookup.ParameterCount];
     107      var latentValues = new double[forecastEpisode.Size, LatentVariables.Length];
     108      Problem.Integrate(optimizationData, fi, jac, latentValues);
     109      for (int i = 0; i < forecastEpisode.Size; i++) {
     110        var res = new double[targetVars.Length + latentVariables.Length];
     111        for (int j = 0; j < targetVars.Length; j++) {
     112          res[j] = fi[i * targetVars.Length + j];
     113        }
     114        for (int j = 0; j < latentVariables.Length; j++) {
     115          res[targetVars.Length + j] = latentValues[i, j];
     116        }
     117        yield return res;
     118      }
    103119    }
    104120  }
  • branches/2925_AutoDiffForDynamicalModels/HeuristicLab.Problems.DynamicalSystemsModelling/3.3/SolutionView.cs

    r16400 r16660  
    7373
    7474      double snmse;
    75       var predictions = Content.Predict(predictionEpisode, forecastHorizon, out snmse).ToArray();
    76       errorLabel.Text = $"SNMSE: {snmse:e4}";
     75      var predictions = Content.Predict(predictionEpisode, forecastHorizon).ToArray();
     76      errorLabel.Text = $"SNMSE: {0.0:e4}";
    7777      var trainingPredictions = predictions.Take(predictionEpisode.Size).ToArray();
    7878      var forecastPredictions = predictions.Skip(predictionEpisode.Size).ToArray();
Note: See TracChangeset for help on using the changeset viewer.