Module smearn.models
The smearn.models
module contains the Model
class, which provides a wrapper to optimize feedforward neural networks using supervised networks.
Expand source code
'''
The `smearn.models` module contains the `smearn.models.Model` class, which provides a wrapper to optimize feedforward neural networks using supervised networks.
'''
import numpy as np
from . import layers
from . import optimization
from .symbolic import *
#
# Models
#
class Model:
def __init__(self, input=None, output=None, loss=layers.MeanSquareError, optimizer=optimization.SGD()):
self.input = input
self.output = output
self.labels = layers.Input(output.shape, pad_one_dimension=False)
self.loss = loss(self.labels, self.output)
self.optimizer = optimizer
self.loss.initialize_optimizer_for_parents(optimizer)
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, start_epoch=0):
# First, handle the some of the logistics of validation splits and early stopping
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")
if batch_size is None:
batch_size = labels.shape[0]
batches = labels.shape[0] // batch_size
consecutive_worsening_epochs = 0
last_validation_loss = np.infty
for epoch in range(start_epoch, epochs):
current_index = 0
loss = np.zeros(())
loss_count = 0
for i in range(batches):
next_index = min(current_index + batch_size, labels.shape[0])
batch_data = data[current_index:next_index]
batch_labels = labels[current_index:next_index]
# Forward pass
self.loss.reset_values_and_gradients()
self.input.set_value(batch_data)
self.labels.set_value(batch_labels.reshape(batch_labels.shape + (1,)))
self.loss.compute_value()
loss += np.mean(self.loss.value)
loss_count += (next_index - current_index) / batch_size
# Backward pass
self.loss.propagate_gradients()
self.loss.propagate_learning(self.optimizer)
current_index = next_index
print("[Epoch {}]: mean training loss: {}".format(epoch + 1, loss / loss_count))
# Tell schedulers to update the hyperparameters
self.optimizer.update_hyperparameters(epoch + 1)
# Compute validation loss and check if we should use early stopping
if validation_data is not None:
self.loss.reset_values_and_gradients(train=False)
self.input.set_value(validation_data)
self.labels.set_value(validation_labels.reshape(validation_labels.shape + (1,)))
self.loss.compute_value()
validation_loss = np.mean(self.loss.value)
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):
self.output.reset_values_and_gradients(train=False)
self.input.set_value(data)
self.output.compute_value()
return self.output.value
Classes
class Model (input=None, output=None, loss=<function MeanSquareError>, optimizer=<smearn.optimization.SGD object>)
-
Expand source code
class Model: def __init__(self, input=None, output=None, loss=layers.MeanSquareError, optimizer=optimization.SGD()): self.input = input self.output = output self.labels = layers.Input(output.shape, pad_one_dimension=False) self.loss = loss(self.labels, self.output) self.optimizer = optimizer self.loss.initialize_optimizer_for_parents(optimizer) 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, start_epoch=0): # First, handle the some of the logistics of validation splits and early stopping 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") if batch_size is None: batch_size = labels.shape[0] batches = labels.shape[0] // batch_size consecutive_worsening_epochs = 0 last_validation_loss = np.infty for epoch in range(start_epoch, epochs): current_index = 0 loss = np.zeros(()) loss_count = 0 for i in range(batches): next_index = min(current_index + batch_size, labels.shape[0]) batch_data = data[current_index:next_index] batch_labels = labels[current_index:next_index] # Forward pass self.loss.reset_values_and_gradients() self.input.set_value(batch_data) self.labels.set_value(batch_labels.reshape(batch_labels.shape + (1,))) self.loss.compute_value() loss += np.mean(self.loss.value) loss_count += (next_index - current_index) / batch_size # Backward pass self.loss.propagate_gradients() self.loss.propagate_learning(self.optimizer) current_index = next_index print("[Epoch {}]: mean training loss: {}".format(epoch + 1, loss / loss_count)) # Tell schedulers to update the hyperparameters self.optimizer.update_hyperparameters(epoch + 1) # Compute validation loss and check if we should use early stopping if validation_data is not None: self.loss.reset_values_and_gradients(train=False) self.input.set_value(validation_data) self.labels.set_value(validation_labels.reshape(validation_labels.shape + (1,))) self.loss.compute_value() validation_loss = np.mean(self.loss.value) 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): self.output.reset_values_and_gradients(train=False) self.input.set_value(data) self.output.compute_value() return self.output.value
Methods
def evaluate(self, data)
-
Expand source code
def evaluate(self, data): self.output.reset_values_and_gradients(train=False) self.input.set_value(data) self.output.compute_value() return self.output.value
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, start_epoch=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, start_epoch=0): # First, handle the some of the logistics of validation splits and early stopping 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") if batch_size is None: batch_size = labels.shape[0] batches = labels.shape[0] // batch_size consecutive_worsening_epochs = 0 last_validation_loss = np.infty for epoch in range(start_epoch, epochs): current_index = 0 loss = np.zeros(()) loss_count = 0 for i in range(batches): next_index = min(current_index + batch_size, labels.shape[0]) batch_data = data[current_index:next_index] batch_labels = labels[current_index:next_index] # Forward pass self.loss.reset_values_and_gradients() self.input.set_value(batch_data) self.labels.set_value(batch_labels.reshape(batch_labels.shape + (1,))) self.loss.compute_value() loss += np.mean(self.loss.value) loss_count += (next_index - current_index) / batch_size # Backward pass self.loss.propagate_gradients() self.loss.propagate_learning(self.optimizer) current_index = next_index print("[Epoch {}]: mean training loss: {}".format(epoch + 1, loss / loss_count)) # Tell schedulers to update the hyperparameters self.optimizer.update_hyperparameters(epoch + 1) # Compute validation loss and check if we should use early stopping if validation_data is not None: self.loss.reset_values_and_gradients(train=False) self.input.set_value(validation_data) self.labels.set_value(validation_labels.reshape(validation_labels.shape + (1,))) self.loss.compute_value() validation_loss = np.mean(self.loss.value) 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