text: # AUTOGENERATED! DO NOT EDIT! File to edit: 03_ensembles.ipynb (unless otherwise specified).
  
  __all__ = ['VanillaEnsemble', 'OnlineBootstrapEnsemble']
  
  # Cell
  
  import torch
  from torch.autograd import Variable
  import random
  import numpy as np
  
  class VanillaEnsemble(object):
      def __init__(self,model_type,dim_input, num_hidden = 10, p=0.00, decay=0.001, non_linearity=torch.nn.LeakyReLU, n_models=10, model_list=None):
          self.models = [model_type(dim_input, num_hidden, p, decay, non_linearity) for model in range(n_models)]
          self.optimizers = [torch.optim.SGD(
              model.parameters(),
              weight_decay=decay,
              lr=0.01) for model in self.models]
          self.criterion = torch.nn.MSELoss()
          self.dropout_p = p
          self.decay = decay
  
      def fit_model(self, model, optimizer, X_obs,y_obs):
          y = Variable(torch.Tensor(y_obs[:, np.newaxis]), requires_grad=False)
          y_pred = model(X_obs[:, np.newaxis])
          optimizer.zero_grad()
          loss = self.criterion(y_pred, y)
          loss.backward()
          optimizer.step()
          return loss
  
      def observe(self,X,y):
          return self.fit_ensemble(X,y)
  
      def fit_ensemble(self, X_obs, y_obs):
          losslist = []
          for model, optimizer in zip(self.models, self.optimizers):
              losslist.append(self.fit_model(model, optimizer, X_obs,y_obs))
          return losslist
  
      def predict_distribution(self, X, ):
          outputs = np.hstack([model(X[:, np.newaxis]).data.numpy() for model in self.models])
          y_mean = outputs.mean(axis=1)
          y_std = outputs.std(axis=1)
          return {'means':y_mean,
                'stds':y_std}
  
  
  class OnlineBootstrapEnsemble(VanillaEnsemble):
  
      def fit_ensemble(self, X_obs, y_obs):
          losslist = []
          for model, optimizer in zip(self.models, self.optimizers):
              if random.random() > 0.5:
                  losslist.append(self.fit_model(model, optimizer, X_obs,y_obs))
                  self.fit_model(model, optimizer, X_obs,y_obs)
          return losslist
  
  