Module smearn.regularization
The smearn.regularization
module includes a few regularization techniques, such as L1 and L2 regularization and bagging ensembles. The smearn.layers
module also includes dropout layers.
Expand source code
'''
The `smearn.regularization` module includes a few regularization techniques, such as L1 and L2 regularization and bagging ensembles. The `smearn.layers` module also includes dropout layers.
'''
from .symbolic import *
class Regularizer:
'''
Regularizer base class.
A class that inherits from it to be used as a regularizer while training a `smearn.models.Model` should overload the method `gradient` to send the gradient of the regularizer function with respect to the `weights` argument.
See `smearn.regularization.L1` or `smearn.regularization.L2` for an example.
'''
def gradient(weights):
return np.zeros(weights.value.shape)
class L2(Regularizer):
'''
L2 regularization
'''
def __init__(self, alpha):
self.alpha = alpha
def gradient(self, weights):
return self.alpha * weights
class L1(Regularizer):
'''
L1 regularization
'''
def __init__(self, alpha):
self.alpha = alpha
def gradient(self, weights):
return self.alpha * np.sign(weights)
class BaggingEnseble:
'''
A class to be used to train and evaluate ensembles of neural networks using the bagging technique.
'''
def __init__(self, models):
for model in models:
if model.input.shape != models[0].input.shape or model.output.shape != models[0].output.shape:
raise Exception("All models in an ensemble must have the same input and output shapes")
self.models = models
def train(self, data, labels=None, lr=0.001, epochs=1, batch_size=None, validation_data=None, validation_labels=None, validation_split=0, early_stopping=0):
if validation_split > 0 and validation_data is not None:
raise Exception("Do not provide a validation split if you are providing validation data")
if validation_split > 0:
if validation_split < 1:
validation_split = validation_split * data.shape[0]
validation_split = int(validation_split)
validation_data = data[:validation_split]
data = data[validation_split:]
validation_labels = labels[:validation_split]
labels = labels[validation_split:]
if early_stopping > 0 and validation_data is None:
raise Exception("Early stopping is not allowed without providing validation data or a validation split")
random_indices = np.random.choice(data.shape[0], size=(len(self.models), data.shape[0]))
consecutive_worsening_epochs = 0
last_validation_loss = np.infty
for epoch in range(epochs):
for i, model in enumerate(self.models):
random_data = data[random_indices[i]]
random_labels = labels[random_indices[i]]
model.train(data=random_data, labels=random_labels, lr=lr, epochs=epoch+1, start_epoch=epoch, batch_size=batch_size)
# Compute validation loss and check if we should use early stopping
if validation_data is not None:
total_loss = 0
for i, model in enumerate(self.models):
model.loss.reset_values_and_gradients(train=False)
model.input.set_value(validation_data)
model.labels.set_value(validation_labels.reshape(validation_labels.shape + (1,)))
model.loss.compute_value()
total_loss += np.mean(model.loss.value)
validation_loss = total_loss / len(self.models)
print("Mean validation loss: {}".format(validation_loss))
if early_stopping > 0:
if validation_loss > last_validation_loss:
consecutive_worsening_epochs += 1
else:
consecutive_worsening_epochs = 0
if consecutive_worsening_epochs >= early_stopping:
print("Training stopped because of early stopping")
return
last_validation_loss = validation_loss
def evaluate(self, data):
return np.mean(np.array([model.evaluate(data) for model in self.models]), axis=0)
Classes
class BaggingEnseble (models)
-
A class to be used to train and evaluate ensembles of neural networks using the bagging technique.
Expand source code
class BaggingEnseble: ''' A class to be used to train and evaluate ensembles of neural networks using the bagging technique. ''' def __init__(self, models): for model in models: if model.input.shape != models[0].input.shape or model.output.shape != models[0].output.shape: raise Exception("All models in an ensemble must have the same input and output shapes") self.models = models def train(self, data, labels=None, lr=0.001, epochs=1, batch_size=None, validation_data=None, validation_labels=None, validation_split=0, early_stopping=0): if validation_split > 0 and validation_data is not None: raise Exception("Do not provide a validation split if you are providing validation data") if validation_split > 0: if validation_split < 1: validation_split = validation_split * data.shape[0] validation_split = int(validation_split) validation_data = data[:validation_split] data = data[validation_split:] validation_labels = labels[:validation_split] labels = labels[validation_split:] if early_stopping > 0 and validation_data is None: raise Exception("Early stopping is not allowed without providing validation data or a validation split") random_indices = np.random.choice(data.shape[0], size=(len(self.models), data.shape[0])) consecutive_worsening_epochs = 0 last_validation_loss = np.infty for epoch in range(epochs): for i, model in enumerate(self.models): random_data = data[random_indices[i]] random_labels = labels[random_indices[i]] model.train(data=random_data, labels=random_labels, lr=lr, epochs=epoch+1, start_epoch=epoch, batch_size=batch_size) # Compute validation loss and check if we should use early stopping if validation_data is not None: total_loss = 0 for i, model in enumerate(self.models): model.loss.reset_values_and_gradients(train=False) model.input.set_value(validation_data) model.labels.set_value(validation_labels.reshape(validation_labels.shape + (1,))) model.loss.compute_value() total_loss += np.mean(model.loss.value) validation_loss = total_loss / len(self.models) print("Mean validation loss: {}".format(validation_loss)) if early_stopping > 0: if validation_loss > last_validation_loss: consecutive_worsening_epochs += 1 else: consecutive_worsening_epochs = 0 if consecutive_worsening_epochs >= early_stopping: print("Training stopped because of early stopping") return last_validation_loss = validation_loss def evaluate(self, data): return np.mean(np.array([model.evaluate(data) for model in self.models]), axis=0)
Methods
def evaluate(self, data)
-
Expand source code
def evaluate(self, data): return np.mean(np.array([model.evaluate(data) for model in self.models]), axis=0)
def train(self, data, labels=None, lr=0.001, epochs=1, batch_size=None, validation_data=None, validation_labels=None, validation_split=0, early_stopping=0)
-
Expand source code
def train(self, data, labels=None, lr=0.001, epochs=1, batch_size=None, validation_data=None, validation_labels=None, validation_split=0, early_stopping=0): if validation_split > 0 and validation_data is not None: raise Exception("Do not provide a validation split if you are providing validation data") if validation_split > 0: if validation_split < 1: validation_split = validation_split * data.shape[0] validation_split = int(validation_split) validation_data = data[:validation_split] data = data[validation_split:] validation_labels = labels[:validation_split] labels = labels[validation_split:] if early_stopping > 0 and validation_data is None: raise Exception("Early stopping is not allowed without providing validation data or a validation split") random_indices = np.random.choice(data.shape[0], size=(len(self.models), data.shape[0])) consecutive_worsening_epochs = 0 last_validation_loss = np.infty for epoch in range(epochs): for i, model in enumerate(self.models): random_data = data[random_indices[i]] random_labels = labels[random_indices[i]] model.train(data=random_data, labels=random_labels, lr=lr, epochs=epoch+1, start_epoch=epoch, batch_size=batch_size) # Compute validation loss and check if we should use early stopping if validation_data is not None: total_loss = 0 for i, model in enumerate(self.models): model.loss.reset_values_and_gradients(train=False) model.input.set_value(validation_data) model.labels.set_value(validation_labels.reshape(validation_labels.shape + (1,))) model.loss.compute_value() total_loss += np.mean(model.loss.value) validation_loss = total_loss / len(self.models) print("Mean validation loss: {}".format(validation_loss)) if early_stopping > 0: if validation_loss > last_validation_loss: consecutive_worsening_epochs += 1 else: consecutive_worsening_epochs = 0 if consecutive_worsening_epochs >= early_stopping: print("Training stopped because of early stopping") return last_validation_loss = validation_loss
class L1 (alpha)
-
L1 regularization
Expand source code
class L1(Regularizer): ''' L1 regularization ''' def __init__(self, alpha): self.alpha = alpha def gradient(self, weights): return self.alpha * np.sign(weights)
Ancestors
Methods
def gradient(self, weights)
-
Expand source code
def gradient(self, weights): return self.alpha * np.sign(weights)
class L2 (alpha)
-
L2 regularization
Expand source code
class L2(Regularizer): ''' L2 regularization ''' def __init__(self, alpha): self.alpha = alpha def gradient(self, weights): return self.alpha * weights
Ancestors
Methods
def gradient(self, weights)
-
Expand source code
def gradient(self, weights): return self.alpha * weights
class Regularizer
-
Regularizer base class. A class that inherits from it to be used as a regularizer while training a
Model
should overload the methodgradient
to send the gradient of the regularizer function with respect to theweights
argument. SeeL1
orL2
for an example.Expand source code
class Regularizer: ''' Regularizer base class. A class that inherits from it to be used as a regularizer while training a `smearn.models.Model` should overload the method `gradient` to send the gradient of the regularizer function with respect to the `weights` argument. See `smearn.regularization.L1` or `smearn.regularization.L2` for an example. ''' def gradient(weights): return np.zeros(weights.value.shape)
Subclasses
Methods
def gradient(weights)
-
Expand source code
def gradient(weights): return np.zeros(weights.value.shape)