File size: 14,908 Bytes
3c6797b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
import os
import shutil
import jax
import jax.numpy as jnp
import flax.linen as nn
import optax
from flax.training import train_state
from flax import jax_utils
import orbax.checkpoint as ocp
import numpy as np
from functools import partial
from datasets import load_dataset
from transformers import AutoTokenizer
from huggingface_hub import HfApi, login
import traceback # Error details dekhne ke liye

# ... (Upar ka Config, Attention, Model aur Data Loaders wala code same rahega) ...
# ==========================================
# 1. 200M MODEL CONFIGURATION (SCALED UP)
# ==========================================
class ProdModelConfig:
    vocab_size = 32000
    hidden_size = 896        # Scaled up for ~200M
    intermediate_size = 3584 # 4x hidden_size
    num_attention_heads = 14 # 896 / 14 = 64 dimension per head
    num_layers = 18          # Increased depth
    max_thought_loops = 6    
    num_memory_tokens = 16   
    context_length = 496     
    dtype = jnp.bfloat16     

# ==========================================
# 2. KV CACHE & SELF-ATTENTION WITH ROPE
# ==========================================
def rotate_half(x):
    x1 = x[..., : x.shape[-1] // 2]
    x2 = x[..., x.shape[-1] // 2 :]
    return jnp.concatenate([-x2, x1], axis=-1)

def apply_rope(xq, xk, position, dtype):
    dim = xq.shape[-1]
    inv_freq = 1.0 / (10000 ** (jnp.arange(0, dim, 2, dtype=jnp.float32) / dim))
    freqs = jnp.einsum("i,j->ij", position, inv_freq)
    emb = jnp.concatenate([freqs, freqs], axis=-1)
    cos = jnp.cos(emb)[None, :, None, :].astype(dtype)
    sin = jnp.sin(emb)[None, :, None, :].astype(dtype)
    return (xq * cos) + (rotate_half(xq) * sin), (xk * cos) + (rotate_half(xk) * sin)

class CausalAttentionWithRoPE(nn.Module):
    config: ProdModelConfig

    @nn.compact
    def __call__(self, x, mask=None, decode=False):
        B, S, C = x.shape
        H = self.config.num_attention_heads
        D = C // H
        
        q = nn.Dense(C, use_bias=False, dtype=self.config.dtype)(x)
        k = nn.Dense(C, use_bias=False, dtype=self.config.dtype)(x)
        v = nn.Dense(C, use_bias=False, dtype=self.config.dtype)(x)
        
        q = q.reshape(B, S, H, D)
        k = k.reshape(B, S, H, D)
        v = v.reshape(B, S, H, D)
        
        if decode:
            is_initialized = self.has_variable('cache', 'cached_key')
            cached_key = self.variable('cache', 'cached_key', jnp.zeros, (B, self.config.context_length, H, D), k.dtype)
            cached_value = self.variable('cache', 'cached_value', jnp.zeros, (B, self.config.context_length, H, D), v.dtype)
            cache_index = self.variable('cache', 'cache_index', lambda: jnp.array(0, dtype=jnp.int32))
            
            if is_initialized:
                idx = cache_index.value
                k = cached_key.value.at[:, idx:idx+S].set(k)
                v = cached_value.value.at[:, idx:idx+S].set(v)
                cache_index.value = idx + S
                positions = jnp.arange(idx, idx + S)
            else:
                positions = jnp.arange(S)
        else:
            positions = jnp.arange(S)
            
        q, k = apply_rope(q, k, positions, self.config.dtype)
        
        scores = jnp.einsum('bqhd,bkhd->bhqk', q, k) / jnp.sqrt(D).astype(self.config.dtype)
        if mask is not None:
            scores = jnp.where(mask, scores, -10000.0)
            
        attn_weights = jax.nn.softmax(scores, axis=-1)
        out = jnp.einsum('bhqk,bkhd->bqhd', attn_weights, v).reshape(B, S, C)
        return nn.Dense(C, use_bias=False, dtype=self.config.dtype)(out)

class MLPBlock(nn.Module):
    config: ProdModelConfig
    @nn.compact
    def __call__(self, x):
        h = nn.Dense(self.config.intermediate_size, use_bias=False, dtype=self.config.dtype)(x)
        h = jax.nn.silu(h)
        return nn.Dense(self.config.hidden_size, use_bias=False, dtype=self.config.dtype)(h)

class TransformerBlock(nn.Module):
    config: ProdModelConfig
    @nn.compact
    def __call__(self, x, mask=None, decode=False):
        attn_in = nn.RMSNorm(dtype=self.config.dtype)(x)
        x = x + CausalAttentionWithRoPE(self.config)(attn_in, mask=mask, decode=decode)
        
        mlp_in = nn.RMSNorm(dtype=self.config.dtype)(x)
        x = x + MLPBlock(self.config)(mlp_in)
        return x

class DynamicThinkingLM(nn.Module):
    config: ProdModelConfig
    @nn.compact
    def __call__(self, input_ids, decode=False):
        batch_size, seq_len = input_ids.shape
        total_len = seq_len + self.config.num_memory_tokens
        
        x = nn.Embed(self.config.vocab_size, self.config.hidden_size, dtype=self.config.dtype)(input_ids)
        memory_tokens = self.param('memory_tokens', jax.nn.initializers.normal(stddev=0.02), (1, self.config.num_memory_tokens, self.config.hidden_size))
        memory_tokens = jnp.broadcast_to(memory_tokens, (batch_size, self.config.num_memory_tokens, self.config.hidden_size)).astype(self.config.dtype)
        
        if not decode:
            x = jnp.concatenate([memory_tokens, x], axis=1)
            causal_mask = jnp.tril(jnp.ones((1, 1, total_len, total_len), dtype=bool))
        else:
            causal_mask = None 

        for i in range(self.config.num_layers):
            x = TransformerBlock(self.config, name=f"perception_{i}")(x, mask=causal_mask, decode=decode)
            
        reasoning_core = TransformerBlock(self.config, name="reasoning_core")
        halt_classifier = nn.Dense(1, use_bias=False, dtype=jnp.float32)
        
        accumulated_state = jnp.zeros_like(x)
        remainders = jnp.ones((batch_size, 1, 1))
        halt_probs_sum = jnp.zeros((batch_size, 1, 1))
        ponder_steps = jnp.zeros((batch_size, 1, 1))

        for _ in range(self.config.max_thought_loops):
            x = reasoning_core(x, mask=causal_mask, decode=decode)
            p_halt = jax.nn.sigmoid(halt_classifier(jnp.mean(x, axis=1, keepdims=True)))
            still_thinking = (halt_probs_sum < 1.0).astype(jnp.float32)
            p_step = jnp.where(halt_probs_sum + p_halt > 1.0, remainders, p_halt) * still_thinking
            
            halt_probs_sum += p_step
            remainders -= p_step
            ponder_steps += still_thinking
            accumulated_state += p_step.astype(self.config.dtype) * x

        x = nn.RMSNorm(dtype=self.config.dtype)(accumulated_state)
        
        if not decode:
            x = x[:, self.config.num_memory_tokens:, :] 
            
        logits = nn.Dense(self.config.vocab_size, use_bias=False, dtype=self.config.dtype)(x)
        return logits, ponder_steps

# ==========================================
# 3. DATA LOADERS (Streaming - Web, Chat, Math)
# ==========================================
tokenizer = AutoTokenizer.from_pretrained("huggyllama/llama-7b")
tokenizer.pad_token = tokenizer.eos_token 

def create_fineweb_stream(global_batch_size, seq_len):
    dataset = load_dataset("HuggingFaceFW/fineweb-edu", name="sample-10BT", split="train", streaming=True)
    buffer = []
    for example in dataset:
        buffer.extend(tokenizer(example['text'])['input_ids'])
        while len(buffer) >= global_batch_size * seq_len:
            batch = buffer[:global_batch_size * seq_len]
            buffer = buffer[global_batch_size * seq_len:]
            yield np.array(batch, dtype=np.int32).reshape(global_batch_size, seq_len)

def create_chat_stream(global_batch_size, seq_len):
    dataset = load_dataset("yahma/alpaca-cleaned", split="train", streaming=True)
    buffer = []
    for example in dataset:
        chat_text = f"[INST] {example['instruction']} [/INST] {example['output']} {tokenizer.eos_token}"
        buffer.extend(tokenizer(chat_text)['input_ids'])
        while len(buffer) >= global_batch_size * seq_len:
            batch = buffer[:global_batch_size * seq_len]
            buffer = buffer[global_batch_size * seq_len:]
            yield np.array(batch, dtype=np.int32).reshape(global_batch_size, seq_len)

def create_math_stream(global_batch_size, seq_len):
    # Math dataset for logical reasoning
    dataset = load_dataset("meta-math/MetaMathQA", split="train", streaming=True)
    buffer = []
    for example in dataset:
        math_text = f"[INST] Solve this math problem: {example['query']} [/INST] {example['response']} {tokenizer.eos_token}"
        buffer.extend(tokenizer(math_text)['input_ids'])
        while len(buffer) >= global_batch_size * seq_len:
            batch = buffer[:global_batch_size * seq_len]
            buffer = buffer[global_batch_size * seq_len:]
            yield np.array(batch, dtype=np.int32).reshape(global_batch_size, seq_len)
# ==========================================
# 4. HIGH-STEP 8B TOKENS TRAINING LOOP (WITH FAILSAFE)
# ==========================================
def main():
    # 1️⃣ HARDCODED HUGGING FACE TOKEN
    # Yahan apni asli token daalein "hf_..."
    hf_token = "hf_mpvCHCISxesjIaGXwaumyxJlyTzRRMuf" 
    print("πŸ”‘ Logging into Hugging Face...")
    login(token=hf_token)

    num_devices = jax.device_count()
    print(f"πŸš€ Initializing on {num_devices} TPU cores!")

    config = ProdModelConfig()
    
    per_device_batch = 16 
    global_batch_size = per_device_batch * num_devices 
    tokens_per_step = global_batch_size * config.context_length
    print(f"πŸ“¦ Global Batch: {global_batch_size} | Tokens/Step: {tokens_per_step:,}")

    fineweb_loader = create_fineweb_stream(global_batch_size, config.context_length)
    chat_loader = create_chat_stream(global_batch_size, config.context_length)
    math_loader = create_math_stream(global_batch_size, config.context_length)

    model = DynamicThinkingLM(config)
    rng = jax.random.PRNGKey(42)
    dummy_input = jnp.ones((1, config.context_length), dtype=jnp.int32)
    params = model.init(rng, dummy_input)

    switch_step = 110250  
    total_steps = 126000 
    
    tx = optax.chain(
        optax.clip_by_global_norm(1.0),
        optax.adamw(learning_rate=optax.cosine_decay_schedule(4e-4, total_steps), weight_decay=0.1)
    )
    
    state = train_state.TrainState.create(apply_fn=model.apply, params=params, tx=tx)
    state = jax_utils.replicate(state)

    def loss_fn(params, batch):
        logits, ponder_steps = model.apply(params, batch)
        shift_logits = logits[..., :-1, :]
        shift_labels = batch[..., 1:]
        ce_loss = optax.softmax_cross_entropy_with_integer_labels(shift_logits, shift_labels).mean()
        return ce_loss + (1e-3 * ponder_steps.mean()), ce_loss

    @partial(jax.pmap, axis_name='batch')
    def train_step(state, batch):
        grad_fn = jax.value_and_grad(loss_fn, has_aux=True)
        (total_loss, ce_loss), grads = grad_fn(state.params, batch)
        grads = jax.lax.pmean(grads, axis_name='batch')
        total_loss = jax.lax.pmean(total_loss, axis_name='batch')
        ce_loss = jax.lax.pmean(ce_loss, axis_name='batch')
        state = state.apply_gradients(grads=grads)
        return state, total_loss, ce_loss

    ckpt_dir = '/kaggle/working/200M_Model_Checkpoints'
    ocp_options = ocp.CheckpointManagerOptions(max_to_keep=2, create=True)
    checkpoint_manager = ocp.CheckpointManager(ckpt_dir, options=ocp_options)

    print(f"\nπŸ”₯ PHASE 1: Pre-Training on 7 Billion Tokens ({switch_step} Steps)...")
    
    step = 0 # Step variable bahar declare kiya taaki exception block me use ho sake
    
    # 2️⃣ FAILSAFE TRY-EXCEPT BLOCK
    try:
        for step in range(1, total_steps + 1):
            
            if step == switch_step:
                print("\n==============================================")
                print("πŸš€ PHASE 2 INITIATED: 1 Billion Tokens Chat & Math Alignment!")
                print("==============================================\n")
                
            if step < switch_step:
                batch = next(fineweb_loader)
            else:
                batch = next(chat_loader) if step % 2 == 0 else next(math_loader)
                
            batch = batch.reshape(num_devices, per_device_batch, config.context_length)
                
            state, total_loss, ce_loss = train_step(state, batch)
            
            if step % 100 == 0:
                loss_v = float(total_loss[0].block_until_ready())
                ppl_v = np.exp(min(float(ce_loss[0]), 100)) 
                mode = "PRETRAIN" if step < switch_step else ("CHAT-TUNE" if step % 2 == 0 else "MATH-TUNE")
                print(f"[{mode}] Step {step}/{total_steps} | Loss: {loss_v:.4f} | PPL: {ppl_v:.2f}")
                
            if step % 3000 == 0 or step == total_steps:
                cpu_state = jax.device_get(jax.tree_util.tree_map(lambda x: x[0], state))
                checkpoint_manager.save(step, args=ocp.args.StandardSave(cpu_state))
                print(f"πŸ’Ύ Checkpoint Saved at Step {step}.")

    except (KeyboardInterrupt, Exception) as e:
        # 🚨 AGAR KUCH GADBAD HUI YA KISI NE ROKA TOH YAHAN AAYEGA
        print(f"\n⚠️ TRAINING RUK GAYI! Error: {e}")
        # Agar manual stop nahi hai toh error ki details print karega
        if not isinstance(e, KeyboardInterrupt):
            traceback.print_exc()
            
        print(f"\nπŸ›‘ Ghabrayein nahi bro, Step {step} par Emergency Checkpoint save ho raha hai...")
        try:
            cpu_state = jax.device_get(jax.tree_util.tree_map(lambda x: x[0], state))
            # Step ko save karenge taaki pichla checkpoint overwrite na ho, usme +1 kar diya taaki conflict na ho
            save_step = step if step % 3000 != 0 else step + 1 
            checkpoint_manager.save(save_step, args=ocp.args.StandardSave(cpu_state))
            print("βœ… Emergency Checkpoint safely saved!")
        except Exception as save_err:
            print(f"❌ Emergency save fail ho gaya: {save_err}")

    finally:
        # πŸ“¦ YE WALA BLOCK HAMESHA CHALEGA (Chaahe error aaye ya puri training ho)
        print("\nπŸ“¦ Hugging Face par push karne ki koshish kar raha hoon...")
        try:
            api = HfApi()
            repo_id = "Nebulixlabs/Dynamic-200M-Math"
            
            print(f"Creating private repository: {repo_id}")
            api.create_repo(repo_id=repo_id, private=True, exist_ok=True)
            
            print("Uploading checkpoint folder... This might take a few minutes.")
            api.upload_folder(
                folder_path=ckpt_dir,
                repo_id=repo_id,
                repo_type="model"
            )
            print(f"βœ… Model successfully uploaded to https://huggingface.co/{repo_id}")
        except Exception as e:
            print(f"❌ Upload failed: {e}")
            print("Model is saved locally in Kaggle. Zipping...")
            shutil.make_archive('/kaggle/working/200M_Ready', 'zip', ckpt_dir)
            print("βœ… Zip file ready to download manually!")

if __name__ == "__main__":
    main()