Upload PersadianNanoV4Model.py with huggingface_hub
Browse files- PersadianNanoV4Model.py +56 -74
PersadianNanoV4Model.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
| 1 |
-
#
|
| 2 |
-
# Stable GPU-ready implementation with Hugging Face compatibility
|
| 3 |
|
| 4 |
import math
|
| 5 |
import torch
|
| 6 |
import torch.nn as nn
|
| 7 |
import torch.nn.functional as F
|
| 8 |
-
from transformers import
|
| 9 |
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 10 |
|
| 11 |
# ============================================================
|
|
@@ -14,51 +13,28 @@ from transformers.modeling_outputs import CausalLMOutputWithPast
|
|
| 14 |
|
| 15 |
class PersadianNanoV4Config:
|
| 16 |
def __init__(self):
|
| 17 |
-
# Core architecture (MATCH CHECKPOINT)
|
| 18 |
self.hidden_size = 512
|
| 19 |
self.intermediate_size = 1024
|
| 20 |
self.num_hidden_layers = 12
|
| 21 |
-
|
| 22 |
-
# Attention
|
| 23 |
self.num_attention_heads = 8
|
| 24 |
self.num_key_value_heads = 4
|
| 25 |
-
|
| 26 |
-
# MoE
|
| 27 |
self.num_experts = 4
|
| 28 |
self.num_experts_per_tok = 2
|
| 29 |
-
|
| 30 |
-
# Progressive experts
|
| 31 |
self.progressive_experts = True
|
| 32 |
self.min_experts = 1
|
| 33 |
self.max_experts = 2
|
| 34 |
-
|
| 35 |
-
# Hyper connections
|
| 36 |
self.use_hyper_connection = True
|
| 37 |
-
|
| 38 |
-
# Compression
|
| 39 |
self.use_compressed_attention = True
|
| 40 |
self.compress_ratio = 4
|
| 41 |
-
|
| 42 |
-
# Context
|
| 43 |
-
self.max_position_embeddings = 2048
|
| 44 |
-
|
| 45 |
-
# Tokenizer
|
| 46 |
self.vocab_size = 50257
|
|
|
|
| 47 |
self.bos_token_id = 50256
|
| 48 |
self.eos_token_id = 50256
|
| 49 |
-
|
| 50 |
-
# RoPE
|
| 51 |
self.rope_theta = 10000.0
|
| 52 |
-
|
| 53 |
-
# Regularization
|
| 54 |
self.dropout = 0.1
|
| 55 |
self.layer_norm_eps = 1e-5
|
| 56 |
-
|
| 57 |
-
# Attention
|
| 58 |
self.attention_dropout = 0.0
|
| 59 |
self.use_flash_attention = True
|
| 60 |
-
|
| 61 |
-
# Precision
|
| 62 |
self.torch_dtype = "float16"
|
| 63 |
|
| 64 |
# ============================================================
|
|
@@ -127,7 +103,6 @@ class CompressedSparseAttention(nn.Module):
|
|
| 127 |
|
| 128 |
def forward(self, hidden_states, attention_mask=None, position_ids=None):
|
| 129 |
batch_size, seq_len, _ = hidden_states.shape
|
| 130 |
-
|
| 131 |
q = self.q_proj(hidden_states).view(batch_size, seq_len, self.num_heads, self.head_dim)
|
| 132 |
|
| 133 |
if self.config.use_compressed_attention and seq_len > 512:
|
|
@@ -172,7 +147,6 @@ class MixtureOfExperts(nn.Module):
|
|
| 172 |
super().__init__()
|
| 173 |
self.config = config
|
| 174 |
self.num_experts = config.num_experts
|
| 175 |
-
|
| 176 |
self.experts = nn.ModuleList([
|
| 177 |
nn.Sequential(
|
| 178 |
nn.Linear(config.hidden_size, config.intermediate_size),
|
|
@@ -181,7 +155,6 @@ class MixtureOfExperts(nn.Module):
|
|
| 181 |
nn.Dropout(config.dropout)
|
| 182 |
) for _ in range(config.num_experts)
|
| 183 |
])
|
| 184 |
-
|
| 185 |
self.router = nn.Linear(config.hidden_size, config.num_experts, bias=False)
|
| 186 |
self.aux_loss_coef = 0.01
|
| 187 |
|
|
@@ -211,7 +184,6 @@ class MixtureOfExperts(nn.Module):
|
|
| 211 |
|
| 212 |
router_probs = routing_weights.mean(dim=0)
|
| 213 |
aux_loss = torch.var(router_probs)
|
| 214 |
-
|
| 215 |
return final_hidden.view(batch_size, seq_len, hidden_size), aux_loss * self.aux_loss_coef
|
| 216 |
|
| 217 |
# ============================================================
|
|
@@ -226,7 +198,6 @@ class PersadianNanoV4DecoderLayer(nn.Module):
|
|
| 226 |
self.self_attn = CompressedSparseAttention(config)
|
| 227 |
self.post_attention_layernorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 228 |
self.moe = MixtureOfExperts(config)
|
| 229 |
-
|
| 230 |
if config.use_hyper_connection:
|
| 231 |
self.hc_attention = AdaptiveHyperConnection(config.hidden_size)
|
| 232 |
self.hc_moe = AdaptiveHyperConnection(config.hidden_size)
|
|
@@ -253,7 +224,7 @@ class PersadianNanoV4DecoderLayer(nn.Module):
|
|
| 253 |
return hidden_states, aux_loss
|
| 254 |
|
| 255 |
# ============================================================
|
| 256 |
-
# MAIN MODEL
|
| 257 |
# ============================================================
|
| 258 |
|
| 259 |
class PersadianNanoV4Model(nn.Module):
|
|
@@ -301,7 +272,9 @@ class PersadianNanoV4Model(nn.Module):
|
|
| 301 |
if top_k > 0:
|
| 302 |
values, _ = torch.topk(next_token_logits, top_k)
|
| 303 |
min_values = values[:, -1].unsqueeze(-1)
|
| 304 |
-
next_token_logits = torch.where(next_token_logits < min_values,
|
|
|
|
|
|
|
| 305 |
probs = F.softmax(next_token_logits, dim=-1)
|
| 306 |
next_token = torch.multinomial(probs, num_samples=1)
|
| 307 |
input_ids = torch.cat([input_ids, next_token], dim=1)
|
|
@@ -310,11 +283,10 @@ class PersadianNanoV4Model(nn.Module):
|
|
| 310 |
return input_ids
|
| 311 |
|
| 312 |
# ============================================================
|
| 313 |
-
# HF
|
| 314 |
# ============================================================
|
| 315 |
|
| 316 |
class PersadianNanoV4ConfigHF(PretrainedConfig):
|
| 317 |
-
"""HF-compatible config class"""
|
| 318 |
model_type = "persadian_nano_v4"
|
| 319 |
|
| 320 |
def __init__(self, **kwargs):
|
|
@@ -322,59 +294,69 @@ class PersadianNanoV4ConfigHF(PretrainedConfig):
|
|
| 322 |
for key, value in kwargs.items():
|
| 323 |
setattr(self, key, value)
|
| 324 |
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
# ============================================================
|
| 328 |
-
|
| 329 |
-
class PersadianNanoV4ForCausalLM(PreTrainedModel):
|
| 330 |
-
"""HF-compatible model class"""
|
| 331 |
config_class = PersadianNanoV4ConfigHF
|
| 332 |
|
| 333 |
-
# Add required attributes for modern Transformers
|
| 334 |
-
_tied_weights_keys = ["lm_head.weight"]
|
| 335 |
-
_no_split_modules = ["PersadianNanoV4DecoderLayer"]
|
| 336 |
-
|
| 337 |
def __init__(self, config):
|
| 338 |
-
super().__init__(
|
| 339 |
-
# Create
|
| 340 |
original_config = PersadianNanoV4Config()
|
| 341 |
-
|
| 342 |
-
# Copy all attributes from HF config to original config
|
| 343 |
for key, value in config.__dict__.items():
|
| 344 |
if hasattr(original_config, key):
|
| 345 |
setattr(original_config, key, value)
|
| 346 |
-
|
| 347 |
self.model = PersadianNanoV4Model(original_config)
|
| 348 |
-
self.post_init()
|
| 349 |
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
|
| 359 |
-
def forward(self, input_ids, attention_mask=None, labels=None
|
| 360 |
logits, aux_loss = self.model(input_ids, attention_mask)
|
| 361 |
-
|
| 362 |
loss = None
|
| 363 |
if labels is not None:
|
| 364 |
shift_logits = logits[..., :-1, :].contiguous()
|
| 365 |
shift_labels = labels[..., 1:].contiguous()
|
| 366 |
-
loss = F.cross_entropy(
|
| 367 |
-
|
| 368 |
-
shift_labels.view(-1)
|
| 369 |
-
)
|
| 370 |
-
|
| 371 |
-
return CausalLMOutputWithPast(
|
| 372 |
-
loss=loss,
|
| 373 |
-
logits=logits,
|
| 374 |
-
)
|
| 375 |
-
|
| 376 |
-
def prepare_inputs_for_generation(self, input_ids, **kwargs):
|
| 377 |
-
return {"input_ids": input_ids}
|
| 378 |
|
| 379 |
def generate(self, input_ids, **kwargs):
|
| 380 |
return self.model.generate(input_ids, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Simple Hugging Face compatible wrapper without complex inheritance
|
|
|
|
| 2 |
|
| 3 |
import math
|
| 4 |
import torch
|
| 5 |
import torch.nn as nn
|
| 6 |
import torch.nn.functional as F
|
| 7 |
+
from transformers import PretrainedConfig
|
| 8 |
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 9 |
|
| 10 |
# ============================================================
|
|
|
|
| 13 |
|
| 14 |
class PersadianNanoV4Config:
|
| 15 |
def __init__(self):
|
|
|
|
| 16 |
self.hidden_size = 512
|
| 17 |
self.intermediate_size = 1024
|
| 18 |
self.num_hidden_layers = 12
|
|
|
|
|
|
|
| 19 |
self.num_attention_heads = 8
|
| 20 |
self.num_key_value_heads = 4
|
|
|
|
|
|
|
| 21 |
self.num_experts = 4
|
| 22 |
self.num_experts_per_tok = 2
|
|
|
|
|
|
|
| 23 |
self.progressive_experts = True
|
| 24 |
self.min_experts = 1
|
| 25 |
self.max_experts = 2
|
|
|
|
|
|
|
| 26 |
self.use_hyper_connection = True
|
|
|
|
|
|
|
| 27 |
self.use_compressed_attention = True
|
| 28 |
self.compress_ratio = 4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
self.vocab_size = 50257
|
| 30 |
+
self.max_position_embeddings = 2048
|
| 31 |
self.bos_token_id = 50256
|
| 32 |
self.eos_token_id = 50256
|
|
|
|
|
|
|
| 33 |
self.rope_theta = 10000.0
|
|
|
|
|
|
|
| 34 |
self.dropout = 0.1
|
| 35 |
self.layer_norm_eps = 1e-5
|
|
|
|
|
|
|
| 36 |
self.attention_dropout = 0.0
|
| 37 |
self.use_flash_attention = True
|
|
|
|
|
|
|
| 38 |
self.torch_dtype = "float16"
|
| 39 |
|
| 40 |
# ============================================================
|
|
|
|
| 103 |
|
| 104 |
def forward(self, hidden_states, attention_mask=None, position_ids=None):
|
| 105 |
batch_size, seq_len, _ = hidden_states.shape
|
|
|
|
| 106 |
q = self.q_proj(hidden_states).view(batch_size, seq_len, self.num_heads, self.head_dim)
|
| 107 |
|
| 108 |
if self.config.use_compressed_attention and seq_len > 512:
|
|
|
|
| 147 |
super().__init__()
|
| 148 |
self.config = config
|
| 149 |
self.num_experts = config.num_experts
|
|
|
|
| 150 |
self.experts = nn.ModuleList([
|
| 151 |
nn.Sequential(
|
| 152 |
nn.Linear(config.hidden_size, config.intermediate_size),
|
|
|
|
| 155 |
nn.Dropout(config.dropout)
|
| 156 |
) for _ in range(config.num_experts)
|
| 157 |
])
|
|
|
|
| 158 |
self.router = nn.Linear(config.hidden_size, config.num_experts, bias=False)
|
| 159 |
self.aux_loss_coef = 0.01
|
| 160 |
|
|
|
|
| 184 |
|
| 185 |
router_probs = routing_weights.mean(dim=0)
|
| 186 |
aux_loss = torch.var(router_probs)
|
|
|
|
| 187 |
return final_hidden.view(batch_size, seq_len, hidden_size), aux_loss * self.aux_loss_coef
|
| 188 |
|
| 189 |
# ============================================================
|
|
|
|
| 198 |
self.self_attn = CompressedSparseAttention(config)
|
| 199 |
self.post_attention_layernorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 200 |
self.moe = MixtureOfExperts(config)
|
|
|
|
| 201 |
if config.use_hyper_connection:
|
| 202 |
self.hc_attention = AdaptiveHyperConnection(config.hidden_size)
|
| 203 |
self.hc_moe = AdaptiveHyperConnection(config.hidden_size)
|
|
|
|
| 224 |
return hidden_states, aux_loss
|
| 225 |
|
| 226 |
# ============================================================
|
| 227 |
+
# MAIN MODEL
|
| 228 |
# ============================================================
|
| 229 |
|
| 230 |
class PersadianNanoV4Model(nn.Module):
|
|
|
|
| 272 |
if top_k > 0:
|
| 273 |
values, _ = torch.topk(next_token_logits, top_k)
|
| 274 |
min_values = values[:, -1].unsqueeze(-1)
|
| 275 |
+
next_token_logits = torch.where(next_token_logits < min_values,
|
| 276 |
+
torch.full_like(next_token_logits, float("-inf")),
|
| 277 |
+
next_token_logits)
|
| 278 |
probs = F.softmax(next_token_logits, dim=-1)
|
| 279 |
next_token = torch.multinomial(probs, num_samples=1)
|
| 280 |
input_ids = torch.cat([input_ids, next_token], dim=1)
|
|
|
|
| 283 |
return input_ids
|
| 284 |
|
| 285 |
# ============================================================
|
| 286 |
+
# HF COMPATIBLE WRAPPER (SIMPLE VERSION)
|
| 287 |
# ============================================================
|
| 288 |
|
| 289 |
class PersadianNanoV4ConfigHF(PretrainedConfig):
|
|
|
|
| 290 |
model_type = "persadian_nano_v4"
|
| 291 |
|
| 292 |
def __init__(self, **kwargs):
|
|
|
|
| 294 |
for key, value in kwargs.items():
|
| 295 |
setattr(self, key, value)
|
| 296 |
|
| 297 |
+
class PersadianNanoV4ForCausalLM(nn.Module):
|
| 298 |
+
"""Simple HF-compatible wrapper - no complex inheritance"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
config_class = PersadianNanoV4ConfigHF
|
| 300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
def __init__(self, config):
|
| 302 |
+
super().__init__()
|
| 303 |
+
# Create original config
|
| 304 |
original_config = PersadianNanoV4Config()
|
|
|
|
|
|
|
| 305 |
for key, value in config.__dict__.items():
|
| 306 |
if hasattr(original_config, key):
|
| 307 |
setattr(original_config, key, value)
|
| 308 |
+
self.config = original_config
|
| 309 |
self.model = PersadianNanoV4Model(original_config)
|
|
|
|
| 310 |
|
| 311 |
+
@classmethod
|
| 312 |
+
def from_pretrained(cls, pretrained_model_name_or_path, **kwargs):
|
| 313 |
+
"""Load model from Hugging Face hub"""
|
| 314 |
+
from transformers import AutoConfig
|
| 315 |
+
import torch
|
| 316 |
+
|
| 317 |
+
# Load config
|
| 318 |
+
config = AutoConfig.from_pretrained(pretrained_model_name_or_path, trust_remote_code=True)
|
| 319 |
+
|
| 320 |
+
# Create model
|
| 321 |
+
model = cls(config)
|
| 322 |
+
|
| 323 |
+
# Load weights
|
| 324 |
+
import os
|
| 325 |
+
from safetensors.torch import load_file
|
| 326 |
+
|
| 327 |
+
# Try to load weights
|
| 328 |
+
weight_files = [
|
| 329 |
+
f"{pretrained_model_name_or_path}/pytorch_model.bin",
|
| 330 |
+
f"{pretrained_model_name_or_path}/model.safetensors"
|
| 331 |
+
]
|
| 332 |
+
|
| 333 |
+
for weight_file in weight_files:
|
| 334 |
+
if os.path.exists(weight_file):
|
| 335 |
+
if weight_file.endswith('.safetensors'):
|
| 336 |
+
state_dict = load_file(weight_file)
|
| 337 |
+
else:
|
| 338 |
+
state_dict = torch.load(weight_file, map_location='cpu')
|
| 339 |
+
model.load_state_dict(state_dict, strict=False)
|
| 340 |
+
break
|
| 341 |
+
|
| 342 |
+
return model
|
| 343 |
|
| 344 |
+
def forward(self, input_ids, attention_mask=None, labels=None):
|
| 345 |
logits, aux_loss = self.model(input_ids, attention_mask)
|
|
|
|
| 346 |
loss = None
|
| 347 |
if labels is not None:
|
| 348 |
shift_logits = logits[..., :-1, :].contiguous()
|
| 349 |
shift_labels = labels[..., 1:].contiguous()
|
| 350 |
+
loss = F.cross_entropy(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
|
| 351 |
+
return CausalLMOutputWithPast(loss=loss, logits=logits)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
|
| 353 |
def generate(self, input_ids, **kwargs):
|
| 354 |
return self.model.generate(input_ids, **kwargs)
|
| 355 |
+
|
| 356 |
+
def eval(self):
|
| 357 |
+
self.model.eval()
|
| 358 |
+
return self
|
| 359 |
+
|
| 360 |
+
def to(self, device):
|
| 361 |
+
self.model = self.model.to(device)
|
| 362 |
+
return self
|