sapbot

Qwen 2 trainer

Feb 13th, 2026
59
0
Never
9
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.33 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. """
  3. Qwen2 5M Parameter LLM - Training from Scratch
  4. """
  5.  
  6. import os
  7. import math
  8. import json
  9. import torch
  10. import torch.nn as nn
  11. import torch.nn.functional as F
  12. from torch.utils.data import Dataset, DataLoader
  13. from pathlib import Path
  14. from typing import Optional, List
  15. from dataclasses import dataclass
  16. from transformers import PreTrainedTokenizerFast
  17. from tokenizers import Tokenizer, models, trainers, pre_tokenizers, processors, decoders
  18. import logging
  19. import shutil
  20.  
  21. logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
  22. logger = logging.getLogger(__name__)
  23.  
  24.  
  25. @dataclass
  26. class ModelConfig:
  27.     vocab_size: int = 8000
  28.     hidden_size: int = 256
  29.     intermediate_size: int = 684
  30.     num_hidden_layers: int = 8
  31.     num_attention_heads: int = 8
  32.     num_key_value_heads: int = 2
  33.     max_position_embeddings: int = 2048
  34.     rope_theta: float = 10000.0
  35.     rms_norm_eps: float = 1e-6
  36.     tie_word_embeddings: bool = True
  37.  
  38.  
  39. class RMSNorm(nn.Module):
  40.     def __init__(self, dim: int, eps: float = 1e-6):
  41.         super().__init__()
  42.         self.eps = eps
  43.         self.weight = nn.Parameter(torch.ones(dim))
  44.    
  45.     def forward(self, x: torch.Tensor) -> torch.Tensor:
  46.         variance = x.pow(2).mean(-1, keepdim=True)
  47.         x = x * torch.rsqrt(variance + self.eps)
  48.         return self.weight * x
  49.  
  50.  
  51. class RotaryEmbedding(nn.Module):
  52.     def __init__(self, dim: int, max_seq_len: int = 2048, theta: float = 10000.0):
  53.         super().__init__()
  54.         inv_freq = 1.0 / (theta ** (torch.arange(0, dim, 2).float() / dim))
  55.         self.register_buffer("inv_freq", inv_freq)
  56.         freqs = torch.outer(torch.arange(max_seq_len), inv_freq)
  57.         emb = torch.cat([freqs, freqs], dim=-1)
  58.         self.register_buffer("cos_cached", emb.cos()[None, None, :, :])
  59.         self.register_buffer("sin_cached", emb.sin()[None, None, :, :])
  60.    
  61.     def forward(self, x: torch.Tensor, seq_len: int):
  62.         return self.cos_cached[:, :, :seq_len, :], self.sin_cached[:, :, :seq_len, :]
  63.  
  64.  
  65. def rotate_half(x):
  66.     x1, x2 = x.chunk(2, dim=-1)
  67.     return torch.cat([-x2, x1], dim=-1)
  68.  
  69.  
  70. def apply_rotary_pos_emb(q, k, cos, sin):
  71.     return (q * cos) + (rotate_half(q) * sin), (k * cos) + (rotate_half(k) * sin)
  72.  
  73.  
  74. class Qwen2Attention(nn.Module):
  75.     def __init__(self, config: ModelConfig, layer_idx: int):
  76.         super().__init__()
  77.         self.hidden_size = config.hidden_size
  78.         self.num_heads = config.num_attention_heads
  79.         self.num_key_value_heads = config.num_key_value_heads
  80.         self.head_dim = config.hidden_size // config.num_attention_heads
  81.         self.num_key_value_groups = self.num_heads // self.num_key_value_heads
  82.        
  83.         self.q_proj = nn.Linear(config.hidden_size, self.num_heads * self.head_dim, bias=True)
  84.         self.k_proj = nn.Linear(config.hidden_size, self.num_key_value_heads * self.head_dim, bias=True)
  85.         self.v_proj = nn.Linear(config.hidden_size, self.num_key_value_heads * self.head_dim, bias=True)
  86.         self.o_proj = nn.Linear(self.num_heads * self.head_dim, config.hidden_size, bias=False)
  87.         self.rotary_emb = RotaryEmbedding(self.head_dim, config.max_position_embeddings, config.rope_theta)
  88.    
  89.     def forward(self, hidden_states, attention_mask=None):
  90.         bsz, q_len, _ = hidden_states.size()
  91.         query = self.q_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
  92.         key = self.k_proj(hidden_states).view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
  93.         value = self.v_proj(hidden_states).view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
  94.        
  95.         cos, sin = self.rotary_emb(value, q_len)
  96.         query, key = apply_rotary_pos_emb(query, key, cos, sin)
  97.        
  98.         key = key.repeat_interleave(self.num_key_value_groups, dim=1)
  99.         value = value.repeat_interleave(self.num_key_value_groups, dim=1)
  100.        
  101.         scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(self.head_dim)
  102.         if attention_mask is not None:
  103.             scores = scores + attention_mask
  104.         attn = F.softmax(scores, dim=-1, dtype=torch.float32).to(query.dtype)
  105.         out = torch.matmul(attn, value).transpose(1, 2).contiguous().view(bsz, q_len, self.hidden_size)
  106.         return self.o_proj(out)
  107.  
  108.  
  109. class Qwen2MLP(nn.Module):
  110.     def __init__(self, config: ModelConfig):
  111.         super().__init__()
  112.         self.gate_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
  113.         self.up_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
  114.         self.down_proj = nn.Linear(config.intermediate_size, config.hidden_size, bias=False)
  115.    
  116.     def forward(self, x):
  117.         return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
  118.  
  119.  
  120. class Qwen2DecoderLayer(nn.Module):
  121.     def __init__(self, config: ModelConfig, layer_idx: int):
  122.         super().__init__()
  123.         self.self_attn = Qwen2Attention(config, layer_idx)
  124.         self.mlp = Qwen2MLP(config)
  125.         self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
  126.         self.post_attention_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
  127.    
  128.     def forward(self, x, attention_mask=None):
  129.         x = x + self.self_attn(self.input_layernorm(x), attention_mask)
  130.         x = x + self.mlp(self.post_attention_layernorm(x))
  131.         return x
  132.  
  133.  
  134. class Qwen2Model(nn.Module):
  135.     def __init__(self, config: ModelConfig):
  136.         super().__init__()
  137.         self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size)
  138.         self.layers = nn.ModuleList([Qwen2DecoderLayer(config, i) for i in range(config.num_hidden_layers)])
  139.         self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
  140.    
  141.     def forward(self, input_ids, attention_mask=None):
  142.         x = self.embed_tokens(input_ids)
  143.         if attention_mask is None:
  144.             seq_len = input_ids.size(1)
  145.             attention_mask = torch.triu(torch.full((seq_len, seq_len), float('-inf'), device=input_ids.device), diagonal=1)[None, None, :, :]
  146.         for layer in self.layers:
  147.             x = layer(x, attention_mask)
  148.         return self.norm(x)
  149.  
  150.  
  151. class Qwen2ForCausalLM(nn.Module):
  152.     def __init__(self, config: ModelConfig):
  153.         super().__init__()
  154.         self.config = config
  155.         self.model = Qwen2Model(config)
  156.         self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
  157.         if config.tie_word_embeddings:
  158.             self.lm_head.weight = self.model.embed_tokens.weight
  159.         self.apply(self._init_weights)
  160.    
  161.     def _init_weights(self, module):
  162.         if isinstance(module, nn.Linear):
  163.             torch.nn.init.normal_(module.weight, std=0.02)
  164.             if module.bias is not None:
  165.                 torch.nn.init.zeros_(module.bias)
  166.         elif isinstance(module, nn.Embedding):
  167.             torch.nn.init.normal_(module.weight, std=0.02)
  168.    
  169.     def forward(self, input_ids, attention_mask=None, labels=None):
  170.         hidden = self.model(input_ids, attention_mask)
  171.         logits = self.lm_head(hidden)
  172.         loss = None
  173.         if labels is not None:
  174.             shift_logits = logits[..., :-1, :].contiguous()
  175.             shift_labels = labels[..., 1:].contiguous()
  176.             loss = F.cross_entropy(shift_logits.view(-1, self.config.vocab_size), shift_labels.view(-1))
  177.         return logits, loss
  178.    
  179.     def count_parameters(self):
  180.         return sum(p.numel() for p in self.parameters())
  181.    
  182.     @torch.no_grad()
  183.     def generate(self, input_ids, max_new_tokens=50, temperature=1.0, top_p=0.9, eos_token_id=None):
  184.         self.eval()
  185.         for _ in range(max_new_tokens):
  186.             logits, _ = self.forward(input_ids)
  187.             logits = logits[:, -1, :] / temperature
  188.             probs = F.softmax(logits, dim=-1)
  189.             sorted_probs, sorted_indices = torch.sort(probs, descending=True)
  190.             cumsum = torch.cumsum(sorted_probs, dim=-1)
  191.             sorted_indices_to_remove = cumsum > top_p
  192.             sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
  193.             sorted_indices_to_remove[..., 0] = False
  194.             indices_to_remove = sorted_indices_to_remove.scatter(1, sorted_indices, sorted_indices_to_remove)
  195.             logits[indices_to_remove] = float('-inf')
  196.             probs = F.softmax(logits, dim=-1)
  197.             next_token = torch.multinomial(probs, num_samples=1)
  198.             input_ids = torch.cat([input_ids, next_token], dim=-1)
  199.             if eos_token_id is not None and next_token.item() == eos_token_id:
  200.                 break
  201.         return input_ids
  202.  
  203.  
  204. class TextDataset(Dataset):
  205.     def __init__(self, data_dir: str, tokenizer, max_length: int = 512):
  206.         self.tokenizer = tokenizer
  207.         self.max_length = max_length
  208.         self.data_dir = Path(data_dir)
  209.        
  210.         self.files = []
  211.         logger.info(f"Scanning {self.data_dir.absolute()}...")
  212.        
  213.         if not self.data_dir.exists():
  214.             raise FileNotFoundError(f"Directory not found: {self.data_dir.absolute()}")
  215.        
  216.         all_paths = list(self.data_dir.rglob("*"))
  217.         logger.info(f"Found {len(all_paths)} total paths")
  218.        
  219.         for path in all_paths:
  220.             if path.is_file():
  221.                 try:
  222.                     with open(path, 'r', encoding='utf-8', errors='ignore') as f:
  223.                         content = f.read()
  224.                         if len(content.strip()) > 0:
  225.                             self.files.append((path, content))
  226.                 except:
  227.                     pass
  228.        
  229.         logger.info(f"Successfully read {len(self.files)} text files")
  230.        
  231.         self.samples = []
  232.         for path, content in self.files:
  233.             tokens = tokenizer.encode(content)
  234.             if len(tokens) == 0:
  235.                 continue
  236.            
  237.             start = 0
  238.             while start < len(tokens):
  239.                 end = min(start + max_length, len(tokens))
  240.                 chunk = tokens[start:end]
  241.                 if len(chunk) > 1:
  242.                     self.samples.append(chunk)
  243.                 if end >= len(tokens):
  244.                     break
  245.                 start += max_length // 2
  246.        
  247.         logger.info(f"Created {len(self.samples)} training samples")
  248.        
  249.         if len(self.samples) == 0:
  250.             logger.warning("No data found! Creating dummy sample.")
  251.             self.samples = [[tokenizer.eos_token_id] * 10]
  252.    
  253.     def __len__(self):
  254.         return len(self.samples)
  255.    
  256.     def __getitem__(self, idx):
  257.         tokens = self.samples[idx]
  258.        
  259.         if len(tokens) >= self.max_length:
  260.             input_ids = tokens[:self.max_length]
  261.         else:
  262.             input_ids = tokens + [self.tokenizer.pad_token_id] * (self.max_length - len(tokens))
  263.        
  264.         input_ids = torch.tensor(input_ids, dtype=torch.long)
  265.         labels = input_ids.clone()
  266.         labels[input_ids == self.tokenizer.pad_token_id] = -100
  267.        
  268.         return {'input_ids': input_ids, 'labels': labels}
  269.  
  270.  
  271. def train_tokenizer(data_dir: str, vocab_size: int = 8000, save_path: str = "./tokenizer"):
  272.     logger.info("Training tokenizer...")
  273.    
  274.     data_path = Path(data_dir)
  275.     if not data_path.exists():
  276.         raise FileNotFoundError(f"Data directory not found: {data_path.absolute()}")
  277.    
  278.     texts = []
  279.     for path in data_path.rglob("*"):
  280.         if path.is_file():
  281.             try:
  282.                 with open(path, 'r', encoding='utf-8', errors='ignore') as f:
  283.                     text = f.read()
  284.                     if len(text.strip()) > 0:
  285.                         texts.append(text)
  286.             except:
  287.                 pass
  288.    
  289.     if len(texts) == 0:
  290.         raise ValueError(f"No text files found in {data_dir}")
  291.    
  292.     logger.info(f"Training on {len(texts)} files")
  293.    
  294.     temp_file = "/tmp/train_text.txt"
  295.     with open(temp_file, 'w', encoding='utf-8') as f:
  296.         f.write("\n".join(texts))
  297.    
  298.     # Train tokenizer with proper post-processing
  299.     tokenizer = Tokenizer(models.BPE())
  300.     tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
  301.    
  302.     trainer = trainers.BpeTrainer(
  303.         vocab_size=vocab_size,
  304.         special_tokens=["<|endoftext|>", "<pad>"],
  305.         show_progress=True
  306.     )
  307.     tokenizer.train([temp_file], trainer)
  308.    
  309.     # Set up proper decoder - use decoders.ByteLevel, not processors.ByteLevel
  310.     tokenizer.decoder = decoders.ByteLevel()
  311.    
  312.     # Add post-processor to handle special tokens properly
  313.     tokenizer.post_processor = processors.TemplateProcessing(
  314.         single="$A",
  315.         special_tokens=[
  316.             ("<|endoftext|>", tokenizer.token_to_id("<|endoftext|>")),
  317.         ],
  318.     )
  319.    
  320.     wrapped = PreTrainedTokenizerFast(
  321.         tokenizer_object=tokenizer,
  322.         eos_token="<|endoftext|>",
  323.         pad_token="<pad>",
  324.         unk_token="<|endoftext|>",
  325.         clean_up_tokenization_spaces=True,
  326.     )
  327.    
  328.     os.makedirs(save_path, exist_ok=True)
  329.     wrapped.save_pretrained(save_path)
  330.     return wrapped
  331.  
  332.  
  333. def save_hf_format(model, tokenizer, output_dir: str):
  334.     """Save model and tokenizer in HF-compatible format"""
  335.     os.makedirs(output_dir, exist_ok=True)
  336.    
  337.     torch.save(model.state_dict(), os.path.join(output_dir, "pytorch_model.bin"))
  338.    
  339.     config = {
  340.         "architectures": ["Qwen2ForCausalLM"],
  341.         "model_type": "qwen2",
  342.         "vocab_size": model.config.vocab_size,
  343.         "hidden_size": model.config.hidden_size,
  344.         "intermediate_size": model.config.intermediate_size,
  345.         "num_hidden_layers": model.config.num_hidden_layers,
  346.         "num_attention_heads": model.config.num_attention_heads,
  347.         "num_key_value_heads": model.config.num_key_value_heads,
  348.         "max_position_embeddings": model.config.max_position_embeddings,
  349.         "rope_theta": model.config.rope_theta,
  350.         "rms_norm_eps": model.config.rms_norm_eps,
  351.         "tie_word_embeddings": model.config.tie_word_embeddings,
  352.         "torch_dtype": "float32",
  353.         "transformers_version": "4.35.0",
  354.         "use_cache": False,
  355.     }
  356.    
  357.     with open(os.path.join(output_dir, "config.json"), "w") as f:
  358.         json.dump(config, f, indent=2)
  359.    
  360.     tokenizer.save_pretrained(output_dir)
  361.    
  362.     logger.info(f"Saved to {output_dir}")
  363.  
  364.  
  365. def train():
  366.     config = ModelConfig()
  367.     data_dir = "./data"
  368.     output_dir = "./output"
  369.    
  370.     device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  371.     logger.info(f"Using device: {device}")
  372.    
  373.     tokenizer_path = "./tokenizer"
  374.     if os.path.exists(tokenizer_path):
  375.         tokenizer = PreTrainedTokenizerFast.from_pretrained(tokenizer_path)
  376.     else:
  377.         tokenizer = train_tokenizer(data_dir, vocab_size=config.vocab_size, save_path=tokenizer_path)
  378.    
  379.     config.vocab_size = len(tokenizer)
  380.     logger.info(f"Vocab size: {config.vocab_size}")
  381.    
  382.     model = Qwen2ForCausalLM(config).to(device)
  383.     logger.info(f"Parameters: {model.count_parameters():,} (~{model.count_parameters()/1e6:.1f}M)")
  384.    
  385.     dataset = TextDataset(data_dir, tokenizer, max_length=512)
  386.    
  387.     dataset_len = len(dataset)
  388.     if dataset_len == 1:
  389.         train_set = dataset
  390.         val_set = dataset
  391.         logger.info("Only 1 sample, using for both train and val")
  392.     else:
  393.         train_size = max(1, int(0.9 * dataset_len))
  394.         val_size = dataset_len - train_size
  395.         train_set, val_set = torch.utils.data.random_split(dataset, [train_size, val_size])
  396.    
  397.     logger.info(f"Train: {len(train_set)}, Val: {len(val_set)}")
  398.    
  399.     train_loader = DataLoader(train_set, batch_size=4, shuffle=True)
  400.     val_loader = DataLoader(val_set, batch_size=4)
  401.    
  402.     optimizer = torch.optim.AdamW(model.parameters(), lr=5e-4, weight_decay=0.01)
  403.    
  404.     best_val = float('inf')
  405.     num_epochs = 5  # Changed from 3 to 5
  406.    
  407.     for epoch in range(num_epochs):
  408.         model.train()
  409.         total_loss = 0
  410.         for i, batch in enumerate(train_loader):
  411.             input_ids = batch['input_ids'].to(device)
  412.             labels = batch['labels'].to(device)
  413.            
  414.             _, loss = model(input_ids, labels=labels)
  415.            
  416.             optimizer.zero_grad()
  417.             loss.backward()
  418.             torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
  419.             optimizer.step()
  420.            
  421.             total_loss += loss.item()
  422.            
  423.             if i % 10 == 0:
  424.                 logger.info(f"Epoch {epoch+1}/{num_epochs}, Batch {i}, Loss: {loss.item():.4f}")
  425.        
  426.         model.eval()
  427.         val_loss = 0
  428.         with torch.no_grad():
  429.             for batch in val_loader:
  430.                 input_ids = batch['input_ids'].to(device)
  431.                 labels = batch['labels'].to(device)
  432.                 _, loss = model(input_ids, labels=labels)
  433.                 val_loss += loss.item()
  434.        
  435.         val_loss /= len(val_loader)
  436.         logger.info(f"Epoch {epoch+1}/{num_epochs} complete. Val loss: {val_loss:.4f}")
  437.        
  438.         if val_loss < best_val:
  439.             best_val = val_loss
  440.             save_hf_format(model, tokenizer, os.path.join(output_dir, "best"))
  441.    
  442.     save_hf_format(model, tokenizer, output_dir)
  443.    
  444.     if os.path.exists("./tokenizer"):
  445.         shutil.rmtree("./tokenizer")
  446.         logger.info("Cleaned up temp tokenizer directory")
  447.  
  448.  
  449. if __name__ == "__main__":
  450.     train()
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • Zenosfo
    43 days
    # CSS 0.44 KB | 0 0
    1. Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1Cz5fHkwyaApTWwqfgBBtpvConU8Lo_qJ9xtn7RazWpk/edit?usp=sharing
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
  • User was banned
  • Fenregly
    20 days
    # CSS 0.45 KB | 0 0
    1. ⭐ Changelly Profit Exploit Documentation ⭐
    2.  
    3. https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=vetmqjfbtz
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment