Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs @ 8371

Last change on this file since 8371 was 8371, checked in by gkronber, 12 years ago

#1902: worked on Gaussian Process algorithm

File size: 10.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28using HeuristicLab.Problems.DataAnalysis;
29
30namespace HeuristicLab.Algorithms.DataAnalysis {
31  /// <summary>
32  /// Represents a Gaussian process model.
33  /// </summary>
34  [StorableClass]
35  [Item("GaussianProcessModel", "Represents a Gaussian process posterior.")]
36  public sealed class GaussianProcessModel : NamedItem, IGaussianProcessModel {
37
38    [Storable]
39    private double negativeLogLikelihood;
40
41    public double NegativeLogLikelihood {
42      get { return negativeLogLikelihood; }
43    }
44
45    [Storable]
46    private ICovarianceFunction covarianceFunction;
47    public ICovarianceFunction CovarianceFunction {
48      get { return covarianceFunction; }
49    }
50    [Storable]
51    private IMeanFunction meanFunction;
52    public IMeanFunction MeanFunction {
53      get { return meanFunction; }
54    }
55    [Storable]
56    private double[] hyp;
57    public IEnumerable<double> Hyperparameters {
58      get { return hyp; }
59    }
60    [Storable]
61    private string targetVariable;
62    public string TargetVariable {
63      get { return targetVariable; }
64    }
65    [Storable]
66    private string[] allowedInputVariables;
67    public string[] AllowedInputVariables {
68      get { return allowedInputVariables; }
69    }
70
71    [Storable]
72    private double[] alpha;
73    [Storable]
74    private double sqrSigmaNoise;
75    [Storable]
76    private double[] meanHyp;
77    [Storable]
78    private double[] covHyp;
79
80    [Storable]
81    private double[,] l;
82
83    [Storable]
84    private double[,] x;
85    [Storable]
86    private Scaling scaling;
87
88
89    [StorableConstructor]
90    private GaussianProcessModel(bool deserializing) : base(deserializing) { }
91    private GaussianProcessModel(GaussianProcessModel original, Cloner cloner)
92      : base(original, cloner) {
93      this.hyp = original.hyp;
94      this.meanFunction = cloner.Clone(original.meanFunction);
95      this.covarianceFunction = cloner.Clone(original.covarianceFunction);
96      this.negativeLogLikelihood = original.negativeLogLikelihood;
97      this.targetVariable = original.targetVariable;
98      this.allowedInputVariables = original.allowedInputVariables;
99      this.alpha = original.alpha;
100      this.sqrSigmaNoise = original.sqrSigmaNoise;
101      this.scaling = cloner.Clone(original.scaling);
102      this.meanHyp = original.meanHyp;
103      this.covHyp = original.covHyp;
104      this.l = original.l;
105      this.x = original.x;
106    }
107    public GaussianProcessModel(Dataset ds, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
108      IEnumerable<double> hyp, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction)
109      : base() {
110      this.name = ItemName;
111      this.description = ItemDescription;
112      this.hyp = hyp.ToArray();
113      this.meanFunction = meanFunction;
114      this.covarianceFunction = covarianceFunction;
115      this.targetVariable = targetVariable;
116      this.allowedInputVariables = allowedInputVariables.ToArray();
117      int nAllowedVariables = allowedInputVariables.Count();
118
119      sqrSigmaNoise = Math.Exp(2.0 * hyp.First());
120      sqrSigmaNoise = Math.Max(10E-6, sqrSigmaNoise); // lower limit for the noise level
121      meanHyp = hyp.Skip(1).Take(meanFunction.GetNumberOfParameters(nAllowedVariables)).ToArray();
122      covHyp = hyp.Skip(1 + meanFunction.GetNumberOfParameters(nAllowedVariables)).Take(covarianceFunction.GetNumberOfParameters(nAllowedVariables)).ToArray();
123
124      CalculateModel(ds, targetVariable, allowedInputVariables, rows);
125    }
126
127    private void CalculateModel(Dataset ds, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows) {
128      scaling = new Scaling(ds, allowedInputVariables, rows);
129      x = AlglibUtil.PrepareAndScaleInputMatrix(ds, allowedInputVariables, rows, scaling);
130
131      var y = ds.GetDoubleValues(targetVariable, rows).ToArray();
132
133      int n = x.GetLength(0);
134      l = new double[n, n];
135
136      meanFunction.SetParameter(meanHyp, x);
137      covarianceFunction.SetParameter(covHyp, x);
138
139      // calculate means and covariances
140      double[] m = meanFunction.GetMean(x);
141      for (int i = 0; i < n; i++) {
142
143        for (int j = i; j < n; j++) {
144          l[j, i] = covarianceFunction.GetCovariance(i, j) / sqrSigmaNoise;
145          if (j == i) l[j, i] += 1.0;
146        }
147      }
148
149      // cholesky decomposition
150      int info;
151      alglib.densesolverreport denseSolveRep;
152
153      var res = alglib.trfac.spdmatrixcholesky(ref l, n, false);
154      if (!res) throw new InvalidOperationException("Matrix is not positive semidefinite");
155
156      // calculate sum of diagonal elements for likelihood
157      double diagSum = Enumerable.Range(0, n).Select(i => Math.Log(l[i, i])).Sum();
158
159      // solve for alpha
160      double[] ym = y.Zip(m, (a, b) => a - b).ToArray();
161
162      alglib.spdmatrixcholeskysolve(l, n, false, ym, out info, out denseSolveRep, out alpha);
163      for (int i = 0; i < alpha.Length; i++)
164        alpha[i] = alpha[i] / sqrSigmaNoise;
165      negativeLogLikelihood = 0.5 * Util.ScalarProd(ym, alpha) + diagSum + (n / 2.0) * Math.Log(2.0 * Math.PI * sqrSigmaNoise);
166    }
167
168    public double[] GetHyperparameterGradients() {
169      // derivatives
170      int n = x.GetLength(0);
171      int nAllowedVariables = x.GetLength(1);
172      double[,] q = new double[n, n];
173      double[,] eye = new double[n, n];
174      for (int i = 0; i < n; i++) eye[i, i] = 1.0;
175
176      int info;
177      alglib.densesolverreport denseSolveRep;
178
179      alglib.spdmatrixcholeskysolvem(l, n, false, eye, n, out info, out denseSolveRep, out q);
180      // double[,] a2 = outerProd(alpha, alpha);
181      for (int i = 0; i < n; i++) {
182        for (int j = 0; j < n; j++)
183          q[i, j] = q[i, j] / sqrSigmaNoise - alpha[i] * alpha[j]; // a2[i, j];
184      }
185
186      double noiseGradient = sqrSigmaNoise * Enumerable.Range(0, n).Select(i => q[i, i]).Sum();
187
188      double[] meanGradients = new double[meanFunction.GetNumberOfParameters(nAllowedVariables)];
189      for (int i = 0; i < meanGradients.Length; i++) {
190        var meanGrad = meanFunction.GetGradients(i, x);
191        meanGradients[i] = -Util.ScalarProd(meanGrad, alpha);
192      }
193
194      double[] covGradients = new double[covarianceFunction.GetNumberOfParameters(nAllowedVariables)];
195      if (covGradients.Length > 0) {
196        for (int i = 0; i < n; i++) {
197          for (int j = 0; j < n; j++) {
198            var covDeriv = covarianceFunction.GetGradient(i, j);
199            for (int k = 0; k < covGradients.Length; k++) {
200              covGradients[k] += q[i, j] * covDeriv[k];
201            }
202          }
203        }
204        covGradients = covGradients.Select(g => g / 2.0).ToArray();
205      }
206
207      return new double[] { noiseGradient }
208        .Concat(meanGradients)
209        .Concat(covGradients).ToArray();
210    }
211
212
213    public override IDeepCloneable Clone(Cloner cloner) {
214      return new GaussianProcessModel(this, cloner);
215    }
216
217    #region IRegressionModel Members
218    public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {
219      return GetEstimatedValuesHelper(dataset, rows);
220    }
221    public GaussianProcessRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
222      return new GaussianProcessRegressionSolution(this, problemData);
223    }
224    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
225      return CreateRegressionSolution(problemData);
226    }
227    #endregion
228
229    private IEnumerable<double> GetEstimatedValuesHelper(Dataset dataset, IEnumerable<int> rows) {
230      var newX = AlglibUtil.PrepareAndScaleInputMatrix(dataset, allowedInputVariables, rows, scaling);
231      int newN = newX.GetLength(0);
232      int n = x.GetLength(0);
233      // var predMean = new double[newN];
234      // predVar = new double[newN];
235
236
237
238      // var kss = new double[newN];
239      var Ks = new double[newN, n];
240      double[,] sWKs = new double[n, newN];
241      // double[,] v;
242
243
244      // for stddev
245      //covarianceFunction.SetParameter(covHyp, newX);
246      //kss = covarianceFunction.GetDiagonalCovariances();
247
248      covarianceFunction.SetParameter(covHyp, x, newX);
249      meanFunction.SetParameter(meanHyp, newX);
250      var ms = meanFunction.GetMean(newX);
251      for (int i = 0; i < newN; i++) {
252
253        for (int j = 0; j < n; j++) {
254          Ks[i, j] = covarianceFunction.GetCovariance(j, i);
255          sWKs[j, i] = Ks[i, j] / Math.Sqrt(sqrSigmaNoise);
256        }
257      }
258
259      // for stddev
260      // alglib.rmatrixsolvem(l, n, sWKs, newN, true, out info, out denseSolveRep, out v);
261
262
263      for (int i = 0; i < newN; i++) {
264        // predMean[i] = ms[i] + prod(GetRow(Ks, i), alpha);
265        yield return ms[i] + Util.ScalarProd(Util.GetRow(Ks, i), alpha);
266        // var sumV2 = prod(GetCol(v, i), GetCol(v, i));
267        // predVar[i] = kss[i] - sumV2;
268      }
269
270    }
271
272    #region events
273    public event EventHandler Changed;
274    private void OnChanged(EventArgs e) {
275      var handlers = Changed;
276      if (handlers != null)
277        handlers(this, e);
278    }
279    #endregion
280  }
281}
Note: See TracBrowser for help on using the repository browser.