Robotics
multilingual
ternary
multimodal
pretraining
jirack
ternarytransformer
kgrabko commited on
Commit
7535858
·
verified ·
1 Parent(s): a674ebd

Initial upload of JiRackNative 3B pre-train weights first checkpoint

Browse files
JiRackTernaryPyTorch_3b.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from torch.utils.checkpoint import checkpoint
5
+
6
+ # --- JIRACK 3B CONSTANTS ---
7
+ VOCAB_SIZE = 128256
8
+ HIDDEN_SIZE = 3072
9
+ NUM_LAYERS = 20
10
+ NUM_HEADS = 24
11
+ NUM_KV_HEADS = 8
12
+ #INTERMEDIATE_SIZE = 8192
13
+ INTERMEDIATE_SIZE = 4096
14
+ MAX_SEQ_LEN = 4096
15
+ RMS_EPS = 1e-6
16
+ STABILITY_EPS = 1e-9
17
+ INT8_SCALE_TARGET = 127.0
18
+ TERNARY = False
19
+
20
+ class TernaryConfig:
21
+ def __init__(self):
22
+ self.vocab_size = VOCAB_SIZE
23
+ self.hidden_size = HIDDEN_SIZE
24
+ self.num_hidden_layers = NUM_LAYERS
25
+ self.num_attention_heads = NUM_HEADS
26
+ self.num_key_value_heads = NUM_KV_HEADS
27
+ self.intermediate_size = INTERMEDIATE_SIZE
28
+ self.max_position_embeddings = MAX_SEQ_LEN
29
+ self.rms_norm_eps = RMS_EPS
30
+ self.tie_word_embeddings = False
31
+ self.model_type = "jirack_ternary"
32
+ self.ternary = TERNARY # Флаг теперь внутри конфига
33
+
34
+ def get(self, key, default=None):
35
+ return getattr(self, key, default)
36
+
37
+ def __getitem__(self, key):
38
+ return getattr(self, key)
39
+
40
+ class BitLinear(nn.Linear):
41
+ def __init__(self, in_features, out_features, bias=False, ternary=False):
42
+ super().__init__(in_features, out_features, bias)
43
+ self.ternary = ternary
44
+
45
+ def forward(self, x):
46
+ if not self.ternary:
47
+ return F.linear(x, self.weight, self.bias)
48
+ # Weight Quantization
49
+ w = self.weight
50
+ gamma = w.abs().mean().clamp(min=STABILITY_EPS)
51
+ w_quant = torch.clamp(torch.round(w / gamma), -1, 1)
52
+ w_final = w + (w_quant * gamma - w).detach()
53
+
54
+ # Activation Quantization (Absmax)
55
+ x_norm = x - x.mean(dim=-1, keepdim=True)
56
+ x_max = x_norm.abs().max(dim=-1, keepdim=True).values.clamp(min=STABILITY_EPS)
57
+ scale = INT8_SCALE_TARGET / x_max
58
+ x_quant = (x_norm * scale).round().clamp(-128, 127) / scale
59
+ x_final = x + (x_quant - x).detach()
60
+
61
+ return F.linear(x_final, w_final, self.bias)
62
+
63
+ class RMSNorm(nn.Module):
64
+ def __init__(self, dim, eps=RMS_EPS):
65
+ super().__init__()
66
+ self.eps = eps
67
+ self.weight = nn.Parameter(torch.ones(dim))
68
+ def forward(self, x):
69
+ # Убран жесткий .pow(2) в float32, чтобы не ломать скорость
70
+ return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) * self.weight
71
+
72
+ def precompute_freqs_cis(dim, seq_len, theta=500000.0):
73
+ freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
74
+ t = torch.arange(seq_len).float()
75
+ freqs = torch.outer(t, freqs)
76
+ return torch.cos(freqs), torch.sin(freqs)
77
+
78
+ def apply_rotary_emb(xq, xk, freqs_cos, freqs_sin):
79
+ def rotate_half(x):
80
+ x1, x2 = x[..., : x.shape[-1] // 2], x[..., x.shape[-1] // 2 :]
81
+ return torch.cat((-x2, x1), dim=-1)
82
+ T = xq.shape[2]
83
+ # Убрали принудительный .to(torch.float32)
84
+ f_cos = freqs_cos[:T].to(device=xq.device, dtype=xq.dtype).view(1, 1, T, -1).repeat(1, 1, 1, 2)
85
+ f_sin = freqs_sin[:T].to(device=xq.device, dtype=xq.dtype).view(1, 1, T, -1).repeat(1, 1, 1, 2)
86
+ return (xq * f_cos) + (rotate_half(xq) * f_sin), (xk * f_cos) + (rotate_half(xk) * f_sin)
87
+
88
+ class TransformerBlock(nn.Module):
89
+ def __init__(self, config):
90
+ super().__init__()
91
+ self.n_heads = config.num_attention_heads
92
+ self.n_kv_heads = config.num_key_value_heads
93
+ self.n_rep = self.n_heads // self.n_kv_heads
94
+ self.head_dim = config.hidden_size // self.n_heads
95
+ # Передаем параметр ternary из конфигурации
96
+ self.q_proj = BitLinear(config.hidden_size, config.hidden_size, ternary=config.ternary)
97
+ self.k_proj = BitLinear(config.hidden_size, self.n_kv_heads * self.head_dim, ternary=config.ternary)
98
+ self.v_proj = BitLinear(config.hidden_size, self.n_kv_heads * self.head_dim, ternary=config.ternary)
99
+ self.out_proj = BitLinear(config.hidden_size, config.hidden_size, ternary=config.ternary)
100
+
101
+ self.ffn_w1 = BitLinear(config.hidden_size, config.intermediate_size, ternary=config.ternary)
102
+ self.ffn_w3 = BitLinear(config.hidden_size, config.intermediate_size, ternary=config.ternary)
103
+ self.ffn_w2 = BitLinear(config.intermediate_size, config.hidden_size, ternary=config.ternary)
104
+
105
+ self.norm1, self.norm2 = RMSNorm(config.hidden_size), RMSNorm(config.hidden_size)
106
+
107
+ def forward(self, x, freqs_cos, freqs_sin):
108
+ h = self.norm1(x)
109
+ B, T, D = x.shape
110
+
111
+ q = self.q_proj(h).view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
112
+ k = self.k_proj(h).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2)
113
+ v = self.v_proj(h).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2)
114
+
115
+ q, k = apply_rotary_emb(q, k, freqs_cos, freqs_sin)
116
+
117
+ if self.n_rep > 1:
118
+ k = k[:, :, None, :, :].expand(B, self.n_kv_heads, self.n_rep, T, self.head_dim).reshape(B, self.n_heads, T, self.head_dim)
119
+ v = v[:, :, None, :, :].expand(B, self.n_kv_heads, self.n_rep, T, self.head_dim).reshape(B, self.n_heads, T, self.head_dim)
120
+
121
+ # Полностью автоматический выбор кернела силами PyTorch
122
+ attn_out = F.scaled_dot_product_attention(q, k, v, is_causal=True)
123
+
124
+ x = x + self.out_proj(attn_out.transpose(1, 2).reshape(B, T, D))
125
+ m = self.norm2(x)
126
+ x = x + self.ffn_w2(F.silu(self.ffn_w1(m)) * self.ffn_w3(m))
127
+ return x
128
+
129
+ class TernaryTransformer3B(nn.Module):
130
+ def __init__(self, config):
131
+ super().__init__()
132
+ self.config = config
133
+ self.token_emb = nn.Embedding(config.vocab_size, config.hidden_size)
134
+ self.blocks = nn.ModuleList([TransformerBlock(config) for _ in range(config.num_hidden_layers)])
135
+ self.ln_f = RMSNorm(config.hidden_size)
136
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
137
+
138
+ self.head_dim = config.hidden_size // config.num_attention_heads
139
+ self.gradient_checkpointing = False
140
+ self._set_rope_cache(config.max_position_embeddings)
141
+ print(f"Ternary={config.ternary} | Native Auto-SDPA Activated")
142
+
143
+ def gradient_checkpointing_enable(self, **kwargs):
144
+ self.gradient_checkpointing = True
145
+
146
+ def _set_rope_cache(self, seq_len):
147
+ cos, sin = precompute_freqs_cis(self.head_dim, seq_len)
148
+ self.register_buffer("freqs_cos", cos, persistent=False)
149
+ self.register_buffer("freqs_sin", sin, persistent=False)
150
+
151
+ def forward(self, input_ids):
152
+ input_ids = input_ids.to(torch.long)
153
+ T = input_ids.shape[1]
154
+ if T > self.freqs_cos.shape[0]:
155
+ self._set_rope_cache(T)
156
+
157
+ x = self.token_emb(input_ids)
158
+
159
+ for block in self.blocks:
160
+ if self.gradient_checkpointing and self.training:
161
+ x = checkpoint(block, x, self.freqs_cos, self.freqs_sin, use_reentrant=False)
162
+ else:
163
+ x = block(x, self.freqs_cos, self.freqs_sin)
164
+
165
+ logits = self.lm_head(self.ln_f(x))
166
+ return logits, None
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|endoftext|>",
4
+ "clean_up_tokenization_spaces": true,
5
+ "eos_token": "<|endoftext|>",
6
+ "model_max_length": 1000000000000000019884624838656,
7
+ "pad_token": "<|padding|>",
8
+ "tokenizer_class": "TokenizersBackend",
9
+ "unk_token": "<|unk|>"
10
+ }
train_jirack_accelerate.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ # Включаем оптимизацию памяти для ROCm/HIP ДО импорта torch!
3
+ os.environ["PYTORCH_HIP_ALLOC_CONF"] = "expandable_segments:True"
4
+
5
+ import glob
6
+ import math
7
+ import torch
8
+ import torch.nn as nn
9
+ from torch.utils.data import Dataset, DataLoader
10
+ from accelerate import Accelerator
11
+ from tqdm import tqdm
12
+ from transformers import Adafactor, get_cosine_schedule_with_warmup
13
+
14
+ # --- ГЛОБАЛЬНЫЕ КОНСТАНТЫ ---
15
+ USE_COSINE_SCHEDULER = True # Переключите в False, если нужно отключить планировщик (warmup + cosine)
16
+
17
+ # --- 1. Легковесный датасет ---
18
+ class SingleShardDataset(Dataset):
19
+ def __init__(self, shard_path):
20
+ self.data = torch.load(shard_path, map_location="cpu", weights_only=True)
21
+ def __len__(self):
22
+ return self.data.shape[0]
23
+ def __getitem__(self, idx):
24
+ return self.data[idx].long()
25
+
26
+ # --- 2. Основная функция тренировки ---
27
+ def train():
28
+ grad_accumulation_steps = 1
29
+ batch_size = 1
30
+
31
+ # Инициализируем Accelerator
32
+ accelerator = Accelerator(
33
+ mixed_precision="bf16",
34
+ gradient_accumulation_steps=grad_accumulation_steps
35
+ )
36
+
37
+ pt_chunks_mask = "/mnt/nfs_clientshare/JiRackPretrain/jirack_pretrain_chunk_*.pt"
38
+ checkpoint_dir = "checkpoints"
39
+ pt_files = sorted(glob.glob(pt_chunks_mask))
40
+
41
+ if not pt_files:
42
+ raise FileNotFoundError(f"Не найдены файлы чанков по маске: {pt_chunks_mask}")
43
+
44
+ if accelerator.is_local_main_process:
45
+ print(f"Найдено шардов: {len(pt_files)}")
46
+ print("Инициализация JiRack 3.3B...")
47
+
48
+ # Импортируем строго ваши классы из локального файла
49
+ from JiRackTernaryPyTorch_3b import TernaryTransformer3B, TernaryConfig
50
+
51
+ config = TernaryConfig()
52
+ model = TernaryTransformer3B(config)
53
+
54
+ # === ТОЧЕЧНАЯ ЗАГРУЗКА ЧЕКПОИНТА ===
55
+ checkpoint_load_path = "model_weights.pt"
56
+ if os.path.exists(checkpoint_load_path):
57
+ if accelerator.is_local_main_process:
58
+ print(f"-> Загрузка сохраненных весов из: {checkpoint_load_path}")
59
+ state_dict = torch.load(checkpoint_load_path, map_location="cpu", weights_only=True)
60
+ model.load_state_dict(state_dict)
61
+ else:
62
+ if accelerator.is_local_main_process:
63
+ print(f"-> Чекпоинт не найден по пути {checkpoint_load_path}, обучение начнется с нуля.")
64
+ # ==================================
65
+
66
+ model.gradient_checkpointing_enable()
67
+
68
+ if accelerator.is_local_main_process:
69
+ print("-> Gradient Checkpointing активирован.")
70
+
71
+ criterion = nn.CrossEntropyLoss()
72
+
73
+ # Сначала переносим модель на ROCm/HIP устройство через accelerator
74
+ model = accelerator.prepare(model)
75
+
76
+ # === НАСТРОЙКА ADAFACTOR ДЛЯ GPU ===
77
+ optimizer = Adafactor(
78
+ model.parameters(),
79
+ lr=2e-4, # Пиковый LR
80
+ weight_decay=0.01,
81
+ relative_step=False,
82
+ scale_parameter=False,
83
+ warmup_init=False
84
+ )
85
+
86
+ # === РАСЧЕТ И ИНИЦИАЛИЗАЦИЯ ПЛАНИРОВЩИКА С WARMUP ===
87
+ scheduler = None
88
+ if USE_COSINE_SCHEDULER:
89
+ # Считаем общее количество реальных шагов обновления весов (optimizer steps)
90
+ # 2000 строк в шарде / batch_size 1 / grad_accumulation_steps 4 = 500 шагов на шард.
91
+ steps_per_shard = math.ceil(2000 / (batch_size * grad_accumulation_steps))
92
+ total_steps = len(pt_files) * steps_per_shard
93
+
94
+ # Задаем warmup (например, 5% от общего числа шагов обучения)
95
+ num_warmup_steps = int(0.05 * total_steps)
96
+
97
+ # Комбинированный планировщик: плавно поднимает LR до 2e-4, затем опускает по косинусу до 0
98
+ scheduler = get_cosine_schedule_with_warmup(
99
+ optimizer=optimizer,
100
+ num_warmup_steps=num_warmup_steps,
101
+ num_training_steps=total_steps
102
+ )
103
+
104
+ if accelerator.is_local_main_process:
105
+ print(f"-> Планировщик АКТИВИРОВАН.")
106
+ print(f" Всего шагов обучения: {total_steps}")
107
+ print(f" Шагов разогрева (warmup): {num_warmup_steps}")
108
+
109
+ # Подготавливаем оптимизатор и планировщик через accelerator
110
+ if scheduler is not None:
111
+ optimizer, scheduler = accelerator.prepare(optimizer, scheduler)
112
+ else:
113
+ optimizer = accelerator.prepare(optimizer)
114
+
115
+ model.train()
116
+ shard_counter = 0
117
+
118
+ if accelerator.is_local_main_process:
119
+ print("Запуск обучения...")
120
+
121
+ for shard_path in pt_files:
122
+ shard_name = os.path.basename(shard_path)
123
+ if accelerator.is_local_main_process:
124
+ print(f"\n[Шард {shard_counter + 1}/{len(pt_files)}] {shard_name}")
125
+
126
+ shard_dataset = SingleShardDataset(shard_path)
127
+
128
+ train_loader = DataLoader(
129
+ shard_dataset,
130
+ batch_size=batch_size,
131
+ shuffle=True,
132
+ num_workers=2,
133
+ pin_memory=True
134
+ )
135
+
136
+ train_loader = accelerator.prepare(train_loader)
137
+
138
+ progress_bar = tqdm(
139
+ train_loader,
140
+ desc=f"Обработка {shard_name}",
141
+ disable=not accelerator.is_local_main_process
142
+ )
143
+
144
+ epoch_loss = 0.0
145
+ for step, batch in enumerate(progress_bar):
146
+ input_ids = batch
147
+ inputs = input_ids[:, :-1]
148
+ targets = input_ids[:, 1:]
149
+
150
+ with accelerator.accumulate(model):
151
+ logits, _ = model(inputs)
152
+ loss = criterion(logits.reshape(-1, logits.size(-1)), targets.reshape(-1))
153
+
154
+ accelerator.backward(loss)
155
+
156
+ optimizer.step()
157
+
158
+ # Делаем шаг планировщика только при реальном обновлении градиентов
159
+ if scheduler is not None and accelerator.sync_gradients:
160
+ if not getattr(accelerator, "optimizer_step_was_skipped", False):
161
+ scheduler.step()
162
+
163
+ optimizer.zero_grad()
164
+
165
+ epoch_loss += loss.item()
166
+ avg_loss = epoch_loss / (step + 1)
167
+ ppl = math.exp(avg_loss) if avg_loss < 20 else float('inf')
168
+
169
+ if accelerator.is_local_main_process:
170
+ # Извлекаем текущий LR для вывода на панель tqdm
171
+ current_lr = scheduler.get_last_lr()[0] if scheduler is not None else optimizer.param_groups[0]['lr']
172
+ progress_bar.set_postfix({
173
+ "loss": f"{loss.item():.4f}",
174
+ "avg_loss": f"{avg_loss:.4f}",
175
+ "ppl": f"{ppl:.1f}",
176
+ "lr": f"{current_lr:.2e}"
177
+ })
178
+
179
+ shard_counter += 1
180
+
181
+ # Сохранение после каждого шарда
182
+ if accelerator.is_local_main_process:
183
+ current_checkpoint_path = os.path.join(checkpoint_dir, f"jirack_shard_{shard_counter}")
184
+ os.makedirs(current_checkpoint_path, exist_ok=True)
185
+ unwrapped_model = accelerator.unwrap_model(model)
186
+ torch.save(unwrapped_model.state_dict(), os.path.join(current_checkpoint_path, "model_weights.pt"))
187
+ print(f"✅ Сохранено после шарда {shard_counter}")
188
+
189
+ # Финальное сохранение
190
+ accelerator.wait_for_everyone()
191
+ if accelerator.is_local_main_process:
192
+ final_dir = os.path.join(checkpoint_dir, "jirack_final_3b")
193
+ os.makedirs(final_dir, exist_ok=True)
194
+ unwrapped_model = accelerator.unwrap_model(model)
195
+ torch.save(unwrapped_model.state_dict(), os.path.join(final_dir, "model_final_weights.pt"))
196
+ print("Финальное сохранение завершено.")
197
+
198
+ if __name__ == "__main__":
199
+ train()