17 | module Spidr.Model.GaussianProcess
19 | import Control.Relation
22 | import Spidr.Constants
23 | import Spidr.Distribution
24 | import Spidr.Model.Supervised
26 | import Spidr.Model.Kernel
27 | import Spidr.Model.MeanFunction
28 | import Spidr.Optimize
37 | data GaussianProcess : (0 features : Shape) -> Type where
39 | MkGP : MeanFunction features -> Kernel features -> GaussianProcess features
42 | GaussianProcess features ->
44 | {s : _} -> (Tensor ((S s) :: features) F64, Tensor [S s] F64) ->
45 | Tag $
GaussianProcess features
46 | posterior (MkGP priorMeanf priorKernel) noise (xTrain, yTrain) = do
47 | l <- tag !(cholesky $
!(priorKernel xTrain xTrain) + broadcast noise * identity)
48 | let alpha = l.T \| (l |\ yTrain)
50 | posteriorMeanf : MeanFunction features
51 | posteriorMeanf x = pure $
!(priorMeanf x) + !(priorKernel x xTrain) @@ alpha
53 | posteriorKernel : Kernel features
54 | posteriorKernel x x' = pure
55 | $
!(priorKernel x x') - (l |\ !(priorKernel xTrain x)).T @@ (l |\ !(priorKernel xTrain x'))
57 | pure $
MkGP posteriorMeanf posteriorKernel
59 | logMarginalLikelihood :
60 | GaussianProcess features ->
62 | {s : _} -> (Tensor ((S s) :: features) F64, Tensor [S s] F64) ->
64 | logMarginalLikelihood (MkGP _ kernel) noise (x, y) = do
65 | l <- tag !(cholesky (!(kernel x x) + broadcast noise * identity))
66 | let alpha = l.T \| (l |\ y)
67 | pure $
- y @@ alpha / 2.0 - !(trace (log l)) - fromDouble (cast (S s)) * log (2.0 * pi) / 2.0
81 | data ConjugateGPRegression : (0 features : Shape) -> Type where
88 | (gpFromHyperparameters : Tensor [p] F64 -> Tag $
GaussianProcess features) ->
89 | (hyperparameters : Tensor [p] F64) ->
90 | (noise : Tensor [] F64) ->
91 | ConjugateGPRegression features
95 | [Latent] ProbabilisticModel features [1] Gaussian (ConjugateGPRegression features) where
96 | marginalise (MkConjugateGPR mkGP gpParams _) x = do
97 | MkGP meanf kernel <- mkGP gpParams
98 | [| MkGaussian (expand 1 <$> meanf x) (expand 2 <$> kernel x x) |]
102 | [Observed] ProbabilisticModel features [1] Gaussian (ConjugateGPRegression features) where
103 | marginalise gpr@(MkConjugateGPR _ _ noise) x = do
104 | MkGaussian latentMean latentCov <- marginalise @{Latent} gpr x
105 | let cov = latentCov + broadcast (expand 2 (broadcast noise * identity {n = S n}))
106 | pure $
MkGaussian latentMean cov
110 | fit : (forall n . Tensor [n] F64 -> Optimizer $
Tensor [n] F64)
111 | -> Dataset features [1]
112 | -> ConjugateGPRegression features
113 | -> Tag $
ConjugateGPRegression features
114 | fit optimizer (MkDataset x y) (MkConjugateGPR {p} mkPrior gpParams noise) = do
115 | let objective : Tensor [S p] F64 -> Tag $
Tensor [] F64
116 | objective params = do
117 | let priorParams = slice [1.to (S p)] params
118 | logMarginalLikelihood !(mkPrior priorParams) (slice [at 0] params) (x, squeeze y)
120 | params <- optimizer (concat 0 (expand 0 noise) gpParams) objective
122 | let mkPosterior : Tensor [p] F64 -> Tag $
GaussianProcess features
123 | mkPosterior params' = posterior !(mkPrior params') (squeeze noise) (x, squeeze y)
125 | pure $
MkConjugateGPR mkPosterior (slice [1.to (S p)] params) (slice [at 0] params)
129 | reflexive : {n : _} -> LTE n n
130 | reflexive = Relation.reflexive {ty = Nat}