from abc import abstractmethod from enum import Enum import numpy as np from neural_net.epoch import Epoch from neural_net.transform_layer import Layer class ModelData: def __init__(self, training_inputs, training_targets, test_inputs, test_targets): self.is_loaded = False self.training_inputs = training_inputs self.training_labels = training_targets self.test_inputs = test_inputs self.test_labels = test_targets # class TrainingSession: # def __init__(self, training_data: ModelData, learning_rate: float, nr_epochs: int, batch_size: int = 1000): # self.training_data = training_data # self.learning_rate = learning_rate # self.nr_epochs = nr_epochs # self.batch_size = batch_size # self.epochs: [Epoch] = [] # for i in range(self.nr_epochs): # self.epochs.append( # Epoch(i, self.training_data.training_inputs, self.training_data.training_labels, self.batch_size)) # # def get_total_training_duration(self): # duration = 0.0 # for epoch in self.epochs: # duration += epoch.duration # return duration class NeuralNet: def __init__(self, layers: [Layer]): self.layers = layers self.last_loss = None self.last_accuracy = None def forward(self, inputs): outputs = inputs for layer in self.layers: outputs = layer.forward(outputs) return outputs def reset(self): for layer in self.layers: layer.reset() def backward(self, dL_dout, epoch): layer_dl_gradients = [] layer_dl_bias = [] layer_weights = [] layer_biases = [] for idx, layer in reversed(list(enumerate(self.layers))): dL_dout, dl_gradients, dl_biases, weights, biases = layer.backward(dL_dout, epoch.learning_rate) if dl_gradients is not None: layer_dl_gradients.append(dl_gradients) if dl_biases is not None: layer_dl_bias.append(dl_biases) if weights is not None: layer_weights.append(weights) if biases is not None: layer_biases.append(biases) return layer_dl_gradients, layer_dl_bias, layer_weights, layer_biases # def train(self, training_run: TrainingRun): # self.training_runs.append(training_run) # # for epoch in training_run.epochs: # epoch.start() # # for batch in epoch.batches: # batch.predictions = self.forward(batch.inputs) # dL_dout = self.loss_derivative(batch.predictions, batch.labels) # # layer_dl_gradients, layer_dl_biases, layer_weights, layer_biases = self.backward(dL_dout, training_run.learning_rate, epoch) # epoch.layer_dl_gradients.append(layer_dl_gradients) # epoch.layer_dl_biases.append(layer_dl_biases) # # epoch.finish() # epoch.loss = self.loss(epoch.all_predictions(), epoch.all_labels()) # # if training_run.epoch_callback is not None: # training_run.epoch_callback(training_run, epoch) # # self.recalculate_loss(training_run.training_data.test_inputs, training_run.training_data.test_labels) # self.recalculate_loss(training_run.training_data.test_inputs, training_run.training_data.test_labels) def get_all_weights(self): all_weights = [] for layer in self.layers: if hasattr(layer, 'weights'): all_weights.append(layer.weights) return all_weights def recalculate_accuracy(self, inputs, labels): raw_outputs = self.forward(inputs) predictions = raw_outputs.argmax(axis=1) num_correct_predictions = 0 for idx, prediction in enumerate(predictions): if prediction == labels[idx]: num_correct_predictions += 1 self.last_accuracy = num_correct_predictions / len(predictions) return self.last_accuracy def recalculate_loss(self, inputs, labels): raw_outputs = self.forward(inputs) self.last_loss = self.loss(np.array(raw_outputs), np.array(labels)) return self.last_loss @abstractmethod def loss(self, outputs: np.array, labels: np.array): pass @abstractmethod def loss_derivative(self, outputs: np.array, labels: np.array): pass def predict(self, inputs): return self.forward(inputs)