Coverage for contextualized/easy/tests.py: 99%

224 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-21 13:49 -0400

1"""" 

2Unit tests for Easy Networks. 

3""" 

4 

5import unittest 

6import numpy as np 

7import torch 

8from sklearn.metrics import roc_auc_score 

9 

10from contextualized.easy import ( 

11 ContextualizedMarkovNetworks, 

12 ContextualizedCorrelationNetworks, 

13 ContextualizedBayesianNetworks, 

14 ContextualizedRegressor, 

15 ContextualizedClassifier, 

16 ContextualGAMClassifier, 

17 ContextualGAMRegressor, 

18) 

19from contextualized.utils import DummyParamPredictor, DummyYPredictor 

20 

21 

22class TestEasyNetworks(unittest.TestCase): 

23 """ 

24 Test Easy Network models. 

25 """ 

26 

27 def __init__(self, *args, **kwargs): 

28 super().__init__(*args, **kwargs) 

29 

30 def _quicktest(self, model, C, X, **kwargs): 

31 print(f"{type(model)} quicktest") 

32 model.fit(C, X, max_epochs=0) 

33 err_init = model.measure_mses(C, X) 

34 model.fit(C, X, **kwargs) 

35 err_trained = model.measure_mses(C, X) 

36 W_pred = model.predict_networks(C) 

37 assert W_pred.shape == (C.shape[0], X.shape[1], X.shape[1]) 

38 assert np.mean(err_trained) < np.mean(err_init) 

39 

40 

41class TestContextualizedMarkovNetworks(TestEasyNetworks): 

42 """ 

43 Test Contextualized Markov Network models. 

44 """ 

45 

46 def setUp(self): 

47 """ 

48 Shared unit test setup code. 

49 """ 

50 np.random.seed(0) 

51 torch.manual_seed(0) 

52 self.n_samples = 100 

53 self.c_dim = 4 

54 self.x_dim = 5 

55 C = torch.rand((self.n_samples, self.c_dim)) - 0.5 

56 # TODO: Use graph utils to generate X from a network. 

57 X = torch.rand((self.n_samples, self.x_dim)) - 0.5 

58 self.C, self.X = C.numpy(), X.numpy() 

59 

60 def test_markov(self): 

61 """Test Case for ContextualizedMarkovNetworks.""" 

62 model = ContextualizedMarkovNetworks() 

63 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

64 self._quicktest( 

65 model, self.C, self.X, max_epochs=10, learning_rate=1e-3, val_split=0.5 

66 ) 

67 

68 model = ContextualizedMarkovNetworks(num_archetypes=16) 

69 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

70 

71 model = ContextualizedMarkovNetworks(encoder_type="ngam", num_archetypes=16) 

72 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

73 omegas = model.predict_precisions(self.C, individual_preds=False) 

74 assert np.shape(omegas) == (self.n_samples, self.x_dim, self.x_dim) 

75 omegas = model.predict_precisions(self.C, individual_preds=True) 

76 assert np.shape(omegas) == (1, self.n_samples, self.x_dim, self.x_dim) 

77 

78 

79class TestContextualizedCorrelationNetworks(TestEasyNetworks): 

80 """ 

81 Test Contextualized Correlation Network models. 

82 """ 

83 

84 def setUp(self): 

85 """ 

86 Shared unit test setup code. 

87 """ 

88 np.random.seed(0) 

89 torch.manual_seed(0) 

90 self.n_samples = 100 

91 self.c_dim = 4 

92 self.x_dim = 5 

93 C = torch.rand((self.n_samples, self.c_dim)) - 0.5 

94 # TODO: Use graph utils to generate X from a network. 

95 X = torch.rand((self.n_samples, self.x_dim)) - 0.5 

96 self.C, self.X = C.numpy(), X.numpy() 

97 

98 def test_correlation(self): 

99 """ 

100 Test Case for ContextualizedCorrelationNetworks. 

101 """ 

102 

103 model = ContextualizedCorrelationNetworks() 

104 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

105 self._quicktest( 

106 model, self.C, self.X, max_epochs=10, learning_rate=1e-3, val_split=0.5 

107 ) 

108 

109 model = ContextualizedCorrelationNetworks(num_archetypes=16) 

110 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

111 

112 model = ContextualizedCorrelationNetworks( 

113 encoder_type="ngam", num_archetypes=16 

114 ) 

115 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

116 rho = model.predict_correlation(self.C, squared=False) 

117 assert rho.shape == (1, self.n_samples, self.x_dim, self.x_dim) 

118 rho = model.predict_correlation(self.C, individual_preds=False, squared=False) 

119 assert rho.shape == (self.n_samples, self.x_dim, self.x_dim), rho.shape 

120 rho_squared = model.predict_correlation(self.C, squared=True) 

121 assert np.min(rho_squared) >= 0 

122 assert rho_squared.shape == (1, self.n_samples, self.x_dim, self.x_dim) 

123 

124 

125class TestContextualizedBayesianNetworks(TestEasyNetworks): 

126 """ 

127 Test Contextualized Bayesian Network models. 

128 """ 

129 

130 def setUp(self): 

131 """ 

132 Shared unit test setup code. 

133 """ 

134 np.random.seed(0) 

135 torch.manual_seed(0) 

136 self.n_samples = 100 

137 self.c_dim = 4 

138 self.x_dim = 5 

139 C = torch.rand((self.n_samples, self.c_dim)) - 0.5 

140 # TODO: Use graph utils to generate X from a network. 

141 X = torch.rand((self.n_samples, self.x_dim)) - 0.5 

142 self.C, self.X = C.numpy(), X.numpy() 

143 

144 def test_bayesian_factors(self): 

145 """Test case for ContextualizedBayesianNetworks.""" 

146 model = ContextualizedBayesianNetworks( 

147 encoder_type="ngam", num_archetypes=16, num_factors=2 

148 ) 

149 model.fit(self.C, self.X, max_epochs=10) 

150 networks = model.predict_networks(self.C, individual_preds=False) 

151 assert np.shape(networks) == (self.n_samples, self.x_dim, self.x_dim) 

152 networks = model.predict_networks(self.C, factors=True) 

153 assert np.shape(networks) == (self.n_samples, 2, 2) 

154 model = ContextualizedBayesianNetworks( 

155 encoder_type="ngam", num_archetypes=16, num_factors=2 

156 ) 

157 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

158 

159 def test_bayesian_default(self): 

160 model = ContextualizedBayesianNetworks() 

161 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

162 

163 def test_bayesian_val_split(self): 

164 model = ContextualizedBayesianNetworks() 

165 self._quicktest( 

166 model, self.C, self.X, max_epochs=10, learning_rate=1e-3, val_split=0.5 

167 ) 

168 

169 def test_bayesian_archetypes(self): 

170 model = ContextualizedBayesianNetworks(num_archetypes=16) 

171 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

172 

173 def test_bayesian_encoder(self): 

174 model = ContextualizedBayesianNetworks(encoder_type="ngam", num_archetypes=16) 

175 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

176 networks = model.predict_networks(self.C, individual_preds=False) 

177 assert np.shape(networks) == (self.n_samples, self.x_dim, self.x_dim) 

178 

179 model = ContextualizedBayesianNetworks(encoder_type="mlp", num_archetypes=16) 

180 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

181 networks = model.predict_networks(self.C, individual_preds=False) 

182 assert np.shape(networks) == (self.n_samples, self.x_dim, self.x_dim) 

183 

184 def test_bayesian_acyclicity(self): 

185 model = ContextualizedBayesianNetworks( 

186 archetype_dag_loss_type="DAGMA", num_archetypes=16 

187 ) 

188 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

189 networks = model.predict_networks(self.C, individual_preds=False) 

190 assert np.shape(networks) == (self.n_samples, self.x_dim, self.x_dim) 

191 

192 model = ContextualizedBayesianNetworks( 

193 archetype_dag_loss_type="poly", num_archetypes=16 

194 ) 

195 self._quicktest(model, self.C, self.X, max_epochs=10, learning_rate=1e-3) 

196 networks = model.predict_networks(self.C, individual_preds=False) 

197 assert np.shape(networks) == (self.n_samples, self.x_dim, self.x_dim) 

198 

199 

200class TestEasyClassifiers(unittest.TestCase): 

201 """ 

202 Test Easy Classifier models. 

203 """ 

204 

205 def __init__(self, *args, **kwargs): 

206 super().__init__(*args, **kwargs) 

207 

208 def _quicktest(self, model, C, X, Y, **kwargs): 

209 print(f"{type(model)} quicktest") 

210 model.fit(C, X, Y, max_epochs=0) 

211 y_preds_init = model.predict(C, X) 

212 y_proba_preds_init = model.predict_proba(C, X)[:, :, 1] 

213 err_init = (Y != y_preds_init).sum() 

214 roc_init = roc_auc_score(Y, y_proba_preds_init) 

215 model.fit(C, X, Y, **kwargs) 

216 beta_preds, mu_preds = model.predict_params(C) 

217 assert beta_preds.shape == (X.shape[0], Y.shape[1], X.shape[1]) 

218 assert mu_preds.shape == (X.shape[0], Y.shape[1]) 

219 assert not np.any(np.isnan(beta_preds)) 

220 assert not np.any(np.isnan(mu_preds)) 

221 y_preds = model.predict(C, X) 

222 y_proba_preds = model.predict_proba(C, X)[:, :, 1] 

223 assert y_preds.shape == Y.shape 

224 assert y_proba_preds.shape == Y.shape 

225 err_trained = (Y != y_preds).sum() 

226 roc_trained = roc_auc_score(Y, y_proba_preds) 

227 assert err_trained < err_init 

228 assert roc_trained > roc_init 

229 print(err_trained, err_init) 

230 

231 def test_classifier(self): 

232 """Test Case for ContextualizedClassifier.""" 

233 

234 n_samples = 1000 

235 c_dim = 100 

236 x_dim = 3 

237 y_dim = 1 

238 C = np.random.uniform(-1, 1, size=(n_samples, c_dim)) 

239 X = np.random.uniform(-1, 1, size=(n_samples, x_dim)) 

240 Y = np.random.binomial(1, 0.5, size=(n_samples, y_dim)) 

241 

242 model = ContextualizedClassifier(alpha=1e-1, encoder_type="mlp") 

243 self._quicktest(model, C, X, Y, max_epochs=10, es_patience=float("inf")) 

244 

245 def test_gam_classifier(self): 

246 """Test Case for ContextualGAMClassifier.""" 

247 

248 n_samples = 1000 

249 c_dim = 100 

250 x_dim = 3 

251 y_dim = 1 

252 C = np.random.uniform(-1, 1, size=(n_samples, c_dim)) 

253 X = np.random.uniform(-1, 1, size=(n_samples, x_dim)) 

254 Y = np.random.binomial(1, 0.5, size=(n_samples, y_dim)) 

255 

256 model = ContextualGAMClassifier(alpha=1e-1, encoder_type="mlp") 

257 self._quicktest(model, C, X, Y, max_epochs=10, es_patience=float("inf")) 

258 

259 

260class TestEasyRegression(unittest.TestCase): 

261 """ 

262 Test Easy Regression models. 

263 """ 

264 

265 def __init__(self, *args, **kwargs): 

266 super().__init__(*args, **kwargs) 

267 

268 def _quicktest(self, model, C, X, Y, **kwargs): 

269 print(f"{type(model)} quicktest") 

270 model.fit(C, X, Y, max_epochs=0) 

271 err_init = np.linalg.norm(Y - model.predict(C, X), ord=2) 

272 model.fit(C, X, Y, **kwargs) 

273 beta_preds, mu_preds = model.predict_params(C) 

274 try: 

275 y_dim = Y.shape[1] 

276 except IndexError: 

277 y_dim = 1 

278 assert beta_preds.shape == (X.shape[0], y_dim, X.shape[1]) 

279 assert mu_preds.shape == (X.shape[0], y_dim) 

280 y_preds = model.predict(C, X) 

281 assert y_preds.shape == (len(Y), y_dim) 

282 err_trained = np.linalg.norm(Y - np.squeeze(y_preds), ord=2) 

283 assert err_trained < err_init 

284 print(err_trained, err_init) 

285 

286 def test_regressor(self): 

287 """Test Case for ContextualizedRegressor.""" 

288 n_samples = 1000 

289 c_dim = 2 

290 x_dim = 3 

291 y_dim = 2 

292 C = torch.rand((n_samples, c_dim)) - 0.5 

293 beta_1 = C.sum(axis=1).unsqueeze(-1) ** 2 

294 beta_2 = -C.sum(axis=1).unsqueeze(-1) 

295 b_1 = C[:, 0].unsqueeze(-1) 

296 b_2 = C[:, 1].unsqueeze(-1) 

297 X = torch.rand((n_samples, x_dim)) - 0.5 

298 outcome_1 = X[:, 0].unsqueeze(-1) * beta_1 + b_1 

299 outcome_2 = X[:, 1].unsqueeze(-1) * beta_2 + b_2 

300 Y = torch.cat((outcome_1, outcome_2), axis=1) 

301 

302 C, X, Y = C.numpy(), X.numpy(), Y.numpy() 

303 

304 # Naive Multivariate 

305 parambase = DummyParamPredictor((y_dim, x_dim), (y_dim, 1)) 

306 ybase = DummyYPredictor((y_dim, 1)) 

307 model = ContextualizedRegressor( 

308 base_param_predictor=parambase, base_y_predictor=ybase 

309 ) 

310 self._quicktest( 

311 model, C, X, Y, max_epochs=10, learning_rate=1e-3, es_patience=float("inf") 

312 ) 

313 

314 model = ContextualizedRegressor(num_archetypes=0) 

315 self._quicktest(model, C, X, Y, max_epochs=10, es_patience=float("inf")) 

316 

317 model = ContextualizedRegressor(num_archetypes=4) 

318 self._quicktest(model, C, X, Y, max_epochs=10, es_patience=float("inf")) 

319 

320 # With regularization 

321 model = ContextualizedRegressor( 

322 num_archetypes=4, alpha=1e-1, l1_ratio=0.5, mu_ratio=0.1 

323 ) 

324 self._quicktest(model, C, X, Y, max_epochs=10, es_patience=float("inf")) 

325 

326 # With bootstrap 

327 model = ContextualizedRegressor( 

328 num_archetypes=4, alpha=1e-1, l1_ratio=0.5, mu_ratio=0.1 

329 ) 

330 self._quicktest( 

331 model, 

332 C, 

333 X, 

334 Y, 

335 max_epochs=10, 

336 n_bootstraps=2, 

337 learning_rate=1e-3, 

338 es_patience=float("inf"), 

339 ) 

340 

341 # Check smaller Y. 

342 model = ContextualizedRegressor( 

343 num_archetypes=4, alpha=1e-1, l1_ratio=0.5, mu_ratio=0.1 

344 ) 

345 self._quicktest( 

346 model, 

347 C, 

348 X, 

349 Y[:, 0], 

350 max_epochs=10, 

351 n_bootstraps=2, 

352 learning_rate=1e-3, 

353 es_patience=float("inf"), 

354 ) 

355 

356 def test_gam_regressor(self): 

357 """Test Case for ContextualGAMRegressor.""" 

358 n_samples = 100 

359 c_dim = 2 

360 x_dim = 3 

361 y_dim = 2 

362 C = torch.rand((n_samples, c_dim)) - 0.5 

363 beta_1 = C.sum(axis=1).unsqueeze(-1) ** 2 

364 beta_2 = -C.sum(axis=1).unsqueeze(-1) 

365 b_1 = C[:, 0].unsqueeze(-1) 

366 b_2 = C[:, 1].unsqueeze(-1) 

367 X = torch.rand((n_samples, x_dim)) - 0.5 

368 outcome_1 = X[:, 0].unsqueeze(-1) * beta_1 + b_1 

369 outcome_2 = X[:, 1].unsqueeze(-1) * beta_2 + b_2 

370 Y = torch.cat((outcome_1, outcome_2), axis=1) 

371 

372 C, X, Y = C.numpy(), X.numpy(), Y.numpy() 

373 

374 model = ContextualGAMRegressor() 

375 self._quicktest( 

376 model, C, X, Y, max_epochs=10, learning_rate=1e-3, es_patience=float("inf") 

377 ) 

378 

379 

380if __name__ == "__main__": 

381 unittest.main()