1414# limitations under the License.
1515#
1616
17+ from typing import List
1718import numpy as np
1819from scipy .stats import gaussian_kde
1920from scipy .integrate import quad
20- from GPy .kern import RBF
21- from GPy .models import GPRegression
22- from GPy .core .parameterization .priors import Gamma
23- from GPy .inference .mcmc import HMC
21+ import GPy
22+
23+ def plot_posteriors (samples : np .array , labels : List [str ], ** kwargs ):
24+
25+ '''
26+ Plot hyper-parameter posteriors following HMC. By convention, first column of samples is RBF kernel variance chain.
27+ The last column of samples is the RBF kernel noise. The middle columns of samples are ARD length scale parameters.
28+
29+ Parameters:
30+ samples (np.array): hyper-parameter HMC chains.
31+ labels (List[str]): sample column labels for graph legends.
32+ '''
33+
34+ import matplotlib .pyplot as plt
35+
36+ num_of_plots = 3
37+ num_of_posteriors = samples .shape [- 1 ]
38+ dim = num_of_posteriors - num_of_plots + 1
39+
40+ assert len (labels ) == num_of_posteriors , \
41+ f'Expected { num_of_posteriors } plot labels, but received { len (labels )} .'
42+
43+ fig_width = kwargs ['fig_width' ] if 'fig_width' in kwargs else 10
44+ fig_length = kwargs ['fig_length' ] if 'fig_length' in kwargs else 3
45+
46+ _ , axs = plt .subplots (num_of_plots ,1 ,figsize = (fig_width ,num_of_plots * fig_length ))
47+ cmap = plt .cm .get_cmap (name = 'Accent' ,lut = num_of_posteriors )
48+
49+ for i , J in zip (range (num_of_plots ),[[0 ],[1 + j for j in range (dim )],[dim + 1 ]]):
50+
51+ modals = []
52+
53+ for j in J :
54+
55+ s = samples [:,j ]
56+ xmin = s .min ()* 0.9
57+ xmax = s .max ()* 1.1
58+ xs = np .linspace (xmin ,xmax ,1000 )
59+
60+ if ('kdes' in kwargs ) and (j in kwargs ['kdes' ]):
61+ kde = kwargs ['kdes' ][j ]
62+ else :
63+ kde = gaussian_kde (s )
64+
65+ if ('modals' in kwargs ) and (j in kwargs ['modals' ]):
66+ modal = kwargs ['modals' ][j ]
67+ else :
68+ density = kde .pdf (xs )
69+ argmax = np .argmax (density )
70+ modal = xs [argmax ]
71+
72+ modals .append (modal )
73+ modal_density = kde .pdf (modal )[0 ]
74+
75+ axs [i ].plot ([modal ,modal ],[0 ,modal_density ],ls = '--' ,color = cmap (j ))
76+ axs [i ].plot (xs ,kde (xs ),label = labels [j ],lw = 3 ,color = cmap (j ))
77+
78+ ticks = np .sort (np .hstack ([np .around (np .array (modals ),2 ), axs [i ].get_xticks ()]))
79+ axs [i ].set_xticks (ticks [1 :- 1 ]) # ticks[1:-1]
80+ axs [i ].tick_params (axis = "x" , rotation = 90 , labelsize = 12 )
81+ axs [i ].legend ()
82+
83+ plt .tight_layout ()
2484
2585def find_modal (samples , linspace_num : int = 1000 ):
2686
@@ -35,69 +95,78 @@ def find_modal(samples, linspace_num: int=1000):
3595 argmax = np .argmax (density )
3696 modal = xs [argmax ]
3797
38- return modal
98+ return modal , kde
3999
40100 except :
41101
42- return None
102+ return None , None
43103
44104def gp_model (X : np .array ,
45105 y : np .array ,
46106 is_mcmc : bool = False ,
47107 num_samples : int = 1000 ,
48108 hmc_iters : int = 2 ,
49- linspace_num : int = 1000 ) -> GPRegression :
109+ plot_kernel_posteriors : bool = False ,
110+ linspace_num : int = 1000 ) -> GPy .models .GPRegression :
50111
51112 dim = X .shape [- 1 ]
52113
53114 if is_mcmc :
54115
55- factor = 10.0 # TODO: clever factor for numerical issues in HMC train
116+ factor = 10.0 # factor for numerical issues in HMC train
56117
57- kern = RBF (input_dim = dim , ARD = True )
58- model = GPRegression (factor * X ,y ,kernel = kern .copy ())
118+ kern = GPy . kern . RBF (input_dim = dim , ARD = True )
119+ model = GPy . models . GPRegression (factor * X ,y ,kernel = kern .copy ())
59120
60- # TODO: automate prior for RBF variance
61- model .kern .variance .set_prior (Gamma .from_EV (0.1 ,0.1 ),warning = False )
121+ # automate prior for RBF variance
122+ model .kern .variance .set_prior (GPy . priors . Gamma .from_EV (0.1 ,0.1 ),warning = False )
62123
63124 lengthscales = {}
125+ kdes = {}
64126 for i in range (dim ):
65127 kde = gaussian_kde (X [:,i ])
128+ kdes [i + 1 ] = kde
66129 mean = quad (lambda x : x * kde .pdf (x ), a = - np .inf , b = np .inf )[0 ]
67130 var = quad (lambda x : x ** 2 * kde .pdf (x ), a = - np .inf , b = np .inf )[0 ] - mean ** 2
68131 lengthscales [i ] = np .sqrt (var )
69- model .kern .lengthscale [[i ]].set_prior (Gamma .from_EV (lengthscales [i ],lengthscales [i ]/ 2 ),warning = False ) # data variance as length scale
132+ model .kern .lengthscale [[i ]].set_prior (GPy . priors . Gamma .from_EV (lengthscales [i ],lengthscales [i ]/ 2 ),warning = False )
70133
71- hmc = HMC (model )
134+ hmc = GPy . inference . mcmc . HMC (model )
72135 samples = hmc .sample (num_samples = num_samples ,hmc_iters = hmc_iters )
73136
74- modals = {}
137+ modals = {}
138+ kdes = {}
75139 for i in range (samples .shape [- 1 ]):
76- modal = find_modal (samples [:,i ],linspace_num )
77- if modal is not None :
140+ modal , kde = find_modal (samples [:,i ],linspace_num )
141+ if ( modal is not None ) and ( kde is not None ) :
78142 modals [i ] = modal
143+ kdes [i ] = kde
79144
80- kern = RBF (input_dim = dim , ARD = True )
81- model = GPRegression (X ,y ,kernel = kern .copy ())
145+ kern = GPy . kern . RBF (input_dim = dim , ARD = True )
146+ model = GPy . models . GPRegression (X ,y ,kernel = kern .copy ())
82147
83148 if (0 in modals ) and (dim - 1 in modals ):
84149 model .rbf .variance = modals [0 ]/ factor ** 2
85150 model .Gaussian_noise .variance = modals [dim - 1 ]/ factor ** 2
86151 else :
87- model = None
88-
152+ raise ValueError ( 'HMC failed. Possible unsuitable priors on kernels parameters leading to repetative samples.' )
153+
89154 for i in range (dim ):
90155 if i in modals :
91156 model .rbf .lengthscale [i ] = modals [1 + i ]/ factor
92157 else :
93158 model .rbf .lengthscale [i ] = lengthscales [i ]
94159
160+ if plot_kernel_posteriors :
161+ labels = ['RBF kernel variance' ]+ [f'RBF kernel lengthscale[x{ i } ]' for i in range (dim )] + ['RBF kernel noise' ]
162+ plot_posteriors (samples , labels , modals = modals , kdes = kdes )
163+
95164 else :
96165
97- kern = RBF (input_dim = dim , ARD = True )
98- model = GPRegression (X ,y ,kernel = kern .copy ())
99-
166+ kern = GPy . kern . RBF (input_dim = dim , ARD = True )
167+ model = GPy . models . GPRegression (X ,y ,kernel = kern .copy ())
168+
100169 # model.optimize_restarts(num_restarts=10,optimizer='lbfgs',verbose=False)
101170 model .optimize (optimizer = 'lbfgs' ,messages = False )
102-
103- return model
171+
172+ return model
0 commit comments