Tralalabs commited on
Commit
81817a2
·
verified ·
1 Parent(s): 600fce0

Create train.py

Browse files
Files changed (1) hide show
  1. train.py +172 -0
train.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import modal
3
+
4
+ # Offload all the heavy dependency installations to the Modal cloud container
5
+ image = (
6
+ modal.Image.debian_slim()
7
+ .pip_install(
8
+ "transformers",
9
+ "datasets",
10
+ "torch",
11
+ "tokenizers",
12
+ "huggingface_hub",
13
+ "accelerate"
14
+ )
15
+ )
16
+
17
+ app = modal.App("tralalabs-16m-qwen-master-pretrain")
18
+
19
+ @app.function(
20
+ image=image,
21
+ gpu="L40S",
22
+ timeout=86400, # 24 hours max runtime allowed
23
+ secrets=[modal.Secret.from_name("huggingface-secret")]
24
+ )
25
+ def train():
26
+ import torch
27
+ import torch.nn as nn
28
+ from torch.utils.data import IterableDataset, DataLoader
29
+ from datasets import load_dataset
30
+ from tokenizers import Tokenizer, models, trainers, pre_tokenizers
31
+ from transformers import PreTrainedTokenizerFast, Qwen2Config, Qwen2ForCausalLM
32
+ from huggingface_hub import HfApi
33
+ from torch.optim import AdamW
34
+
35
+ print("Initialization started! Fetching data for Tokenizer and Training...")
36
+
37
+ hf_token = os.environ.get("HF_TOKEN")
38
+ if not hf_token:
39
+ print("Error: HF_TOKEN environment variable missing in your Modal secret.")
40
+ return
41
+
42
+ # 1. Stream the 85% / 10% / 5% mix
43
+ try:
44
+ ds_fw_2024 = load_dataset("HuggingFaceFW/fineweb-edu", "CC-MAIN-2024-18", split="train", streaming=True)
45
+ ds_wiki = load_dataset("wikipedia", "20231101.en", split="train", streaming=True)
46
+ ds_fw_2023 = load_dataset("HuggingFaceFW/fineweb-edu", "CC-MAIN-2023-50", split="train", streaming=True)
47
+
48
+ def batch_iterator(batch_size=1000):
49
+ fw_2024_iter = iter(ds_fw_2024)
50
+ wiki_iter = iter(ds_wiki)
51
+ fw_2023_iter = iter(ds_fw_2023)
52
+
53
+ # Infinite loop generator for the massive 81k step pre-training run
54
+ while True:
55
+ batch = []
56
+ for _ in range(int(batch_size * 0.85)): batch.append(next(fw_2024_iter)["text"])
57
+ for _ in range(int(batch_size * 0.10)): batch.append(next(wiki_iter)["text"])
58
+ for _ in range(int(batch_size * 0.05)): batch.append(next(fw_2023_iter)["text"])
59
+ yield batch
60
+ except Exception as e:
61
+ print(f"Error setting up datasets: {e}")
62
+ return
63
+
64
+ # 2. Train Tokenizer (16k Vocab) using the first few batches
65
+ print("Training 16k Byte-Level BPE Tokenizer...")
66
+ raw_tokenizer = Tokenizer(models.BPE(unk_token="<unk>"))
67
+ raw_tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
68
+ trainer = trainers.BpeTrainer(vocab_size=16000, special_tokens=["<unk>", "<s>", "</s>", "<pad>", "<mask>"])
69
+
70
+ # Grab a finite chunk of data to train the vocabulary, then stop
71
+ def tokenizer_iterator():
72
+ iterator = batch_iterator(1000)
73
+ for _ in range(20):
74
+ yield next(iterator)
75
+
76
+ raw_tokenizer.train_from_iterator(tokenizer_iterator(), trainer=trainer)
77
+
78
+ tokenizer = PreTrainedTokenizerFast(
79
+ tokenizer_object=raw_tokenizer,
80
+ bos_token="<s>",
81
+ eos_token="</s>",
82
+ unk_token="<unk>",
83
+ pad_token="<pad>",
84
+ mask_token="<mask>"
85
+ )
86
+ tokenizer.pad_token = "<pad>"
87
+
88
+ os.makedirs("./outputs", exist_ok=True)
89
+ tokenizer.save_pretrained("./outputs")
90
+
91
+ # 3. Model Hyperparameters: 16.7M params Qwen2 Architecture
92
+ print("Configuring 16.7M Parameter Qwen2 Architecture...")
93
+ config = Qwen2Config(
94
+ vocab_size=16000,
95
+ hidden_size=384,
96
+ intermediate_size=1536,
97
+ num_hidden_layers=6,
98
+ num_attention_heads=6,
99
+ num_key_value_heads=2, # GQA activated for maximum efficiency
100
+ max_position_embeddings=1024,
101
+ pad_token_id=3,
102
+ bos_token_id=1,
103
+ eos_token_id=2,
104
+ tie_word_embeddings=True,
105
+ rope_theta=10000.0
106
+ )
107
+
108
+ model = Qwen2ForCausalLM(config).to(device="cuda", dtype=torch.bfloat16)
109
+
110
+ # 4. The 334M Token Training Loop
111
+ print("Tokenizer baked! Starting massive gradient descent pre-training run...")
112
+ optimizer = AdamW(model.parameters(), lr=6e-4, weight_decay=0.1)
113
+ model.train()
114
+
115
+ class ProportionalDataset(IterableDataset):
116
+ def __init__(self, it): self.it = it
117
+ def __iter__(self):
118
+ for batch in self.it:
119
+ for text in batch: yield text
120
+
121
+ train_loader = DataLoader(ProportionalDataset(batch_iterator(batch_size=200)), batch_size=4)
122
+
123
+ step = 0
124
+ # 334,000,000 total tokens / (4 batch size * 1024 sequence length) = 81,543 steps
125
+ TARGET_STEPS = 81543
126
+
127
+ for batch_text in train_loader:
128
+ if step >= TARGET_STEPS:
129
+ break
130
+
131
+ optimizer.zero_grad()
132
+
133
+ encodings = tokenizer(
134
+ batch_text,
135
+ truncation=True,
136
+ max_length=1024,
137
+ padding="max_length",
138
+ return_tensors="pt"
139
+ )
140
+
141
+ input_ids = encodings["input_ids"].to("cuda")
142
+ attention_mask = encodings["attention_mask"].to("cuda")
143
+
144
+ outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=input_ids)
145
+ loss = outputs.loss
146
+
147
+ loss.backward()
148
+ torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
149
+ optimizer.step()
150
+
151
+ # Log every 50 steps so the terminal doesn't get flooded
152
+ if step % 50 == 0:
153
+ print(f"Step {step}/{TARGET_STEPS} | Loss: {loss.item():.4f}")
154
+
155
+ step += 1
156
+
157
+ # 5. Save and Push the Final Master Weights
158
+ print(f"Saving Final Learned Weights after {TARGET_STEPS} steps...")
159
+ model.save_pretrained("./outputs")
160
+
161
+ repo_id = "Tralalabs/TralaLabs-16M-Base"
162
+ try:
163
+ api = HfApi()
164
+ api.create_repo(repo_id=repo_id, token=hf_token, exist_ok=True)
165
+ api.upload_folder(folder_path="./outputs", repo_id=repo_id, repo_type="model", token=hf_token)
166
+ print("Complete master success! Full 334M token Qwen model uploaded.")
167
+ except Exception as e:
168
+ print(f"Error uploading to HF: {e}")
169
+
170
+ @app.local_entrypoint()
171
+ def main():
172
+ train.remote()