sage002 commited on
Commit
00adb8d
·
verified ·
1 Parent(s): e72e9a9

feat: SAGE v2 upgrade (GQA, CoT, W&B, FineWeb-Edu)

Browse files
Files changed (8) hide show
  1. requirements.txt +1 -0
  2. sage/config.py +2 -0
  3. sage/data.py +9 -2
  4. sage/finetune.py +13 -0
  5. sage/memory.py +11 -16
  6. sage/model.py +22 -8
  7. sage/train.py +14 -0
  8. sage_single.py +25 -7
requirements.txt CHANGED
@@ -6,3 +6,4 @@ tqdm>=4.66.1
6
  bitsandbytes>=0.41.0
7
  numpy<2.0.0
8
  huggingface_hub>=0.20.0
 
 
6
  bitsandbytes>=0.41.0
7
  numpy<2.0.0
8
  huggingface_hub>=0.20.0
9
+ wandb>=0.16.0
sage/config.py CHANGED
@@ -7,6 +7,7 @@ class SageConfig:
7
  # Model dimensions corresponding to T4 (16GB VRAM) fit
8
  d_model: int = 512
9
  n_heads: int = 8
 
10
  n_layers: int = 6
11
  d_ff: int = 2048
12
 
@@ -32,6 +33,7 @@ class SageConfig:
32
 
33
  # Checkpointing and path details
34
  checkpoint_dir: str = "checkpoints"
 
35
 
36
  @property
37
  def device(self):
 
7
  # Model dimensions corresponding to T4 (16GB VRAM) fit
8
  d_model: int = 512
9
  n_heads: int = 8
10
+ n_kv_heads: int = 4 # GQA: must divide n_heads
11
  n_layers: int = 6
12
  d_ff: int = 2048
13
 
 
33
 
34
  # Checkpointing and path details
35
  checkpoint_dir: str = "checkpoints"
36
+ project_name: str = "sage-v2"
37
 
38
  @property
39
  def device(self):
sage/data.py CHANGED
@@ -79,7 +79,7 @@ class StreamingTextDataset(IterableDataset):
79
 
80
  def __init__(
81
  self,
82
- dataset_name: str = "roneneldan/TinyStories",
83
  split: str = "train",
84
  seq_len: int = 512,
85
  tokenizer: Optional[SageTokenizer] = None,
@@ -97,6 +97,13 @@ class StreamingTextDataset(IterableDataset):
97
  self.text_field = text_field
98
  self.min_doc_len = min_doc_len
99
  self.max_doc_len = max_doc_len
 
 
 
 
 
 
 
100
 
101
  def _stream_tokens(self) -> Iterator[int]:
102
  """Yields individual token IDs from the HuggingFace dataset stream."""
@@ -164,7 +171,7 @@ class StreamingTextDataset(IterableDataset):
164
 
165
  def create_dataloader(
166
  config: SageConfig,
167
- dataset_name: str = "roneneldan/TinyStories",
168
  split: str = "train",
169
  tokenizer: Optional[SageTokenizer] = None,
170
  ) -> DataLoader:
 
79
 
80
  def __init__(
81
  self,
82
+ dataset_name: str = "HuggingFaceFW/fineweb-edu",
83
  split: str = "train",
84
  seq_len: int = 512,
85
  tokenizer: Optional[SageTokenizer] = None,
 
97
  self.text_field = text_field
98
  self.min_doc_len = min_doc_len
99
  self.max_doc_len = max_doc_len
100
+
101
+ # Auto-adjust configuration based on popular datasets
102
+ if "fineweb-edu" in dataset_name.lower():
103
+ self.text_field = "text"
104
+ self.split = "train" if split == "train" else split
105
+ elif "tinystories" in dataset_name.lower():
106
+ self.text_field = "text"
107
 
108
  def _stream_tokens(self) -> Iterator[int]:
109
  """Yields individual token IDs from the HuggingFace dataset stream."""
 
171
 
172
  def create_dataloader(
173
  config: SageConfig,
174
+ dataset_name: str = "HuggingFaceFW/fineweb-edu",
175
  split: str = "train",
176
  tokenizer: Optional[SageTokenizer] = None,
177
  ) -> DataLoader:
sage/finetune.py CHANGED
@@ -16,6 +16,7 @@ import torch
16
  import torch.nn as nn
17
  from torch.amp import GradScaler, autocast
18
  from tqdm import tqdm
 
19
  from typing import Optional, List
20
 
21
  from .config import SageConfig
@@ -156,6 +157,13 @@ def finetune_instruction(
156
  if use_lora:
157
  model = inject_lora(model, rank=lora_rank)
158
 
 
 
 
 
 
 
 
159
  optimizer = create_optimizer(model, config)
160
 
161
  # AMP setup
@@ -213,6 +221,10 @@ def finetune_instruction(
213
  avg = accum_loss / 10
214
  pbar.set_postfix(loss=f"{avg:.4f}", lr=f"{lr:.2e}")
215
  logger.info(f"finetune step={step+1} | loss={avg:.4f}")
 
 
 
 
216
  accum_loss = 0.0
217
 
218
  # Merge LoRA weights back for clean inference
@@ -221,6 +233,7 @@ def finetune_instruction(
221
 
222
  save_checkpoint(model, None, total_steps, config.checkpoint_dir, filename="sage_finetuned.pt")
223
  logger.info("Instruction fine-tuning complete. Checkpoint saved as sage_finetuned.pt")
 
224
  return model
225
 
226
 
 
16
  import torch.nn as nn
17
  from torch.amp import GradScaler, autocast
18
  from tqdm import tqdm
19
+ import wandb
20
  from typing import Optional, List
21
 
22
  from .config import SageConfig
 
157
  if use_lora:
158
  model = inject_lora(model, rank=lora_rank)
159
 
160
+ # ------- W&B Logging -------
161
+ wandb.init(
162
+ project=config.project_name,
163
+ name=f"finetune-{time.strftime('%Y%m%d-%H%M')}",
164
+ config=config.__dict__,
165
+ )
166
+
167
  optimizer = create_optimizer(model, config)
168
 
169
  # AMP setup
 
221
  avg = accum_loss / 10
222
  pbar.set_postfix(loss=f"{avg:.4f}", lr=f"{lr:.2e}")
223
  logger.info(f"finetune step={step+1} | loss={avg:.4f}")
224
+ wandb.log({
225
+ "finetune/loss": avg,
226
+ "finetune/lr": lr,
227
+ }, step=step + 1)
228
  accum_loss = 0.0
229
 
230
  # Merge LoRA weights back for clean inference
 
233
 
234
  save_checkpoint(model, None, total_steps, config.checkpoint_dir, filename="sage_finetuned.pt")
235
  logger.info("Instruction fine-tuning complete. Checkpoint saved as sage_finetuned.pt")
236
+ wandb.finish()
237
  return model
238
 
239
 
sage/memory.py CHANGED
@@ -178,22 +178,17 @@ class RAGManager:
178
  # ===================================================================
179
 
180
  DEFAULT_SYSTEM_PROMPT = (
181
- "You are a high-quality reasoning assistant model.\n"
182
- "You must ONLY learn from high-quality instruction and reasoning datasets.\n"
183
- "You must IGNORE any previously trained low-quality or repetitive patterns.\n"
184
- "\n"
185
- "Training preference rules:\n"
186
- "1. Prioritize step-by-step reasoning over short or repetitive answers.\n"
187
- "2. Always produce structured logical explanations when solving problems.\n"
188
- "3. Avoid repetition, filler words, or looped phrases.\n"
189
- "4. Prefer datasets with mathematical reasoning and high-quality instruction.\n"
190
- "5. Do not imitate noisy conversational or corrupted text patterns.\n"
191
- "6. Always prefer clarity, correctness, and structured reasoning.\n"
192
- "\n"
193
- "Output behavior goal:\n"
194
- "- Think in steps.\n"
195
- "- Explain logic clearly.\n"
196
- "- Produce final answer only after reasoning."
197
  )
198
 
199
  class ConversationHistory:
 
178
  # ===================================================================
179
 
180
  DEFAULT_SYSTEM_PROMPT = (
181
+ "You are SAGE, a high-quality reasoning assistant. "
182
+ "Your goal is to provide accurate, structured, and deep logical explanations.\n\n"
183
+ "CRITICAL GUIDELINES:\n"
184
+ "1. THINKING PHASE: You must ALWAYS start your response with a <thinking> section. "
185
+ "In this section, break down the user's request, identify key constraints, and plan your logical steps.\n"
186
+ "2. RESPONSE PHASE: After completing your internal reasoning, provide your final answer within <response> tags.\n"
187
+ "3. QUALITY: Prioritize step-by-step mathematical or logical derivation over short answers.\n"
188
+ "4. NO REPETITION: Avoid filler words or circular logic.\n\n"
189
+ "RESPONSE TEMPLATE:\n"
190
+ "<thinking>\n[Step-by-step logic here]\n</thinking>\n"
191
+ "<response>\n[Final clear answer here]\n</response>"
 
 
 
 
 
192
  )
193
 
194
  class ConversationHistory:
sage/model.py CHANGED
@@ -32,17 +32,30 @@ def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor
32
 
33
  return xq_out.type_as(xq), xk_out.type_as(xk)
34
 
 
 
 
 
 
 
 
 
 
 
 
35
  class CausalSelfAttention(nn.Module):
36
  def __init__(self, config: SageConfig):
37
  super().__init__()
38
  self.n_heads = config.n_heads
 
 
39
  self.d_model = config.d_model
40
  assert self.d_model % self.n_heads == 0
41
  self.head_dim = self.d_model // self.n_heads
42
 
43
- self.wq = nn.Linear(self.d_model, self.d_model, bias=False)
44
- self.wk = nn.Linear(self.d_model, self.d_model, bias=False)
45
- self.wv = nn.Linear(self.d_model, self.d_model, bias=False)
46
  self.wo = nn.Linear(self.d_model, self.d_model, bias=False)
47
 
48
  self.resid_dropout = nn.Dropout(config.dropout)
@@ -54,14 +67,11 @@ class CausalSelfAttention(nn.Module):
54
  x: torch.Tensor,
55
  freqs_cis: torch.Tensor,
56
  kv_cache: Optional[Tuple[torch.Tensor, torch.Tensor]] = None
57
- ) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, torch.Tensor]]]:
58
- B, T, C = x.size() # batch, seq_len, d_model
59
-
60
  q, k, v = self.wq(x), self.wk(x), self.wv(x)
61
 
62
  q = q.view(B, T, self.n_heads, self.head_dim)
63
- k = k.view(B, T, self.n_heads, self.head_dim)
64
- v = v.view(B, T, self.n_heads, self.head_dim)
65
 
66
  q, k = apply_rotary_emb(q, k, freqs_cis)
67
 
@@ -74,6 +84,10 @@ class CausalSelfAttention(nn.Module):
74
  else:
75
  new_kv_cache = None
76
 
 
 
 
 
77
  # Move heads to correct dimension: (B, n_heads, T, head_dim)
78
  q = q.transpose(1, 2)
79
  k = k.transpose(1, 2)
 
32
 
33
  return xq_out.type_as(xq), xk_out.type_as(xk)
34
 
35
+ def repeat_kv(x: torch.Tensor, n_rep: int) -> torch.Tensor:
36
+ """Repeat Key/Value heads n_rep times to match number of Query heads."""
37
+ if n_rep == 1:
38
+ return x
39
+ B, T, n_kv_heads, head_dim = x.size()
40
+ return (
41
+ x[:, :, :, None, :]
42
+ .expand(B, T, n_kv_heads, n_rep, head_dim)
43
+ .reshape(B, T, n_kv_heads * n_rep, head_dim)
44
+ )
45
+
46
  class CausalSelfAttention(nn.Module):
47
  def __init__(self, config: SageConfig):
48
  super().__init__()
49
  self.n_heads = config.n_heads
50
+ self.n_kv_heads = config.n_kv_heads
51
+ self.n_rep = self.n_heads // self.n_kv_heads
52
  self.d_model = config.d_model
53
  assert self.d_model % self.n_heads == 0
54
  self.head_dim = self.d_model // self.n_heads
55
 
56
+ self.wq = nn.Linear(self.d_model, self.n_heads * self.head_dim, bias=False)
57
+ self.wk = nn.Linear(self.d_model, self.n_kv_heads * self.head_dim, bias=False)
58
+ self.wv = nn.Linear(self.d_model, self.n_kv_heads * self.head_dim, bias=False)
59
  self.wo = nn.Linear(self.d_model, self.d_model, bias=False)
60
 
61
  self.resid_dropout = nn.Dropout(config.dropout)
 
67
  x: torch.Tensor,
68
  freqs_cis: torch.Tensor,
69
  kv_cache: Optional[Tuple[torch.Tensor, torch.Tensor]] = None
 
 
 
70
  q, k, v = self.wq(x), self.wk(x), self.wv(x)
71
 
72
  q = q.view(B, T, self.n_heads, self.head_dim)
73
+ k = k.view(B, T, self.n_kv_heads, self.head_dim)
74
+ v = v.view(B, T, self.n_kv_heads, self.head_dim)
75
 
76
  q, k = apply_rotary_emb(q, k, freqs_cis)
77
 
 
84
  else:
85
  new_kv_cache = None
86
 
87
+ # Repeat KV heads to match Q heads (GQA)
88
+ k = repeat_kv(k, self.n_rep)
89
+ v = repeat_kv(v, self.n_rep)
90
+
91
  # Move heads to correct dimension: (B, n_heads, T, head_dim)
92
  q = q.transpose(1, 2)
93
  k = k.transpose(1, 2)
sage/train.py CHANGED
@@ -11,6 +11,7 @@ import torch
11
  import torch.nn as nn
12
  from torch.amp import GradScaler, autocast
13
  from tqdm import tqdm
 
14
  from typing import Optional
15
 
16
  from .config import SageConfig
@@ -140,6 +141,13 @@ def train(
140
  loader = create_dataloader(config, dataset_name=dataset_name, tokenizer=tok)
141
  data_iter = iter(loader)
142
 
 
 
 
 
 
 
 
143
  # ------- gradient checkpointing (saves VRAM) -------
144
  base_model = getattr(model, "module", model)
145
  if hasattr(base_model, "layers"):
@@ -220,6 +228,11 @@ def train(
220
  logger.info(
221
  f"step={step+1} | loss={avg_loss:.4f} | ppl={perplexity:.2f} | lr={lr:.2e}"
222
  )
 
 
 
 
 
223
  accum_loss = 0.0
224
 
225
  # ------- checkpoint every 100 steps -------
@@ -228,4 +241,5 @@ def train(
228
  logger.info(f"Checkpoint saved at step {step + 1}")
229
 
230
  logger.info("Training complete.")
 
231
  return model
 
11
  import torch.nn as nn
12
  from torch.amp import GradScaler, autocast
13
  from tqdm import tqdm
14
+ import wandb
15
  from typing import Optional
16
 
17
  from .config import SageConfig
 
141
  loader = create_dataloader(config, dataset_name=dataset_name, tokenizer=tok)
142
  data_iter = iter(loader)
143
 
144
+ # ------- W&B Logging -------
145
+ wandb.init(
146
+ project=config.project_name,
147
+ name=f"pretrain-{time.strftime('%Y%m%d-%H%M')}",
148
+ config=config.__dict__,
149
+ )
150
+
151
  # ------- gradient checkpointing (saves VRAM) -------
152
  base_model = getattr(model, "module", model)
153
  if hasattr(base_model, "layers"):
 
228
  logger.info(
229
  f"step={step+1} | loss={avg_loss:.4f} | ppl={perplexity:.2f} | lr={lr:.2e}"
230
  )
231
+ wandb.log({
232
+ "train/loss": avg_loss,
233
+ "train/perplexity": perplexity,
234
+ "train/lr": lr,
235
+ }, step=step + 1)
236
  accum_loss = 0.0
237
 
238
  # ------- checkpoint every 100 steps -------
 
241
  logger.info(f"Checkpoint saved at step {step + 1}")
242
 
243
  logger.info("Training complete.")
244
+ wandb.finish()
245
  return model
sage_single.py CHANGED
@@ -30,6 +30,7 @@ from torch.amp import GradScaler, autocast
30
  from torch.utils.data import IterableDataset, DataLoader
31
  from tqdm import tqdm
32
  import tiktoken
 
33
 
34
  __version__ = "1.0.0"
35
 
@@ -42,6 +43,7 @@ __version__ = "1.0.0"
42
  class SageConfig:
43
  d_model: int = 512
44
  n_heads: int = 8
 
45
  n_layers: int = 6
46
  d_ff: int = 2048
47
  n_experts: int = 4
@@ -57,6 +59,7 @@ class SageConfig:
57
  weight_decay: float = 0.01
58
  max_grad_norm: float = 1.0
59
  checkpoint_dir: str = "checkpoints"
 
60
 
61
  @property
62
  def device(self):
@@ -151,15 +154,22 @@ def apply_rotary_emb(xq, xk, freqs_cis):
151
  xk_out = torch.view_as_real(xk_ * fc).flatten(3)
152
  return xq_out.type_as(xq), xk_out.type_as(xk)
153
 
 
 
 
 
 
154
  class CausalSelfAttention(nn.Module):
155
  def __init__(self, config):
156
  super().__init__()
157
  self.n_heads = config.n_heads
 
 
158
  self.d_model = config.d_model
159
  self.head_dim = config.d_model // config.n_heads
160
- self.wq = nn.Linear(config.d_model, config.d_model, bias=False)
161
- self.wk = nn.Linear(config.d_model, config.d_model, bias=False)
162
- self.wv = nn.Linear(config.d_model, config.d_model, bias=False)
163
  self.wo = nn.Linear(config.d_model, config.d_model, bias=False)
164
  self.resid_dropout = nn.Dropout(config.dropout)
165
 
@@ -167,8 +177,8 @@ class CausalSelfAttention(nn.Module):
167
  B, T, C = x.size()
168
  q, k, v = self.wq(x), self.wk(x), self.wv(x)
169
  q = q.view(B, T, self.n_heads, self.head_dim)
170
- k = k.view(B, T, self.n_heads, self.head_dim)
171
- v = v.view(B, T, self.n_heads, self.head_dim)
172
  q, k = apply_rotary_emb(q, k, freqs_cis)
173
  if kv_cache is not None:
174
  k = torch.cat([kv_cache[0], k], dim=1)
@@ -176,6 +186,7 @@ class CausalSelfAttention(nn.Module):
176
  new_kv = (k, v)
177
  else:
178
  new_kv = None
 
179
  q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2)
180
  is_causal = kv_cache is None and T > 1
181
  try:
@@ -293,11 +304,13 @@ def clean_text(text):
293
  return text.strip()
294
 
295
  class StreamingTextDataset(IterableDataset):
296
- def __init__(self, dataset_name="roneneldan/TinyStories", split="train", seq_len=512, tokenizer=None, buffer_size=1000, text_field="text"):
297
  super().__init__()
298
  self.dataset_name, self.split, self.seq_len = dataset_name, split, seq_len
299
  self.tokenizer = tokenizer or SageTokenizer()
300
  self.buffer_size, self.text_field = buffer_size, text_field
 
 
301
 
302
  def _tokens(self):
303
  from datasets import load_dataset
@@ -321,7 +334,7 @@ class StreamingTextDataset(IterableDataset):
321
  random.shuffle(buf)
322
  yield from buf
323
 
324
- def create_dataloader(config, dataset_name="roneneldan/TinyStories", tokenizer=None):
325
  tok = tokenizer or SageTokenizer()
326
  ds = StreamingTextDataset(dataset_name=dataset_name, seq_len=config.max_seq_len, tokenizer=tok)
327
  return DataLoader(ds, batch_size=config.batch_size, num_workers=0, pin_memory=True, drop_last=True)
@@ -362,6 +375,7 @@ def train_model(model, config, total_steps=500, dataset_name="roneneldan/TinySto
362
  scaler = GradScaler("cuda", enabled=use_amp and amp_dtype == torch.float16)
363
  loader = create_dataloader(config, dataset_name, tok)
364
  data_iter = iter(loader)
 
365
  model.train()
366
  accum_loss, t0 = 0.0, time.time()
367
  pbar = tqdm(range(start_step, total_steps), desc="Training")
@@ -387,11 +401,13 @@ def train_model(model, config, total_steps=500, dataset_name="roneneldan/TinySto
387
  if (step + 1) % 10 == 0:
388
  avg = accum_loss / 10
389
  pbar.set_postfix(loss=f"{avg:.4f}", ppl=f"{math.exp(min(avg,20)):.1f}", lr=f"{lr:.2e}")
 
390
  accum_loss = 0.0
391
  if (step + 1) % 100 == 0:
392
  save_checkpoint(model, opt, step + 1, config.checkpoint_dir)
393
  save_checkpoint(model, opt, total_steps, config.checkpoint_dir)
394
  logger.info("Training complete.")
 
395
  return model
396
 
397
 
@@ -517,6 +533,7 @@ def finetune(model, config, samples=None, steps=200, use_lora=True, tokenizer=No
517
  use_amp = device.type == "cuda"
518
  amp_dtype = torch.bfloat16 if use_amp and torch.cuda.is_bf16_supported() else torch.float16
519
  scaler = GradScaler("cuda", enabled=use_amp and amp_dtype == torch.float16)
 
520
  model.train(); accum = 0.0
521
  for step in tqdm(range(steps), desc="Fine-tuning"):
522
  lr = get_lr(step, config, steps)
@@ -537,6 +554,7 @@ def finetune(model, config, samples=None, steps=200, use_lora=True, tokenizer=No
537
  if use_lora: model = merge_lora(model)
538
  save_checkpoint(model, None, steps, config.checkpoint_dir, "sage_finetuned.pt")
539
  logger.info("Fine-tuning complete.")
 
540
  return model
541
 
542
 
 
30
  from torch.utils.data import IterableDataset, DataLoader
31
  from tqdm import tqdm
32
  import tiktoken
33
+ import wandb
34
 
35
  __version__ = "1.0.0"
36
 
 
43
  class SageConfig:
44
  d_model: int = 512
45
  n_heads: int = 8
46
+ n_kv_heads: int = 4
47
  n_layers: int = 6
48
  d_ff: int = 2048
49
  n_experts: int = 4
 
59
  weight_decay: float = 0.01
60
  max_grad_norm: float = 1.0
61
  checkpoint_dir: str = "checkpoints"
62
+ project_name: str = "sage-v2"
63
 
64
  @property
65
  def device(self):
 
154
  xk_out = torch.view_as_real(xk_ * fc).flatten(3)
155
  return xq_out.type_as(xq), xk_out.type_as(xk)
156
 
157
+ def repeat_kv(x, n_rep):
158
+ if n_rep == 1: return x
159
+ B, T, n_kv_heads, head_dim = x.size()
160
+ return x[:, :, :, None, :].expand(B, T, n_kv_heads, n_rep, head_dim).reshape(B, T, n_kv_heads * n_rep, head_dim)
161
+
162
  class CausalSelfAttention(nn.Module):
163
  def __init__(self, config):
164
  super().__init__()
165
  self.n_heads = config.n_heads
166
+ self.n_kv_heads = config.n_kv_heads
167
+ self.n_rep = self.n_heads // self.n_kv_heads
168
  self.d_model = config.d_model
169
  self.head_dim = config.d_model // config.n_heads
170
+ self.wq = nn.Linear(config.d_model, config.n_heads * self.head_dim, bias=False)
171
+ self.wk = nn.Linear(config.d_model, config.n_kv_heads * self.head_dim, bias=False)
172
+ self.wv = nn.Linear(config.d_model, config.n_kv_heads * self.head_dim, bias=False)
173
  self.wo = nn.Linear(config.d_model, config.d_model, bias=False)
174
  self.resid_dropout = nn.Dropout(config.dropout)
175
 
 
177
  B, T, C = x.size()
178
  q, k, v = self.wq(x), self.wk(x), self.wv(x)
179
  q = q.view(B, T, self.n_heads, self.head_dim)
180
+ k = k.view(B, T, self.n_kv_heads, self.head_dim)
181
+ v = v.view(B, T, self.n_kv_heads, self.head_dim)
182
  q, k = apply_rotary_emb(q, k, freqs_cis)
183
  if kv_cache is not None:
184
  k = torch.cat([kv_cache[0], k], dim=1)
 
186
  new_kv = (k, v)
187
  else:
188
  new_kv = None
189
+ k, v = repeat_kv(k, self.n_rep), repeat_kv(v, self.n_rep)
190
  q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2)
191
  is_causal = kv_cache is None and T > 1
192
  try:
 
304
  return text.strip()
305
 
306
  class StreamingTextDataset(IterableDataset):
307
+ def __init__(self, dataset_name="HuggingFaceFW/fineweb-edu", split="train", seq_len=512, tokenizer=None, buffer_size=1000, text_field="text"):
308
  super().__init__()
309
  self.dataset_name, self.split, self.seq_len = dataset_name, split, seq_len
310
  self.tokenizer = tokenizer or SageTokenizer()
311
  self.buffer_size, self.text_field = buffer_size, text_field
312
+ if "fineweb-edu" in dataset_name.lower(): self.text_field = "text"
313
+ elif "tinystories" in dataset_name.lower(): self.text_field = "text"
314
 
315
  def _tokens(self):
316
  from datasets import load_dataset
 
334
  random.shuffle(buf)
335
  yield from buf
336
 
337
+ def create_dataloader(config, dataset_name="HuggingFaceFW/fineweb-edu", tokenizer=None):
338
  tok = tokenizer or SageTokenizer()
339
  ds = StreamingTextDataset(dataset_name=dataset_name, seq_len=config.max_seq_len, tokenizer=tok)
340
  return DataLoader(ds, batch_size=config.batch_size, num_workers=0, pin_memory=True, drop_last=True)
 
375
  scaler = GradScaler("cuda", enabled=use_amp and amp_dtype == torch.float16)
376
  loader = create_dataloader(config, dataset_name, tok)
377
  data_iter = iter(loader)
378
+ wandb.init(project=config.project_name, name=f"pretrain-{time.strftime('%Y%m%d-%H%M')}", config=config.__dict__)
379
  model.train()
380
  accum_loss, t0 = 0.0, time.time()
381
  pbar = tqdm(range(start_step, total_steps), desc="Training")
 
401
  if (step + 1) % 10 == 0:
402
  avg = accum_loss / 10
403
  pbar.set_postfix(loss=f"{avg:.4f}", ppl=f"{math.exp(min(avg,20)):.1f}", lr=f"{lr:.2e}")
404
+ wandb.log({"train/loss": avg, "train/perplexity": math.exp(min(avg, 20)), "train/lr": lr}, step=step + 1)
405
  accum_loss = 0.0
406
  if (step + 1) % 100 == 0:
407
  save_checkpoint(model, opt, step + 1, config.checkpoint_dir)
408
  save_checkpoint(model, opt, total_steps, config.checkpoint_dir)
409
  logger.info("Training complete.")
410
+ wandb.finish()
411
  return model
412
 
413
 
 
533
  use_amp = device.type == "cuda"
534
  amp_dtype = torch.bfloat16 if use_amp and torch.cuda.is_bf16_supported() else torch.float16
535
  scaler = GradScaler("cuda", enabled=use_amp and amp_dtype == torch.float16)
536
+ wandb.init(project=config.project_name, name=f"finetune-{time.strftime('%Y%m%d-%H%M')}", config=config.__dict__)
537
  model.train(); accum = 0.0
538
  for step in tqdm(range(steps), desc="Fine-tuning"):
539
  lr = get_lr(step, config, steps)
 
554
  if use_lora: model = merge_lora(model)
555
  save_checkpoint(model, None, steps, config.checkpoint_dir, "sage_finetuned.pt")
556
  logger.info("Fine-tuning complete.")
557
+ wandb.finish()
558
  return model
559
 
560