nnfs_book
nnfs_book copied to clipboard
Chapter 19 Model class `train` method validation should be aligned with the outer for loop
In Chapter 18, we have the train method as:
def train(
self,
X: np.ndarray,
y: np.ndarray,
*,
validation: tuple[np.ndarray, np.ndarray] = None,
epochs: int = 100,
print_every: int = 10,
):
self.accuracy.init(y)
for epoch in range(1, 1 + epochs):
output = self.forward(X)
data_loss, reg_loss = self.loss.calculate(output, y)
loss = data_loss + reg_loss
predictions = self.output_layer.predict(output)
acc = self.accuracy.calculate(predictions, y)
self.backward(output, y)
self.optimizer.pre_update_params()
self.optimizer.update()
self.optimizer.post_update_params()
if not epoch % print_every:
print(
f"epoch: {epoch}, "
+ f"acc: {acc:.3f}, "
+ f"loss: {loss:.3f}, "
+ f"data_loss: {data_loss:.3f}, "
+ f"reg_loss: {reg_loss:.3f}, "
+ f"lr: {self.optimizer.curr_lr}"
)
if validation:
x_val, y_val = validation
output = self.forward(x_val, training=False)
loss = self.loss.calculate(output, y_val, include_regularization=False)
predictions = self.output_layer.predict(output)
accuracy = self.accuracy.calculate(predictions, y_val)
print(f"Validation, acc: {accuracy:.3f}, loss: {loss:.3f}")
The if validation clause is aligned with the outer for loop, which is understandable since we only need to validate the data once after the training process.
In chapter 19 sample code, we have:
# Main training loop
for epoch in range(1, epochs+1):
# Print epoch number
print(f'epoch: {epoch}')
# Reset accumulated values in loss and accuracy objects
self.loss.new_pass()
self.accuracy.new_pass()
# Iterate over steps
for step in range(train_steps):
# If batch size is not set -
# train using one step and full dataset
if batch_size is None:
batch_X = X
batch_y = y
# Otherwise slice a batch
else:
batch_X = X[step*batch_size:(step+1)*batch_size]
batch_y = y[step*batch_size:(step+1)*batch_size]
# Perform the forward pass
output = self.forward(batch_X, training=True)
# Calculate loss
data_loss, regularization_loss = \
self.loss.calculate(output, batch_y,
include_regularization=True)
loss = data_loss + regularization_loss
# Get predictions and calculate an accuracy
predictions = self.output_layer_activation.predictions(
output)
accuracy = self.accuracy.calculate(predictions,
batch_y)
# Perform backward pass
self.backward(output, batch_y)
# Optimize (update parameters)
self.optimizer.pre_update_params()
for layer in self.trainable_layers:
self.optimizer.update_params(layer)
self.optimizer.post_update_params()
# Print a summary
if not step % print_every or step == train_steps - 1:
print(f'step: {step}, ' +
f'acc: {accuracy:.3f}, ' +
f'loss: {loss:.3f} (' +
f'data_loss: {data_loss:.3f}, ' +
f'reg_loss: {regularization_loss:.3f}), ' +
f'lr: {self.optimizer.current_learning_rate}')
# Get and print epoch loss and accuracy
epoch_data_loss, epoch_regularization_loss = \
self.loss.calculate_accumulated(
include_regularization=True)
epoch_loss = epoch_data_loss + epoch_regularization_loss
epoch_accuracy = self.accuracy.calculate_accumulated()
print(f'training, ' +
f'acc: {epoch_accuracy:.3f}, ' +
f'loss: {epoch_loss:.3f} (' +
f'data_loss: {epoch_data_loss:.3f}, ' +
f'reg_loss: {epoch_regularization_loss:.3f}), ' +
f'lr: {self.optimizer.current_learning_rate}')
# If there is the validation data
if validation_data is not None:
# Reset accumulated values in loss
# and accuracy objects
self.loss.new_pass()
self.accuracy.new_pass()
# Iterate over steps
for step in range(validation_steps):
# If batch size is not set -
# train using one step and full dataset
if batch_size is None:
batch_X = X_val
batch_y = y_val
# Otherwise slice a batch
else:
batch_X = X_val[
step*batch_size:(step+1)*batch_size
]
batch_y = y_val[
step*batch_size:(step+1)*batch_size
]
# Perform the forward pass
output = self.forward(batch_X, training=False)
# Calculate the loss
self.loss.calculate(output, batch_y)
# Get predictions and calculate an accuracy
predictions = self.output_layer_activation.predictions(
output)
self.accuracy.calculate(predictions, batch_y)
# Get and print validation loss and accuracy
validation_loss = self.loss.calculate_accumulated()
validation_accuracy = self.accuracy.calculate_accumulated()
# Print a summary
print(f'validation, ' +
f'acc: {validation_accuracy:.3f}, ' +
f'loss: {validation_loss:.3f}')
If I was correct on
we only need to validate the data once after the training process
then why should we validate the test data through the epochs?