Fix CUDA OOM on T4: cast model to amp_dtype directly, batch_size=2, safe RMSNorm
Browse files- model/configs/train_kaggle_t4.yaml +8 -8
- model/scripts/train.py +2 -0
- model/scripts/viu_moe.py +34 -13
model/configs/train_kaggle_t4.yaml
CHANGED
|
@@ -13,23 +13,23 @@ curriculum: true
|
|
| 13 |
curriculum_stages:
|
| 14 |
- max_step: 50000
|
| 15 |
seq_len: 512
|
| 16 |
-
batch_size:
|
| 17 |
-
grad_accum:
|
| 18 |
- max_step: 200000
|
| 19 |
seq_len: 1024
|
| 20 |
-
batch_size:
|
| 21 |
-
grad_accum:
|
| 22 |
- max_step: null
|
| 23 |
seq_len: 2048
|
| 24 |
batch_size: 1
|
| 25 |
-
grad_accum: 32
|
| 26 |
|
| 27 |
seq_len: 1024
|
| 28 |
train_split: 0.95
|
| 29 |
|
| 30 |
-
# Kaggle T4 16GB VRAM: micro-batch
|
| 31 |
-
batch_size:
|
| 32 |
-
grad_accum:
|
| 33 |
target_global_batch: 128
|
| 34 |
auto_tune: false
|
| 35 |
|
|
|
|
| 13 |
curriculum_stages:
|
| 14 |
- max_step: 50000
|
| 15 |
seq_len: 512
|
| 16 |
+
batch_size: 1
|
| 17 |
+
grad_accum: 128 # 512 * 1 * 128 = 65,536 tokens/step per GPU (x2 GPUs = 131,072 tok/step)
|
| 18 |
- max_step: 200000
|
| 19 |
seq_len: 1024
|
| 20 |
+
batch_size: 1
|
| 21 |
+
grad_accum: 64 # 1024 * 1 * 64 = 65,536 tokens/step per GPU (x2 GPUs = 131,072 tok/step)
|
| 22 |
- max_step: null
|
| 23 |
seq_len: 2048
|
| 24 |
batch_size: 1
|
| 25 |
+
grad_accum: 32 # 2048 * 1 * 32 = 65,536 tokens/step per GPU (x2 GPUs = 131,072 tok/step)
|
| 26 |
|
| 27 |
seq_len: 1024
|
| 28 |
train_split: 0.95
|
| 29 |
|
| 30 |
+
# Kaggle T4 16GB VRAM: micro-batch 1 with SDPA and Gradient Checkpointing (<11GB peak VRAM)
|
| 31 |
+
batch_size: 1
|
| 32 |
+
grad_accum: 64
|
| 33 |
target_global_batch: 128
|
| 34 |
auto_tune: false
|
| 35 |
|
model/scripts/train.py
CHANGED
|
@@ -1798,6 +1798,8 @@ def main():
|
|
| 1798 |
scaler.update()
|
| 1799 |
else:
|
| 1800 |
opt.step()
|
|
|
|
|
|
|
| 1801 |
step += 1
|
| 1802 |
|
| 1803 |
# Clean industry-standard pretraining logs: only essential metrics, no terminal garbling
|
|
|
|
| 1798 |
scaler.update()
|
| 1799 |
else:
|
| 1800 |
opt.step()
|
| 1801 |
+
if device.type == "cuda":
|
| 1802 |
+
torch.cuda.empty_cache()
|
| 1803 |
step += 1
|
| 1804 |
|
| 1805 |
# Clean industry-standard pretraining logs: only essential metrics, no terminal garbling
|
model/scripts/viu_moe.py
CHANGED
|
@@ -443,25 +443,46 @@ class Viu1MoE(nn.Module):
|
|
| 443 |
total_aux = total_aux + aux
|
| 444 |
usages.append(usage.detach())
|
| 445 |
h = self.norm(x)
|
| 446 |
-
logits = self.head(h)
|
| 447 |
-
if self.final_softcap > 0:
|
| 448 |
-
logits = self.final_softcap * torch.tanh(logits / self.final_softcap)
|
| 449 |
-
|
| 450 |
loss, mt_loss = None, None
|
| 451 |
if targets is not None:
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 457 |
if self.final_softcap > 0:
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
loss = loss + 0.1 * mt_loss
|
|
|
|
| 463 |
if isinstance(total_aux, torch.Tensor):
|
| 464 |
loss = loss + total_aux
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 465 |
aux_info = {
|
| 466 |
"moe_aux": float(total_aux.detach()) if isinstance(total_aux, torch.Tensor) else 0.0,
|
| 467 |
"mt_loss": float(mt_loss.detach()) if isinstance(mt_loss, torch.Tensor) else 0.0,
|
|
|
|
| 443 |
total_aux = total_aux + aux
|
| 444 |
usages.append(usage.detach())
|
| 445 |
h = self.norm(x)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
loss, mt_loss = None, None
|
| 447 |
if targets is not None:
|
| 448 |
+
# Chunked cross entropy: computes head projection + loss in 256-token chunks
|
| 449 |
+
# Eliminates 300MB+ peak allocation at vocabulary projection on 16GB GPUs
|
| 450 |
+
flat_h = h.reshape(-1, self.args.dim)
|
| 451 |
+
flat_tgt = targets.reshape(-1)
|
| 452 |
+
chunk_size = 256
|
| 453 |
+
n_tokens = flat_tgt.numel()
|
| 454 |
+
total_loss = 0.0
|
| 455 |
+
for ci in range(0, n_tokens, chunk_size):
|
| 456 |
+
ch_h = flat_h[ci : ci + chunk_size]
|
| 457 |
+
ch_tgt = flat_tgt[ci : ci + chunk_size]
|
| 458 |
+
ch_logits = self.head(ch_h)
|
| 459 |
if self.final_softcap > 0:
|
| 460 |
+
ch_logits = self.final_softcap * torch.tanh(ch_logits / self.final_softcap)
|
| 461 |
+
total_loss = total_loss + F.cross_entropy(ch_logits, ch_tgt, reduction="sum")
|
| 462 |
+
loss = total_loss / max(n_tokens, 1)
|
| 463 |
+
|
| 464 |
+
if self.mt_head is not None and T > 1:
|
| 465 |
+
flat_h_mt = h[:, :-1, :].reshape(-1, self.args.dim)
|
| 466 |
+
flat_tgt_mt = targets[:, 1:].reshape(-1)
|
| 467 |
+
n_tokens_mt = flat_tgt_mt.numel()
|
| 468 |
+
total_mt_loss = 0.0
|
| 469 |
+
for ci in range(0, n_tokens_mt, chunk_size):
|
| 470 |
+
ch_h_mt = flat_h_mt[ci : ci + chunk_size]
|
| 471 |
+
ch_tgt_mt = flat_tgt_mt[ci : ci + chunk_size]
|
| 472 |
+
ch_logits_mt = self.mt_head(ch_h_mt)
|
| 473 |
+
if self.final_softcap > 0:
|
| 474 |
+
ch_logits_mt = self.final_softcap * torch.tanh(ch_logits_mt / self.final_softcap)
|
| 475 |
+
total_mt_loss = total_mt_loss + F.cross_entropy(ch_logits_mt, ch_tgt_mt, reduction="sum")
|
| 476 |
+
mt_loss = total_mt_loss / max(n_tokens_mt, 1)
|
| 477 |
loss = loss + 0.1 * mt_loss
|
| 478 |
+
|
| 479 |
if isinstance(total_aux, torch.Tensor):
|
| 480 |
loss = loss + total_aux
|
| 481 |
+
logits = None
|
| 482 |
+
else:
|
| 483 |
+
logits = self.head(h)
|
| 484 |
+
if self.final_softcap > 0:
|
| 485 |
+
logits = self.final_softcap * torch.tanh(logits / self.final_softcap)
|
| 486 |
aux_info = {
|
| 487 |
"moe_aux": float(total_aux.detach()) if isinstance(total_aux, torch.Tensor) else 0.0,
|
| 488 |
"mt_loss": float(mt_loss.detach()) if isinstance(mt_loss, torch.Tensor) else 0.0,
|