Nutral-v2-Tiny / train-GPU.py
Nebulixlabs's picture
Update train-GPU.py
d558f39 verified
Raw
History Blame Contribute Delete
4.14 kB
!pip install safetensors -q
import time
import torch
import torch.nn as nn
from transformers import AutoTokenizer
from datasets import load_dataset
from torch.utils.data import DataLoader
from safetensors.torch import save_file
print("πŸš€ Initializing TINY Model Dual-T4 Master Script...")
# 1. Dataset & Tokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
tokenizer.pad_token = tokenizer.eos_token
print("Downloading Clean TinyStories Dataset...")
dataset = load_dataset("roneneldan/TinyStories", split="train")
small_dataset = dataset.select(range(100000))
def tokenize_function(example):
tokens = tokenizer(example['text'], truncation=True, max_length=512, padding="max_length", return_tensors="pt")
return {"input_ids": tokens["input_ids"][0]}
print("Tokenizing Dataset...")
tokenized_dataset = small_dataset.map(tokenize_function, remove_columns=dataset.column_names, num_proc=4)
tokenized_dataset.set_format("torch")
train_dataloader = DataLoader(tokenized_dataset, batch_size=16, shuffle=True)
# 2. Architecture (5M Params)
class TinyLLM(nn.Module):
def __init__(self, vocab_size=50257, d_model=128, n_heads=4, n_layers=4, max_seq_len=512):
super().__init__()
self.d_model = d_model
self.token_emb = nn.Embedding(vocab_size, d_model)
self.pos_emb = nn.Embedding(max_seq_len, d_model)
decoder_layer = nn.TransformerEncoderLayer(
d_model=d_model, nhead=n_heads, dim_feedforward=4 * d_model,
batch_first=True, activation="gelu"
)
self.transformer = nn.TransformerEncoder(decoder_layer, num_layers=n_layers)
self.lm_head = nn.Linear(d_model, vocab_size, bias=False)
self.token_emb.weight = self.lm_head.weight
# Loss calculation inside forward to prevent GPU 0 OOM
def forward(self, x, labels=None):
seq_len = x.size(1)
mask = nn.Transformer.generate_square_subsequent_mask(seq_len).to(x.device)
positions = torch.arange(0, seq_len, dtype=torch.long, device=x.device).unsqueeze(0)
x = self.token_emb(x) + self.pos_emb(positions)
x = self.transformer(x, mask=mask, is_causal=True)
logits = self.lm_head(x)
if labels is not None:
shift_logits = logits[..., :-1, :].contiguous()
shift_labels = labels[..., 1:].contiguous()
loss_fct = nn.CrossEntropyLoss()
loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
return loss
return logits
# 3. Training Setup
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = TinyLLM()
if torch.cuda.device_count() > 1:
print(f"πŸ”₯ Detected {torch.cuda.device_count()} GPUs! Wrapping model...")
model = nn.DataParallel(model)
model.to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=5e-4)
scaler = torch.amp.GradScaler('cuda')
model.train()
print("πŸ”₯ Starting 50M Token Training on 2x T4...")
start_time = time.time()
for step, batch in enumerate(train_dataloader):
inputs = batch['input_ids'].to(device)
optimizer.zero_grad()
with torch.amp.autocast('cuda'):
loss = model(inputs, labels=inputs).mean()
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
if step % 50 == 0 and step > 0:
elapsed = time.time() - start_time
steps_per_sec = 50 / elapsed
print(f"Step {step} | Loss: {loss.item():.4f} | Speed: {steps_per_sec:.2f} steps/sec")
start_time = time.time()
print("βœ… Dual T4 Training Complete! Saving model...")
# 4. Save Block (Both Formats)
# Remove DataParallel wrapper for saving pure weights
model_to_save = model.module if hasattr(model, 'module') else model
# PyTorch Default Format
torch.save(model_to_save.state_dict(), 'tiny_model_t4.pth')
print("βœ… Saved PyTorch format: 'tiny_model_t4.pth'")
# Safetensors Format
save_file(model_to_save.state_dict(), 'tiny_model_t4.safetensors')
print("βœ… Saved Safetensors format: 'tiny_model_t4.safetensors'")
print("πŸŽ‰ All Done! Download your files from the right panel.")