def train_exact_gp_model_average(trainX, trainY, testX, testY, kind, model_kwargs, train_kwargs, devices=('cpu',), skip_posterior_variances=False, evaluate_on_train=True, output_device=None, record_pred_unc=False): from fitting.sampling import ModelAverage model_kwargs = copy.deepcopy(model_kwargs) train_kwargs = copy.deepcopy(train_kwargs) if len(devices) > 1: raise ValueError("CGP not implemented for multi GPUs (yet?)") if str(devices[0]) != 'cpu': torch.cuda.set_device(torch.device(devices[0])) devices = [torch.device(device) for device in devices] if output_device is None: output_device = devices[0] else: output_device = torch.device(output_device) trainX = trainX.to(output_device) trainY = trainY.to(output_device) testX = testX.to(output_device) testY = testY.to(output_device) predictions, log_mlls = [], [] varying_params = model_kwargs.pop('varying_params') k = list(varying_params.keys())[0] for i in range(len(varying_params[k])): for k, v in varying_params.items(): model_kwargs[k] = v[i] metrics, pred_mean, model = train_exact_gp(trainX, trainY, testX, testY, kind, model_kwargs, train_kwargs, devices=devices, skip_posterior_variances=skip_posterior_variances, skip_random_restart=True, evaluate_on_train=False) log_mlls.append(-metrics['prior_train_nmll']) model.eval() predictions.append(model(testX)) test_outputs = ModelAverage(predictions, log_mlls) model_metrics = dict() with torch.no_grad(): if not skip_posterior_variances: model_metrics['test_nll'] = -test_outputs.log_prob(testY).item() # TODO: implement confidence region method for model average object. model_metrics['sampled_mean_mse'] = mean_squared_error(test_outputs.sample_mean(), testY) model_metrics['normal_mean_mse'] = mean_squared_error(test_outputs.mean(), testY) # model_metrics['state_dict_file'] = _save_state_dict(model) return model_metrics, test_outputs.mean().to('cpu'), None
def train_compressed_gp(trainX, trainY, testX, testY, model_kwargs, train_kwargs, devices=('cpu',), skip_posterior_variances=False, evaluate_on_train=True, output_device=None, record_pred_unc=False): from fitting.sampling import CGPSampler d = trainX.shape[-1] if len(devices) > 1: raise ValueError("CGP not implemented for multi GPUs (yet?)") if str(devices[0]) != 'cpu': torch.cuda.set_device(torch.device(devices[0])) devices = [torch.device(device) for device in devices] if output_device is None: output_device = devices[0] else: output_device = torch.device(output_device) trainX = trainX.to(output_device) trainY = trainY.to(output_device) testX = testX.to(output_device) testY = testY.to(output_device) # Pack all of the kwargs into one object... maybe not the best idea. model = CGPSampler(trainX, trainY, **model_kwargs, **train_kwargs) model_metrics = dict() with torch.no_grad(): if evaluate_on_train: train_outputs = model.pred(trainX) model_metrics['train_mse'] = mean_squared_error(train_outputs.mean(), trainY) test_outputs = model.pred(testX) if not skip_posterior_variances: if evaluate_on_train: model_metrics['train_nll'] = -train_outputs.log_prob(trainY).item() model_metrics['test_nll'] = -test_outputs.log_prob(testY).item() # TODO: implement confidence region method for model average object. model_metrics['sampled_mean_mse'] = mean_squared_error(test_outputs.sample_mean(), testY) model_metrics['normal_mean_mse'] = mean_squared_error(test_outputs.mean(), testY) # model_metrics['state_dict_file'] = _save_state_dict(model) return model_metrics, test_outputs.mean().to('cpu'), model
def train_ppr_gp(trainX, trainY, testX, testY, model_kwargs, train_kwargs, device='cpu', skip_posterior_variances=False): model_kwargs = copy.copy(model_kwargs) train_kwargs = copy.copy(train_kwargs) d = trainX.shape[-1] device = torch.device(device) trainX = trainX.to(device) trainY = trainY.to(device) testX = testX.to(device) testY = testY.to(device) kernel_type = model_kwargs.pop('kernel_type', 'RBF') if kernel_type == 'RBF': kernels = [RBFKernel() for _ in range(10)] elif kernel_type == 'Matern': kernels = [MaternKernel(nu=1.5) for _ in range(10)] else: raise ValueError("Unknown kernel type") if len(model_kwargs) > 0: warnings.warn("Not all model kwargs are used: {}".format(list(model_kwargs.keys()))) optimizer_ = _map_to_optim(train_kwargs.pop('optimizer')) model = learn_projections(kernels, trainX, trainY, optimizer=optimizer_, **train_kwargs) likelihood = model.likelihood mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model) model.eval() likelihood.eval() mll.eval() model_metrics = dict() with torch.no_grad(): model.train() # consider prior for evaluation on train dataset likelihood.train() train_outputs = model(trainX) model_metrics['prior_train_nmll'] = -mll(train_outputs, trainY).item() with gpytorch.settings.skip_posterior_variances(skip_posterior_variances): model.eval() # Now consider posterior distributions likelihood.eval() train_outputs = model(trainX) test_outputs = model(testX) if not skip_posterior_variances: model_metrics['train_nll'] = -likelihood(train_outputs).log_prob( trainY).item() model_metrics['test_nll'] = -likelihood(test_outputs).log_prob( testY).item() model_metrics['train_mse'] = mean_squared_error(train_outputs.mean, trainY) model_metrics['state_dict_file'] = _save_state_dict(model) return model_metrics, test_outputs.mean.to('cpu'), model
def benchmark_on_n_pts(n_pts, create_model_func, target_func, ho_x, ho_y, fit=True, repeats=3, max_iter=1000, return_model=False, verbose=0, checkpoint=True, print_freq=1, use_chol=False, **kwargs): dims = ho_x.shape[1] # if n_pts > 20: # ho_x = ho_x.to(device) # ho_y = ho_y.to(device) rep_mses = [] models = [] mlls = [] for i in range(repeats): # Don't edit the master copies fo the hold-out dataset test_ho_x = torch.empty_like(ho_x).copy_(ho_x) test_ho_y = torch.empty_like(ho_y).copy_(ho_y) # test_ho_x = ho_x.copy_() # test_ho_y = ho_y.copy_() # Create the data. data = torch.rand(n_pts, dims) * 4 - 2 y = target_func(data) + torch.randn(n_pts) * 0.01 # Normalize by TEST in this case for all methods for more accurate comparison m = ho_x.mean(dim=0) s = ho_x.std(dim=0) data = (data - m) / s test_ho_x = (test_ho_x - m) / s # Do the same for Ys. m = ho_y.mean() s = ho_y.std() y = (y - m) / s test_ho_y = (test_ho_y - m) / s # Create the model now. model = create_model_func(data, y, **kwargs) # Put things on the GPU if necessary if n_pts > 20: test_ho_x = test_ho_x.to(device) test_ho_y = test_ho_y.to(device) model = model.to(device) data = data.to(device) y = y.to(device) fast = not use_chol with gp_set.fast_computations(fast, fast, fast), gp_set.max_cg_iterations(10_000): with gp_set.cg_tolerance(0.001), gp_set.eval_cg_tolerance( 0.0005), gp_set.memory_efficient(True): if fit: mll = ExactMarginalLogLikelihood(model.likelihood, model) train_to_convergence(model, data, y, torch.optim.Adam, objective=mll, checkpoint=checkpoint, max_iter=max_iter, print_freq=print_freq, verbose=verbose) model.eval() with torch.no_grad(): mse = mean_squared_error(model(test_ho_x).mean, test_ho_y) print(i, mse) rep_mses.append(mse) if return_model: models.append(model) mlls.append(mll) else: del mll del model del data del y
def run_experiment(training_routine: Callable, training_options: Dict, dataset: Union[str, pd.DataFrame], split: float, cv: bool, addl_metrics: Dict = {}, repeats=1, error_repeats=10, normalize_using_train=True, chosen_fold=0, print_to_console=True): """Main function to run a model on a dataset. This function is intended to take a training routine (implicitly instantiates a model and trains it), options for said training routine, any metrics that should be run in addition to negative log likelihood (if applicable) and mean squared error given in {'name': function} format, a dataset name/dataframe, a fraction determining the train/test split of the data, a bool that determines whether full CV is used (or whether a single train/test split is used), and finally how many times to repeat each fitting/evaluating step in each fold. The output is a dataframe of the results. Note that if the dataset if provided, it is assumed to be sufficiently shuffled already. :param training_routine: :param training_options: :param addl_metrics: :param dataset: :param split: :param cv: :return: results_list """ if isinstance(dataset, str): dataset = load_dataset(dataset) cols = list(dataset.columns) features = [x for x in cols if (x != 'target' and x.lower() != 'index')] fold_starts = _determine_folds(split, dataset) n_folds = len(fold_starts) - 1 results_list = [] t0 = time.time() for fold in range(n_folds): if not cv and fold != chosen_fold: # only do one fold if you're not doing CV continue train, test = _access_fold(dataset, fold_starts, fold) if normalize_using_train: train, test = _normalize_by_train(train, test) succeed = False n_errors = 0 while not succeed and n_errors < error_repeats: try: trainX = torch.tensor(train[features].values, dtype=torch.float).contiguous() trainY = torch.tensor(train['target'].values, dtype=torch.float).contiguous() testX = torch.tensor(test[features].values, dtype=torch.float).contiguous() testY = torch.tensor(test['target'].values, dtype=torch.float).contiguous() for repeat in range(repeats): result_dict = { 'fold': fold, 'repeat': repeat, 'n': len(dataset), 'd': len(features) } start = time.perf_counter() ret = training_routine(trainX, trainY, testX, testY, **training_options) model_metrics = ret[0] ypred = ret[1] end = time.perf_counter() result_dict['mse'] = mean_squared_error(ypred, testY) result_dict['rmse'] = np.sqrt(result_dict['mse']) result_dict['train_time'] = end - start # e.g. -ll, -mll for name, value in model_metrics.items(): result_dict[name] = value # e.g. mae, ... for name, fxn in addl_metrics.items(): result_dict[name] = fxn(ypred, testY) results_list.append(result_dict) succeed = True t = time.time() elapsed = t - t0 num_finished = fold * repeats + repeat + 1 num_remaining = n_folds * repeats - num_finished eta = datetime.timedelta(seconds=elapsed / num_finished * num_remaining) if print_to_console: print('{}, fold={}, rep={}, eta={} \n{}'.format( datetime.datetime.now(), fold, repeat, format_timedelta(eta), result_dict)) # print("succeed: ", succeed) except Exception: result_dict = dict(error=traceback.format_exc(), fold=fold, n=len(dataset), d=len(features) - 2, mse=np.nan, rmse=np.nan) print(result_dict) traceback.print_exc() results_list.append(result_dict) n_errors += 1 print('errors: ', n_errors) results = pd.DataFrame(results_list) print('Mean RMSE = {}'.format(results['rmse'].mean())) return results
def train_exact_gp(trainX, trainY, testX, testY, kind, model_kwargs, train_kwargs, devices=('cpu',), skip_posterior_variances=False, skip_random_restart=False, evaluate_on_train=True, output_device=None, record_pred_unc=False, double=False): """Create and train an exact GP with the given options""" model_kwargs = copy.copy(model_kwargs) train_kwargs = copy.copy(train_kwargs) d = trainX.shape[-1] devices = [torch.device(device) for device in devices] if output_device is None: output_device = devices[0] else: output_device = torch.device(output_device) type_ = torch.double if double else torch.float trainX = trainX.to(output_device, type_) trainY = trainY.to(output_device, type_) testX = testX.to(output_device, type_) testY = testY.to(output_device, type_) # replace with value from dataset for convenience for k, v in list(model_kwargs.items()): if isinstance(v, str) and v == 'd': model_kwargs[k] = d # Change some options just for initial training with random restarts. random_restarts = train_kwargs.pop('random_restarts', 1) init_iters = train_kwargs.pop('init_iters', 20) optimizer_ = _map_to_optim(train_kwargs.pop('optimizer')) rr_check_conv = train_kwargs.pop('rr_check_conv', False) initial_train_kwargs = copy.copy(train_kwargs) initial_train_kwargs['max_iter'] = init_iters initial_train_kwargs['check_conv'] = rr_check_conv # initial_train_kwargs['verbose'] = 0 # don't shout about it best_model, best_likelihood, best_mll = None, None, None best_loss = np.inf # TODO: move random restarts code to a train_to_convergence-like function if not skip_random_restart: # Do some number of random restarts, keeping the best one after a truncated training. for restart in range(random_restarts): # TODO: log somehow what's happening in the restarts. model, likelihood = create_exact_gp(trainX, trainY, kind, devices=devices, **model_kwargs) model = model.to(output_device, type_) # regular marginal log likelihood mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model) _ = train_to_convergence(model, trainX, trainY, optimizer=optimizer_, objective=mll, isloss=False, **initial_train_kwargs) model.train() output = model(trainX) loss = -mll(output, trainY).item() if loss < best_loss: best_loss = loss best_model = model best_likelihood = likelihood best_mll = mll model = best_model likelihood = best_likelihood mll = best_mll else: model, likelihood = create_exact_gp(trainX, trainY, kind, devices=devices, **model_kwargs) model = model.to(output_device, type_) mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model) # fit GP with warnings.catch_warnings(record=True) as w: trained_epochs = train_to_convergence(model, trainX, trainY, optimizer=optimizer_, objective=mll, isloss=False, **train_kwargs) model.eval() likelihood.eval() mll.eval() model_metrics = dict() model_metrics['trained_epochs'] = trained_epochs with torch.no_grad(): model.train() # consider prior for evaluation on train dataset likelihood.train() train_outputs = model(trainX) model_metrics['prior_train_nmll'] = -mll(train_outputs, trainY).item() with gpytorch.settings.skip_posterior_variances(skip_posterior_variances): model.eval() # Now consider posterior distributions likelihood.eval() if evaluate_on_train: train_outputs = model(trainX) model_metrics['train_mse'] = mean_squared_error(train_outputs.mean, trainY) with warnings.catch_warnings(record=True) as w2: test_outputs = model(testX) pred_mean = test_outputs.mean if not skip_posterior_variances: # model_metrics['train_nll'] = -likelihood(train_outputs).log_prob( # trainY).item() # model_metrics['test_nll'] = -likelihood(test_outputs).log_prob( # testY).item() if evaluate_on_train: model_metrics['train_nll'] = -mll(train_outputs, trainY).item() model_metrics['test_nll'] = -mll(test_outputs, testY).item() distro = likelihood(test_outputs) lower, upper = distro.confidence_region() frac = ((testY > lower) * (testY < upper)).to(torch.float).mean().item() model_metrics['test_pred_frac_in_cr'] = frac if record_pred_unc: model_metrics['test_pred_z_score'] = (testY - distro.mean) / distro.stddev # model_metrics['test_pred_var'] = distro.variance.tolist() # model_metrics['test_pred_mean'] = distro.mean.tolist() model_metrics['training_warnings'] = len(w) model_metrics['testing_warning'] = '' if len(w2) == 0 else w2[-1].message model_metrics['state_dict_file'] = _save_state_dict(model) return model_metrics, pred_mean.to('cpu', torch.float), model