Skip to content

Commit 7d206fb

Browse files
Henry BarnesClaude Opus 4.6
andcommitted
Add early stopping, ETA display, and richer result logging
- Early stopping with configurable patience (default 50 epochs) - Per-epoch timing and ETA estimate in training output - Log best_epoch and hidden size to results.json entries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9ad23da commit 7d206fb

1 file changed

Lines changed: 19 additions & 2 deletions

File tree

common/training.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,16 @@ def run_training(model, train_loader, test_loader, config):
122122
)
123123

124124
n_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
125+
patience = config.get('patience', 50) # Early stopping patience
125126
print(f"Parameters: {n_params:,}")
127+
print(f"Early stopping patience: {patience} epochs")
126128

127129
best_acc = 0.0
128130
best_epoch = 0
129131
start_time = time.time()
130132

131133
for epoch in range(epochs):
134+
epoch_start = time.time()
132135
train_loss, train_acc = train_epoch(
133136
model, train_loader, optimizer, device,
134137
augment_fn=augment_fn,
@@ -137,6 +140,7 @@ def run_training(model, train_loader, test_loader, config):
137140
)
138141
test_loss, test_acc = evaluate(model, test_loader, device)
139142
scheduler.step()
143+
epoch_time = time.time() - epoch_start
140144

141145
if test_acc > best_acc:
142146
best_acc = test_acc
@@ -149,10 +153,20 @@ def run_training(model, train_loader, test_loader, config):
149153
}, save_path)
150154

151155
lr = optimizer.param_groups[0]['lr']
156+
elapsed = time.time() - start_time
157+
remaining = epoch_time * (epochs - epoch - 1)
158+
eta_str = f"{remaining/60:.0f}m" if remaining < 3600 else f"{remaining/3600:.1f}h"
159+
152160
print(f"Epoch {epoch+1:3d}/{epochs} | "
153161
f"Train: {train_loss:.4f} / {train_acc*100:.1f}% | "
154162
f"Test: {test_loss:.4f} / {test_acc*100:.1f}% | "
155-
f"LR={lr:.2e} | Best={best_acc*100:.1f}%")
163+
f"LR={lr:.2e} | Best={best_acc*100:.1f}% | "
164+
f"{epoch_time:.1f}s/ep | ETA {eta_str}")
165+
166+
# Early stopping
167+
if epoch - best_epoch >= patience:
168+
print(f"\nEarly stopping: no improvement for {patience} epochs")
169+
break
156170

157171
training_time = time.time() - start_time
158172

@@ -184,12 +198,15 @@ def _save_result(results_file, benchmark, config, result):
184198
except (FileNotFoundError, json.JSONDecodeError):
185199
results = []
186200

201+
model_config = config.get('model_config', {})
187202
entry = {
188203
'benchmark': benchmark,
189204
'accuracy_float': round(result['best_acc'] * 100, 2),
190205
'n_params': result['n_params'],
191206
'epochs': config.get('epochs'),
192-
'neuron_type': config.get('model_config', {}).get('neuron_type', 'lif'),
207+
'best_epoch': result['best_epoch'] + 1,
208+
'neuron_type': model_config.get('neuron_type', 'lif'),
209+
'hidden': model_config.get('hidden', model_config.get('n_hidden')),
193210
'date': datetime.now().strftime('%Y-%m-%d'),
194211
'training_time_s': result['training_time_s'],
195212
}

0 commit comments

Comments
 (0)