Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1902 implemented a few covariance functions as parameterized named items. Implemented rudimentary view for Gaussian process models.

File size: 10.2 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    [Storable]
38    private double negativeLogLikelihood;
39    public double NegativeLogLikelihood {
40      get { return negativeLogLikelihood; }
41    }
42
43    [Storable]
44    private double[] hyperparameterGradients;
45    public double[] HyperparameterGradients {
46      get {
47        var copy = new double[hyperparameterGradients.Length];
48        Array.Copy(hyperparameterGradients, copy, copy.Length);
49        return copy;
50      }
51    }
52
53    [Storable]
54    private ICovarianceFunction covarianceFunction;
55    public ICovarianceFunction CovarianceFunction {
56      get { return covarianceFunction; }
57    }
58    [Storable]
59    private IMeanFunction meanFunction;
60    public IMeanFunction MeanFunction {
61      get { return meanFunction; }
62    }
63    [Storable]
64    private string targetVariable;
65    public string TargetVariable {
66      get { return targetVariable; }
67    }
68    [Storable]
69    private string[] allowedInputVariables;
70    public string[] AllowedInputVariables {
71      get { return allowedInputVariables; }
72    }
73
74    [Storable]
75    private double[] alpha;
76    [Storable]
77    private double sqrSigmaNoise;
78    public double SigmaNoise {
79      get { return Math.Sqrt(sqrSigmaNoise); }
80    }
81
82    [Storable]
83    private double[,] l;
84
85    [Storable]
86    private double[,] x;
87    [Storable]
88    private Scaling inputScaling;
89
90
91    [StorableConstructor]
92    private GaussianProcessModel(bool deserializing) : base(deserializing) { }
93    private GaussianProcessModel(GaussianProcessModel original, Cloner cloner)
94      : base(original, cloner) {
95      this.meanFunction = cloner.Clone(original.meanFunction);
96      this.covarianceFunction = cloner.Clone(original.covarianceFunction);
97      this.inputScaling = cloner.Clone(original.inputScaling);
98      this.negativeLogLikelihood = original.negativeLogLikelihood;
99      this.targetVariable = original.targetVariable;
100      this.sqrSigmaNoise = original.sqrSigmaNoise;
101
102      // shallow copies of arrays because they cannot be modified
103      this.allowedInputVariables = original.allowedInputVariables;
104      this.alpha = original.alpha;
105      this.l = original.l;
106      this.x = original.x;
107    }
108    public GaussianProcessModel(Dataset ds, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
109      IEnumerable<double> hyp, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction)
110      : base() {
111      this.name = ItemName;
112      this.description = ItemDescription;
113      this.meanFunction = (IMeanFunction)meanFunction.Clone();
114      this.covarianceFunction = (ICovarianceFunction)covarianceFunction.Clone();
115      this.targetVariable = targetVariable;
116      this.allowedInputVariables = allowedInputVariables.ToArray();
117
118
119      int nVariables = this.allowedInputVariables.Length;
120      this.meanFunction.SetParameter(hyp
121        .Take(this.meanFunction.GetNumberOfParameters(nVariables))
122        .ToArray());
123      this.covarianceFunction.SetParameter(hyp.Skip(this.meanFunction.GetNumberOfParameters(nVariables))
124        .Take(this.covarianceFunction.GetNumberOfParameters(nVariables))
125        .ToArray());
126      sqrSigmaNoise = Math.Exp(2.0 * hyp.Last());
127
128      CalculateModel(ds, rows);
129    }
130
131    private void CalculateModel(Dataset ds, IEnumerable<int> rows) {
132      inputScaling = new Scaling(ds, allowedInputVariables, rows);
133      x = AlglibUtil.PrepareAndScaleInputMatrix(ds, allowedInputVariables, rows, inputScaling);
134      var y = ds.GetDoubleValues(targetVariable, rows);
135
136      int n = x.GetLength(0);
137      l = new double[n, n];
138
139      meanFunction.SetData(x);
140
141      // calculate means and covariances
142      double[] m = meanFunction.GetMean(x);
143      for (int i = 0; i < n; i++) {
144        for (int j = i; j < n; j++) {
145          l[j, i] = covarianceFunction.GetCovariance(x, i, j) / sqrSigmaNoise;
146          if (j == i) l[j, i] += 1.0;
147        }
148      }
149
150      // cholesky decomposition
151      int info;
152      alglib.densesolverreport denseSolveRep;
153
154      var res = alglib.trfac.spdmatrixcholesky(ref l, n, false);
155      if (!res) throw new ArgumentException("Matrix is not positive semidefinite");
156
157      // calculate sum of diagonal elements for likelihood
158      double diagSum = Enumerable.Range(0, n).Select(i => Math.Log(l[i, i])).Sum();
159
160      // solve for alpha
161      double[] ym = y.Zip(m, (a, b) => a - b).ToArray();
162
163      alglib.spdmatrixcholeskysolve(l, n, false, ym, out info, out denseSolveRep, out alpha);
164      for (int i = 0; i < alpha.Length; i++)
165        alpha[i] = alpha[i] / sqrSigmaNoise;
166      negativeLogLikelihood = 0.5 * Util.ScalarProd(ym, alpha) + diagSum + (n / 2.0) * Math.Log(2.0 * Math.PI * sqrSigmaNoise);
167
168      // derivatives
169      int nAllowedVariables = x.GetLength(1);
170
171      alglib.matinvreport matInvRep;
172      double[,] lCopy = new double[l.GetLength(0), l.GetLength(1)];
173      Array.Copy(l, lCopy, lCopy.Length);
174
175      alglib.spdmatrixcholeskyinverse(ref lCopy, n, false, out info, out matInvRep);
176      if (info != 1) throw new ArgumentException("Can't invert matrix to calculate gradients.");
177      for (int i = 0; i < n; i++) {
178        for (int j = 0; j <= i; j++)
179          lCopy[i, j] = lCopy[i, j] / sqrSigmaNoise - alpha[i] * alpha[j];
180      }
181
182      double noiseGradient = sqrSigmaNoise * Enumerable.Range(0, n).Select(i => lCopy[i, i]).Sum();
183
184      double[] meanGradients = new double[meanFunction.GetNumberOfParameters(nAllowedVariables)];
185      for (int i = 0; i < meanGradients.Length; i++) {
186        var meanGrad = meanFunction.GetGradients(i, x);
187        meanGradients[i] = -Util.ScalarProd(meanGrad, alpha);
188      }
189
190      double[] covGradients = new double[covarianceFunction.GetNumberOfParameters(nAllowedVariables)];
191      if (covGradients.Length > 0) {
192        for (int i = 0; i < n; i++) {
193          for (int j = 0; j < i; j++) {
194            var g = covarianceFunction.GetGradient(x, i, j).ToArray();
195            for (int k = 0; k < covGradients.Length; k++) {
196              covGradients[k] += lCopy[i, j] * g[k];
197            }
198          }
199
200          var gDiag = covarianceFunction.GetGradient(x, i, i).ToArray();
201          for (int k = 0; k < covGradients.Length; k++) {
202            // diag
203            covGradients[k] += 0.5 * lCopy[i, i] * gDiag[k];
204          }
205        }
206      }
207
208      hyperparameterGradients =
209        meanGradients
210        .Concat(covGradients)
211        .Concat(new double[] { noiseGradient }).ToArray();
212
213    }
214
215
216    public override IDeepCloneable Clone(Cloner cloner) {
217      return new GaussianProcessModel(this, cloner);
218    }
219
220    #region IRegressionModel Members
221    public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {
222      return GetEstimatedValuesHelper(dataset, rows);
223    }
224    public GaussianProcessRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
225      return new GaussianProcessRegressionSolution(this, new RegressionProblemData(problemData));
226    }
227    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
228      return CreateRegressionSolution(problemData);
229    }
230    #endregion
231
232    private IEnumerable<double> GetEstimatedValuesHelper(Dataset dataset, IEnumerable<int> rows) {
233      var newX = AlglibUtil.PrepareAndScaleInputMatrix(dataset, allowedInputVariables, rows, inputScaling);
234      int newN = newX.GetLength(0);
235      int n = x.GetLength(0);
236      var Ks = new double[newN, n];
237      meanFunction.SetData(newX);
238      var ms = meanFunction.GetMean(newX);
239      for (int i = 0; i < newN; i++) {
240        for (int j = 0; j < n; j++) {
241          Ks[i, j] = covarianceFunction.GetCrossCovariance(x, newX, j, i);
242        }
243      }
244
245      return Enumerable.Range(0, newN)
246        .Select(i => ms[i] + Util.ScalarProd(Util.GetRow(Ks, i), alpha));
247    }
248
249    public IEnumerable<double> GetEstimatedVariance(Dataset dataset, IEnumerable<int> rows) {
250      var newX = AlglibUtil.PrepareAndScaleInputMatrix(dataset, allowedInputVariables, rows, inputScaling);
251      int newN = newX.GetLength(0);
252      int n = x.GetLength(0);
253
254      var kss = new double[newN];
255      double[,] sWKs = new double[n, newN];
256
257      // for stddev
258      for (int i = 0; i < newN; i++)
259        kss[i] = covarianceFunction.GetCovariance(newX, i, i);
260
261      for (int i = 0; i < newN; i++) {
262        for (int j = 0; j < n; j++) {
263          sWKs[j, i] = covarianceFunction.GetCrossCovariance(x, newX, j, i) / Math.Sqrt(sqrSigmaNoise);
264        }
265      }
266
267      // for stddev
268      alglib.ablas.rmatrixlefttrsm(n, newN, l, 0, 0, false, false, 0, ref sWKs, 0, 0);
269
270      for (int i = 0; i < newN; i++) {
271        var sumV = Util.ScalarProd(Util.GetCol(sWKs, i), Util.GetCol(sWKs, i));
272        kss[i] -= sumV;
273        if (kss[i] < 0) kss[i] = 0;
274      }
275      return kss;
276    }
277  }
278}
Note: See TracBrowser for help on using the repository browser.