ihatebaselines commited on
Commit
10830b0
·
verified ·
1 Parent(s): bf94660

Upload trainer.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. trainer.py +110 -0
trainer.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from tqdm import tqdm
3
+
4
+ class Trainer:
5
+ """
6
+ The Trainer class enables fully customizable training of the SOCRATE model.
7
+ You can pass a custom loss function (criterion), optimizer, scheduler, and a scaler for AMP.
8
+ """
9
+ def __init__(self, model, optimizer, scheduler, criterion, device, scaler=None, save_dir=".", save_name="socrate", save_interval=100):
10
+ self.model = model
11
+ self.optimizer = optimizer
12
+ self.scheduler = scheduler
13
+ self.criterion = criterion
14
+ self.device = device
15
+ self.scaler = scaler
16
+ self.save_dir = save_dir
17
+ self.save_name = save_name
18
+ self.save_interval = save_interval
19
+
20
+ import os
21
+ if self.save_dir and self.save_dir != ".":
22
+ os.makedirs(self.save_dir, exist_ok=True)
23
+
24
+ def train_epoch(self, dataloader, best_loss, epoch_num=1, total_epochs=1):
25
+ """
26
+ Trains a full epoch over the dataloader.
27
+ Returns the new `best_loss`.
28
+ """
29
+ self.model.train()
30
+ total_loss = 0.0
31
+ pbar = tqdm(dataloader, desc=f"Epoch {epoch_num}/{total_epochs}")
32
+
33
+ for step, (image, t1, t2) in enumerate(pbar, 1):
34
+ image = image.to(self.device, non_blocking=True)
35
+ t1 = t1.to(self.device, non_blocking=True)
36
+ t2 = t2.to(self.device, non_blocking=True)
37
+
38
+ self.optimizer.zero_grad(set_to_none=True)
39
+
40
+ if self.scaler is not None:
41
+ # Mixed Precision Training (AMP)
42
+ with torch.amp.autocast(device_type="cuda"):
43
+ output = self.model(image, t1)
44
+ loss = self.criterion(
45
+ output.reshape(-1, output.size(-1)),
46
+ t2.reshape(-1)
47
+ )
48
+
49
+ self.scaler.scale(loss).backward()
50
+ self.scaler.unscale_(self.optimizer)
51
+ torch.nn.utils.clip_grad_norm_(self.model.parameters(), 1.0)
52
+ self.scaler.step(self.optimizer)
53
+ self.scaler.update()
54
+ else:
55
+ # Standard Training (FP32)
56
+ output = self.model(image, t1)
57
+ loss = self.criterion(
58
+ output.reshape(-1, output.size(-1)),
59
+ t2.reshape(-1)
60
+ )
61
+ loss.backward()
62
+ torch.nn.utils.clip_grad_norm_(self.model.parameters(), 1.0)
63
+ self.optimizer.step()
64
+
65
+ if self.scheduler is not None:
66
+ self.scheduler.step()
67
+
68
+ total_loss += loss.item()
69
+ avg_loss = total_loss / step
70
+
71
+ pbar.set_postfix(
72
+ loss=f"{loss.item():.4f}",
73
+ avg_loss=f"{avg_loss:.4f}",
74
+ best=f"{best_loss:.4f}"
75
+ )
76
+
77
+ # Periodic saving during the epoch (can be extracted if too rigid)
78
+ if step % self.save_interval == 0:
79
+ import os
80
+ self.save_checkpoint(os.path.join(self.save_dir, f"{self.save_name}_previous.pt"), best_loss, avg_loss, step)
81
+ if avg_loss < best_loss:
82
+ best_loss = avg_loss
83
+ self.save_checkpoint(os.path.join(self.save_dir, f"{self.save_name}_best.pt"), best_loss, avg_loss, step)
84
+
85
+ epoch_avg_loss = total_loss / len(dataloader)
86
+ if epoch_avg_loss < best_loss:
87
+ best_loss = epoch_avg_loss
88
+ import os
89
+ self.save_checkpoint(os.path.join(self.save_dir, f"{self.save_name}_best.pt"), best_loss, epoch_avg_loss, step)
90
+
91
+ print(f"Train Loss pt Epoch {epoch_num}: {epoch_avg_loss:.4f}")
92
+ return best_loss
93
+
94
+ def save_checkpoint(self, filename, best_loss, avg_loss, step):
95
+ checkpoint = {
96
+ "model": self.model.state_dict(),
97
+ "optimizer": self.optimizer.state_dict(),
98
+ "scheduler": self.scheduler.state_dict() if self.scheduler else None,
99
+ "best_loss": best_loss,
100
+ "avg_loss": avg_loss,
101
+ "step": step,
102
+ }
103
+ torch.save(checkpoint, filename)
104
+
105
+ def train(model, dataloader, optimizer, scheduler, criterion, device, best_loss, scaler, save_dir=".", save_name="socrate", save_interval=100):
106
+ """
107
+ The original function exposed for backward compatibility with the old script.
108
+ """
109
+ trainer = Trainer(model, optimizer, scheduler, criterion, device, scaler, save_dir, save_name, save_interval)
110
+ return trainer.train_epoch(dataloader, best_loss)