pcntoolkit 0.32.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,333 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Fri Nov 22 14:41:07 2019
5
+
6
+ @author: seykia
7
+ """
8
+
9
+ from __future__ import print_function
10
+ from __future__ import division
11
+
12
+ import os
13
+ import sys
14
+ import numpy as np
15
+ import torch
16
+ from torch import nn, optim
17
+ from torch.nn import functional as F
18
+ from sklearn.linear_model import LinearRegression
19
+ from sklearn.preprocessing import MinMaxScaler
20
+ import pickle
21
+
22
+ try: # run as a package if installed
23
+ from pcntoolkit.normative_model.normbase import NormBase
24
+ from pcntoolkit.model.NPR import NPR, np_loss
25
+ except ImportError:
26
+ pass
27
+
28
+ path = os.path.abspath(os.path.dirname(__file__))
29
+ if path not in sys.path:
30
+ sys.path.append(path)
31
+ del path
32
+
33
+ from model.NPR import NPR, np_loss
34
+ from norm_base import NormBase
35
+
36
+
37
+ class struct(object):
38
+ pass
39
+
40
+
41
+ class Encoder(nn.Module):
42
+ """
43
+ Encoder module for the Neural Process Regression model.
44
+
45
+ This module is responsible for encoding the input data into a latent representation.
46
+ It is a part of the Neural Process Regression (NPR) model and is implemented as a PyTorch module.
47
+
48
+ :param x: Input data matrix.
49
+ :param y: Target values.
50
+ :param args: A dictionary-like object containing the following attributes:
51
+ - r_dim: Dimension of the latent representation.
52
+ - z_dim: Dimension of the latent variable.
53
+ - hidden_neuron_num: Number of neurons in the hidden layers.
54
+ """
55
+
56
+ def __init__(self, x, y, args):
57
+ """
58
+ Initialize the Encoder module.
59
+
60
+ :param x: Input data matrix.
61
+ :param y: Target values.
62
+ :param args: A dictionary-like object containing the following attributes:
63
+ - r_dim: Dimension of the latent representation.
64
+ - z_dim: Dimension of the latent variable.
65
+ - hidden_neuron_num: Number of neurons in the hidden layers.
66
+ """
67
+ super(Encoder, self).__init__()
68
+ self.r_dim = args.r_dim
69
+ self.z_dim = args.z_dim
70
+ self.hidden_neuron_num = args.hidden_neuron_num
71
+ self.h_1 = nn.Linear(x.shape[1] + y.shape[1], self.hidden_neuron_num)
72
+ self.h_2 = nn.Linear(self.hidden_neuron_num, self.hidden_neuron_num)
73
+ self.h_3 = nn.Linear(self.hidden_neuron_num, self.r_dim)
74
+
75
+ def forward(self, x, y):
76
+ """
77
+ Forward pass of the Encoder module.
78
+
79
+ :param x: Input data matrix.
80
+ :param y: Target values.
81
+ :return: The latent representation of the input data.
82
+ """
83
+
84
+ x_y = torch.cat([x, y], dim=2)
85
+ x_y = F.relu(self.h_1(x_y))
86
+ x_y = F.relu(self.h_2(x_y))
87
+ x_y = F.relu(self.h_3(x_y))
88
+ r = torch.mean(x_y, dim=1)
89
+ return r
90
+
91
+
92
+ class Decoder(nn.Module):
93
+ """
94
+ Decoder module for the Neural Process Regression model.
95
+
96
+ This module is responsible for decoding the latent representation into the target values.
97
+ It is a part of the Neural Process Regression (NPR) model and is implemented as a PyTorch module.
98
+
99
+ :param x: Input data matrix.
100
+ :param y: Target values.
101
+ :param args: A dictionary-like object containing the following attributes:
102
+ - r_dim: Dimension of the latent representation.
103
+ - z_dim: Dimension of the latent variable.
104
+ - hidden_neuron_num: Number of neurons in the hidden layers.
105
+ """
106
+
107
+ def __init__(self, x, y, args):
108
+ """
109
+ Initialize the Decoder module.
110
+
111
+ :param x: Input data matrix.
112
+ :param y: Target values.
113
+ :param args: A dictionary-like object containing the following attributes:
114
+ - r_dim: Dimension of the latent representation.
115
+ - z_dim: Dimension of the latent variable.
116
+ - hidden_neuron_num: Number of neurons in the hidden layers.
117
+ """
118
+ super(Decoder, self).__init__()
119
+ self.r_dim = args.r_dim
120
+ self.z_dim = args.z_dim
121
+ self.hidden_neuron_num = args.hidden_neuron_num
122
+
123
+ self.g_1 = nn.Linear(self.z_dim, self.hidden_neuron_num)
124
+ self.g_2 = nn.Linear(self.hidden_neuron_num, self.hidden_neuron_num)
125
+ self.g_3 = nn.Linear(self.hidden_neuron_num, y.shape[1])
126
+
127
+ self.g_1_84 = nn.Linear(self.z_dim, self.hidden_neuron_num)
128
+ self.g_2_84 = nn.Linear(self.hidden_neuron_num, self.hidden_neuron_num)
129
+ self.g_3_84 = nn.Linear(self.hidden_neuron_num, y.shape[1])
130
+
131
+ def forward(self, z_sample):
132
+ """
133
+ Forward pass of the Decoder module.
134
+
135
+ :param z_sample: Sampled latent variable.
136
+ :return: The predicted target values.
137
+ """
138
+ z_hat = F.relu(self.g_1(z_sample))
139
+ z_hat = F.relu(self.g_2(z_hat))
140
+ y_hat = torch.sigmoid(self.g_3(z_hat))
141
+
142
+ z_hat_84 = F.relu(self.g_1(z_sample))
143
+ z_hat_84 = F.relu(self.g_2_84(z_hat_84))
144
+ y_hat_84 = torch.sigmoid(self.g_3_84(z_hat_84))
145
+
146
+ return y_hat, y_hat_84
147
+
148
+
149
+ class NormNP(NormBase):
150
+ """ Classical GPR-based normative modelling approach
151
+ """
152
+
153
+ def __init__(self, X, y, configparam=None):
154
+ """
155
+ Initialize the NormNP object.
156
+
157
+ This function initializes the NormNP object with the given arguments. It requires a data matrix 'X' and target 'y'.
158
+ It also takes an optional 'configparam' which is a path to a pickle file containing configuration parameters.
159
+ If 'configparam' is not provided, default values are used for the configuration parameters.
160
+
161
+ :param X: Data matrix.
162
+ :param y: Target values.
163
+ :param configparam: Path to a pickle file containing configuration parameters. Optional.
164
+ """
165
+ self.configparam = configparam
166
+ if configparam is not None:
167
+ with open(configparam, 'rb') as handle:
168
+ config = pickle.load(handle)
169
+ args = struct()
170
+ if 'batch_size' in config:
171
+ args.batch_size = config['batch_size']
172
+ else:
173
+ args.batch_size = 10
174
+ if 'epochs' in config:
175
+ args.epochs = config['epochs']
176
+ else:
177
+ args.epochs = 100
178
+ if 'device' in config:
179
+ args.device = config['device']
180
+ else:
181
+ args.device = torch.device('cpu')
182
+ if 'm' in config:
183
+ args.m = config['m']
184
+ else:
185
+ args.m = 200
186
+ if 'hidden_neuron_num' in config:
187
+ args.hidden_neuron_num = config['hidden_neuron_num']
188
+ else:
189
+ args.hidden_neuron_num = 10
190
+ if 'r_dim' in config:
191
+ args.r_dim = config['r_dim']
192
+ else:
193
+ args.r_dim = 5
194
+ if 'z_dim' in config:
195
+ args.z_dim = config['z_dim']
196
+ else:
197
+ args.z_dim = 3
198
+ if 'nv' in config:
199
+ args.nv = config['nv']
200
+ else:
201
+ args.nv = 0.01
202
+ else:
203
+ args = struct()
204
+ args.batch_size = 10
205
+ args.epochs = 100
206
+ args.device = torch.device('cpu')
207
+ args.m = 200
208
+ args.hidden_neuron_num = 10
209
+ args.r_dim = 5
210
+ args.z_dim = 3
211
+ args.nv = 0.01
212
+
213
+ if y is not None:
214
+ if y.ndim == 1:
215
+ y = y.reshape(-1, 1)
216
+ self.args = args
217
+ self.encoder = Encoder(X, y, args)
218
+ self.decoder = Decoder(X, y, args)
219
+ self.model = NPR(self.encoder, self.decoder, args)
220
+
221
+ @property
222
+ def n_params(self):
223
+ return 1
224
+
225
+ @property
226
+ def neg_log_lik(self):
227
+ return -1
228
+
229
+ def estimate(self, X, y):
230
+ """
231
+ Estimate the parameters of the Neural Process Regression model.
232
+
233
+ This function estimates the parameters of the Neural Process Regression (NPR) model given the data matrix 'X' and target 'y'.
234
+ It uses mini-batch gradient descent for optimization and updates the model parameters in place.
235
+
236
+ :param X: Data matrix.
237
+ :param y: Target values. If y is one-dimensional, it is reshaped to (-1, 1).
238
+ :return: The instance of the norm_np object with updated parameters.
239
+ """
240
+ if y.ndim == 1:
241
+ y = y.reshape(-1, 1)
242
+ sample_num = X.shape[0]
243
+ batch_size = self.args.batch_size
244
+ factor_num = self.args.m
245
+ mini_batch_num = int(np.floor(sample_num/batch_size))
246
+ device = self.args.device
247
+
248
+ self.scaler = MinMaxScaler()
249
+ y = self.scaler.fit_transform(y)
250
+
251
+ self.reg = []
252
+ for i in range(factor_num):
253
+ self.reg.append(LinearRegression())
254
+ # int(sample_num/10))
255
+ idx = np.random.randint(0, sample_num, sample_num)
256
+ self.reg[i].fit(X[idx, :], y[idx, :])
257
+
258
+ x_context = np.zeros([sample_num, factor_num, X.shape[1]])
259
+ y_context = np.zeros([sample_num, factor_num, 1])
260
+
261
+ s = X.std(axis=0)
262
+ for j in range(factor_num):
263
+ x_context[:, j, :] = X + \
264
+ np.sqrt(self.args.nv) * s * \
265
+ np.random.randn(X.shape[0], X.shape[1])
266
+ y_context[:, j, :] = self.reg[j].predict(x_context[:, j, :])
267
+
268
+ x_context = torch.tensor(x_context, device=device, dtype=torch.float)
269
+ y_context = torch.tensor(y_context, device=device, dtype=torch.float)
270
+
271
+ x_all = torch.tensor(np.expand_dims(X, axis=1),
272
+ device=device, dtype=torch.float)
273
+ y_all = torch.tensor(
274
+ y.reshape(-1, 1, y.shape[1]), device=device, dtype=torch.float)
275
+
276
+ self.model.train()
277
+ epochs = [int(self.args.epochs/4), int(self.args.epochs/2), int(self.args.epochs/5),
278
+ int(self.args.epochs-self.args.epochs/4-self.args.epochs/2-self.args.epochs/5)]
279
+ k = 1
280
+ for e in range(len(epochs)):
281
+ optimizer = optim.Adam(self.model.parameters(), lr=10**(-e-2))
282
+ for j in range(epochs[e]):
283
+ train_loss = 0
284
+ for i in range(mini_batch_num):
285
+ optimizer.zero_grad()
286
+ idx = np.arange(i*batch_size, (i+1)*batch_size)
287
+ y_hat, y_hat_84, z_all, z_context, dummy, dummy = self.model(
288
+ x_context[idx, :, :], y_context[idx, :, :], x_all[idx, :, :], y_all[idx, :, :])
289
+ loss = np_loss(y_hat, y_hat_84,
290
+ y_all[idx, 0, :], z_all, z_context)
291
+ loss.backward()
292
+ train_loss += loss.item()
293
+ optimizer.step()
294
+ print('Epoch: %d, Loss:%f' % (k, train_loss))
295
+ k += 1
296
+ return self
297
+
298
+ def predict(self, Xs, X=None, Y=None, theta=None):
299
+ """
300
+ Predict the target values for the given test data.
301
+
302
+ This function predicts the target values for the given test data 'Xs' using the Neural Process Regression (NPR) model.
303
+
304
+ :param Xs: Test data matrix.
305
+ :param X: Not used in this function.
306
+ :param Y: Not used in this function.
307
+ :param theta: Not used in this function.
308
+ :return: A tuple containing the predicted target values and the marginal variances for the test data.
309
+ """
310
+ sample_num = Xs.shape[0]
311
+ factor_num = self.args.m
312
+ x_context_test = np.zeros([sample_num, factor_num, Xs.shape[1]])
313
+ y_context_test = np.zeros([sample_num, factor_num, 1])
314
+ for j in range(factor_num):
315
+ x_context_test[:, j, :] = Xs
316
+ y_context_test[:, j, :] = self.reg[j].predict(
317
+ x_context_test[:, j, :])
318
+ x_context_test = torch.tensor(
319
+ x_context_test, device=self.args.device, dtype=torch.float)
320
+ y_context_test = torch.tensor(
321
+ y_context_test, device=self.args.device, dtype=torch.float)
322
+ self.model.eval()
323
+ with torch.no_grad():
324
+ y_hat, y_hat_84, z_all, z_context, y_sigma, y_sigma_84 = self.model(
325
+ x_context_test, y_context_test, n=100)
326
+
327
+ y_hat = self.scaler.inverse_transform(y_hat.cpu().numpy())
328
+ y_hat_84 = self.scaler.inverse_transform(y_hat_84.cpu().numpy())
329
+ y_sigma = y_sigma.cpu().numpy() * (self.scaler.data_max_ - self.scaler.data_min_)
330
+ y_sigma_84 = y_sigma_84.cpu().numpy() * (self.scaler.data_max_ - self.scaler.data_min_)
331
+ sigma_al = y_hat - y_hat_84
332
+ # , z_context[0].cpu().numpy(), z_context[1].cpu().numpy()
333
+ return y_hat.squeeze(), (y_sigma**2 + sigma_al**2).squeeze()
@@ -0,0 +1,109 @@
1
+ from __future__ import print_function
2
+ from __future__ import division
3
+
4
+ import os
5
+ import sys
6
+ import numpy as np
7
+
8
+ try: # run as a package if installed
9
+ from pcntoolkit.normative_model.norm_base import NormBase
10
+ from pcntoolkit.model.rfa import GPRRFA
11
+ except ImportError:
12
+ pass
13
+
14
+ path = os.path.abspath(os.path.dirname(__file__))
15
+ if path not in sys.path:
16
+ sys.path.append(path)
17
+ del path
18
+
19
+ from model.rfa import GPRRFA
20
+ from norm_base import NormBase
21
+
22
+
23
+ class NormRFA(NormBase):
24
+ """ Classical GPR-based normative modelling approach
25
+ """
26
+
27
+ def __init__(self, X, y=None, theta=None, n_feat=None):
28
+ """
29
+ Initialize the NormRFA object.
30
+
31
+ This function initializes the NormRFA object with the given arguments. It requires a data matrix 'X' and optionally takes a target 'y', parameters 'theta', and the number of random features 'n_feat'.
32
+ It initializes the Gaussian Process Regression with Random Feature Approximation (GPRRFA) model and sets the initial parameters.
33
+
34
+ :param X: Data matrix. Must be specified.
35
+ :param y: Not used.
36
+ :param theta: Parameters for the model. Optional.
37
+ :param n_feat: Number of random features for the GPRRFA model. Optional.
38
+ :raises ValueError: If 'X' is not specified.
39
+ """
40
+ if (X is not None):
41
+ if n_feat is None:
42
+ print("initialising RFA")
43
+ else:
44
+ print("initialising RFA with", n_feat, "random features")
45
+ self.gprrfa = GPRRFA(theta, X, n_feat=n_feat)
46
+ self._n_params = self.gprrfa.get_n_params(X)
47
+ else:
48
+ raise ValueError('Covariates not specified')
49
+ return
50
+
51
+ if theta is None:
52
+ self.theta0 = np.zeros(self._n_params)
53
+ else:
54
+ if len(theta) == self._n_params:
55
+ self.theta0 = theta
56
+ else:
57
+ raise ValueError('hyperparameter vector has incorrect size')
58
+
59
+ self.theta = self.theta0
60
+
61
+ @property
62
+ def n_params(self):
63
+
64
+ return self._n_params
65
+
66
+ @property
67
+ def neg_log_lik(self):
68
+ return self.gprrfa.nlZ
69
+
70
+ def estimate(self, X, y, theta=None):
71
+ """
72
+ Estimate the parameters of the Random Feature Approximation model.
73
+
74
+ This function estimates the parameters of the Random Feature Approximation (RFA) model given the data matrix 'X' and target 'y'.
75
+ If 'theta' is provided, it is used as the initial parameters for estimation.
76
+ Otherwise, the current value of 'self.theta0' is used.
77
+
78
+ :param X: Data matrix.
79
+ :param y: Target values.
80
+ :param theta: Initial parameters for estimation. Optional.
81
+ :return: The instance of the NormRFA object with updated parameters.
82
+ """
83
+ if theta is None:
84
+ theta = self.theta0
85
+ self.gprrfa = GPRRFA(theta, X, y)
86
+ self.theta = self.gprrfa.estimate(theta, X, y)
87
+
88
+ return self
89
+
90
+ def predict(self, Xs, X, y, theta=None):
91
+ """
92
+ Predict the target values for the given test data.
93
+
94
+ This function predicts the target values for the given test data 'Xs' using the Random Feature Approximation (RFA) model.
95
+ If 'X' and 'y' are provided, they are used to update the model before prediction.
96
+ If 'theta' is provided, it is used as the parameters for prediction.
97
+ Otherwise, the current value of 'self.theta' is used.
98
+
99
+ :param Xs: Test data matrix.
100
+ :param X: Training data matrix.
101
+ :param y: Training target values.
102
+ :param theta: Parameters for prediction. Optional.
103
+ :return: A tuple containing the predicted target values and the marginal variances for the test data.
104
+ """
105
+ if theta is None:
106
+ theta = self.theta
107
+ yhat, s2 = self.gprrfa.predict(theta, X, y, Xs)
108
+
109
+ return yhat, s2
@@ -0,0 +1,29 @@
1
+ try: # run as a package if installed
2
+ from pcntoolkit.normative_model.norm_blr import NormBLR
3
+ from pcntoolkit.normative_model.norm_gpr import NormGPR
4
+ from pcntoolkit.normative_model.norm_rfa import NormRFA
5
+ from pcntoolkit.normative_model.norm_hbr import NormHBR
6
+ from pcntoolkit.normative_model.norm_np import NormNP
7
+ except:
8
+ from norm_blr import NormBLR
9
+ from norm_gpr import NormGPR
10
+ from norm_rfa import NormRFA
11
+ from norm_hbr import NormHBR
12
+ from norm_np import NormNP
13
+
14
+
15
+ def norm_init(X, y=None, theta=None, alg='gpr', **kwargs):
16
+ if alg == 'gpr':
17
+ nm = NormGPR(X=X, y=y, theta=theta, **kwargs)
18
+ elif alg == 'blr':
19
+ nm = NormBLR(X=X, y=y, theta=theta, **kwargs)
20
+ elif alg == 'rfa':
21
+ nm = NormRFA(X=X, y=y, theta=theta, **kwargs)
22
+ elif alg == 'hbr':
23
+ nm = NormHBR(**kwargs)
24
+ elif alg == 'np':
25
+ nm = NormNP(X=X, y=y, **kwargs)
26
+ else:
27
+ raise ValueError("Algorithm " + alg + " not known.")
28
+
29
+ return nm