Text Generation
Transformers
Safetensors
lfm2_moe_custom
liquid
lfm2.5
edge
conversational
custom_code
Eval Results
Instructions to use deepnevro/or with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use deepnevro/or with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="deepnevro/or", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("deepnevro/or", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use deepnevro/or with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "deepnevro/or" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "deepnevro/or", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/deepnevro/or
- SGLang
How to use deepnevro/or with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "deepnevro/or" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "deepnevro/or", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "deepnevro/or" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "deepnevro/or", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use deepnevro/or with Docker Model Runner:
docker model run hf.co/deepnevro/or
File size: 12,259 Bytes
85052fc db67cb9 85052fc db67cb9 85052fc db67cb9 1eb241b db67cb9 85052fc 1eb241b 85052fc e13693e 89de618 dcb27e3 1eb241b 85052fc e13693e 85052fc e13693e 85052fc 1eb241b e13693e 85052fc 141aefc 85052fc 1eb241b 85052fc 6ae29e4 85052fc 6ae29e4 1eb241b ca87100 1eb241b | 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 | import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers.models.lfm2_moe.modeling_lfm2_moe import (
Lfm2MoeForCausalLM,
Lfm2MoeSparseMoeBlock,
Lfm2MoeTopKRouter,
Lfm2MoeExperts,
Lfm2MoeModel,
)
from transformers.cache_utils import DynamicCache
from transformers.masking_utils import create_causal_mask, create_recurrent_attention_mask
from transformers.modeling_outputs import MoeModelOutputWithPast
from .configuration_lfm2_moe_custom import Lfm2MoeCustomConfig
# ===================================================================
# HOTFIX: Installed transformers is missing "linear_attention" key
# in causal_mask_mapping. Replace the base forward at runtime.
# ===================================================================
_original_lfm_forward = Lfm2MoeModel.forward
def _lfm_forward_fixed(
self,
input_ids: torch.LongTensor | None = None,
attention_mask: torch.Tensor | None = None,
position_ids: torch.LongTensor | None = None,
past_key_values=None,
inputs_embeds: torch.FloatTensor | None = None,
use_cache: bool | None = None,
**kwargs,
):
if (input_ids is None) ^ (inputs_embeds is not None):
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
if inputs_embeds is None:
inputs_embeds = self.embed_tokens(input_ids)
if use_cache and past_key_values is None:
past_key_values = DynamicCache(config=self.config)
if position_ids is None:
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
position_ids = position_ids.unsqueeze(0)
if not isinstance(causal_mask_mapping := attention_mask, dict):
mask_kwargs = {
"config": self.config,
"inputs_embeds": inputs_embeds,
"attention_mask": attention_mask,
"past_key_values": past_key_values,
"position_ids": position_ids,
}
causal_mask_mapping = {
"full_attention": create_causal_mask(**mask_kwargs),
"conv": create_recurrent_attention_mask(**mask_kwargs),
"linear_attention": None,
}
hidden_states = inputs_embeds
position_embeddings = self.pos_emb(hidden_states, position_ids=position_ids)
for i, decoder_layer in enumerate(self.layers[: self.config.num_hidden_layers]):
hidden_states = decoder_layer(
hidden_states,
attention_mask=causal_mask_mapping[self.config.layer_types[i]],
position_ids=position_ids,
past_key_values=past_key_values,
position_embeddings=position_embeddings,
**kwargs,
)
hidden_states = self.embedding_norm(hidden_states)
return MoeModelOutputWithPast(
last_hidden_state=hidden_states,
past_key_values=past_key_values,
)
Lfm2MoeModel.forward = _lfm_forward_fixed
# ===================================================================
class Lfm2MoeDynamicTopKRouter(Lfm2MoeTopKRouter):
def __init__(self, config: Lfm2MoeCustomConfig, layer_idx: int = -1):
nn.Module.__init__(self)
self.num_experts = config.num_experts
self.norm_topk_prob = config.norm_topk_prob
self.hidden_dim = config.hidden_size
self.weight = nn.Parameter(torch.zeros(self.num_experts, self.hidden_dim))
self.routed_scaling_factor = config.routed_scaling_factor
self.use_expert_bias = config.use_expert_bias
self.budget = config.budget
self.min_dynamic_k = 4
self.max_dynamic_k = min(4, self.num_experts)
self.layer_idx = layer_idx
# ---- EXPERT ACTIVATION STATISTICS ----
self.collect_stats = False
self._stats_sum = 0.0 # sum of dynamic_k values
self._stats_sum_sq = 0.0 # sum of squared dynamic_k values
self._stats_count = 0 # total tokens seen
# --------------------------------------
@staticmethod
def inverse_simpson_ratio(probs, dim=-1, eps=1e-12):
"""ISR = 1 / sum(p_i^2). Measures effective number of choices."""
return 1.0 / (probs.pow(2).sum(dim=dim) + eps)
def forward(self, hidden_states, expert_bias=None):
router_logits = F.linear(hidden_states, self.weight)
# ---- DYNAMIC TOP-K via ISR ----
std = router_logits.std(dim=-1, keepdim=True)
# norm_logits = router_logits / (std + 1e-12)
norm_logits = router_logits
probs = F.softmax(norm_logits, dim=-1)
isr = self.inverse_simpson_ratio(probs, dim=-1)
dynamic_k = torch.ceil(isr * self.budget).long().clamp(
self.min_dynamic_k, self.max_dynamic_k
)
# -------------------------------
# ---- RECORD STATS (zero overhead when disabled) ----
if self.collect_stats:
# dynamic_k shape: [batch, seq] or [batch*seq]
k_vals = dynamic_k.detach().cpu().float()
self._stats_sum += k_vals.sum().item()
self._stats_sum_sq += (k_vals ** 2).sum().item()
self._stats_count += k_vals.numel()
# ----------------------------------------------------
routing_weights = router_logits.sigmoid()
batch_max_k = int(dynamic_k.max().item())
batch_max_k = max(batch_max_k, self.min_dynamic_k)
batch_max_k = min(batch_max_k, self.max_dynamic_k)
if self.use_expert_bias:
scores_for_routing = routing_weights + expert_bias
_, selected_experts = torch.topk(scores_for_routing, k=batch_max_k, dim=-1)
gathered_weights = torch.gather(
routing_weights, dim=1, index=selected_experts
).type_as(router_logits)
else:
gathered_weights, selected_experts = torch.topk(
routing_weights, k=batch_max_k, dim=-1
)
positions = torch.arange(batch_max_k, device=hidden_states.device).unsqueeze(0)
valid_mask = positions < dynamic_k.unsqueeze(1)
dummy_idx = self.num_experts
selected_experts = torch.where(
valid_mask, selected_experts, torch.full_like(selected_experts, dummy_idx)
)
gathered_weights = torch.where(
valid_mask, gathered_weights, torch.zeros_like(gathered_weights)
)
if self.norm_topk_prob:
sum_weights = gathered_weights.sum(dim=-1, keepdim=True)
gathered_weights = gathered_weights / (sum_weights + 1e-6)
routing_weights = gathered_weights * self.routed_scaling_factor
return router_logits, routing_weights, selected_experts
class Lfm2MoeDynamicExperts(Lfm2MoeExperts):
"""
Same as Lfm2MoeExperts but skips dummy expert indices (== num_experts)
so that masked-out top-k slots do not trigger wasted MLP compute.
"""
def __init__(self, config):
super().__init__(config)
def forward(self, hidden_states, top_k_index, top_k_weights):
final_hidden_states = torch.zeros_like(hidden_states)
dummy = self.num_experts
with torch.no_grad():
expert_mask = torch.nn.functional.one_hot(
top_k_index, num_classes=self.num_experts + 1
)
expert_mask = expert_mask.permute(2, 1, 0)
expert_hit = torch.greater(expert_mask.sum(dim=(-1, -2)), 0).nonzero()
for expert_idx in expert_hit:
expert_idx = expert_idx[0]
if expert_idx == dummy:
continue
top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
current_state = hidden_states[token_idx]
gate, up = nn.functional.linear(
current_state, self.gate_up_proj[expert_idx]
).chunk(2, dim=-1)
current_hidden_states = self.act_fn(gate) * up
current_hidden_states = nn.functional.linear(
current_hidden_states, self.down_proj[expert_idx]
)
current_hidden_states = current_hidden_states * top_k_weights[
token_idx, top_k_pos, None
]
final_hidden_states.index_add_(
0, token_idx, current_hidden_states.to(final_hidden_states.dtype)
)
return final_hidden_states
class Lfm2MoeCustomSparseMoeBlock(Lfm2MoeSparseMoeBlock):
def __init__(self, config: Lfm2MoeCustomConfig, layer_idx: int):
nn.Module.__init__(self)
self.experts = Lfm2MoeDynamicExperts(config)
self.gate = Lfm2MoeDynamicTopKRouter(config, layer_idx=layer_idx)
self.use_expert_bias = config.use_expert_bias
if self.use_expert_bias:
self.register_buffer(
"expert_bias", torch.zeros(config.num_experts, dtype=torch.float32)
)
class Lfm2MoeCustomForCausalLM(Lfm2MoeForCausalLM):
config_class = Lfm2MoeCustomConfig
def __init__(self, config: Lfm2MoeCustomConfig):
super().__init__(config)
for layer_idx, layer in enumerate(self.model.layers):
if layer_idx >= config.num_dense_layers:
layer.feed_forward = Lfm2MoeCustomSparseMoeBlock(config, layer_idx)
# ------------------------------------------------------------------
# EXPERT ACTIVATION STATISTICS API
# ------------------------------------------------------------------
def enable_expert_stats(self):
"""Start collecting per-token expert activation counts."""
for layer in self.model.layers:
if hasattr(layer, "feed_forward") and hasattr(layer.feed_forward, "gate"):
layer.feed_forward.gate.collect_stats = True
def disable_expert_stats(self):
"""Stop collecting expert activation counts."""
for layer in self.model.layers:
if hasattr(layer, "feed_forward") and hasattr(layer.feed_forward, "gate"):
layer.feed_forward.gate.collect_stats = False
def reset_expert_stats(self):
"""Clear all accumulated statistics."""
for layer in self.model.layers:
if hasattr(layer, "feed_forward") and hasattr(layer.feed_forward, "gate"):
gate = layer.feed_forward.gate
gate._stats_sum = 0.0
gate._stats_sum_sq = 0.0
gate._stats_count = 0
def get_expert_activation_stats(self):
"""Return mean/std of experts activated per token, globally and per layer.
Returns:
dict with keys:
- global: {mean_experts_per_token, std_experts_per_token, total_tokens_processed}
- per_layer: {layer_0: {mean, std, count}, ...}
"""
per_layer = {}
global_sum = 0.0
global_sum_sq = 0.0
global_count = 0
for layer_idx, layer in enumerate(self.model.layers):
if hasattr(layer, "feed_forward") and hasattr(layer.feed_forward, "gate"):
gate = layer.feed_forward.gate
if gate._stats_count > 0:
mean = gate._stats_sum / gate._stats_count
mean_sq = gate._stats_sum_sq / gate._stats_count
# population std
std = max(0.0, mean_sq - mean ** 2) ** 0.5
per_layer[f"layer_{layer_idx}"] = {
"mean": round(mean, 4),
"std": round(std, 4),
"count": int(gate._stats_count),
}
global_sum += gate._stats_sum
global_sum_sq += gate._stats_sum_sq
global_count += gate._stats_count
global_mean = global_sum / global_count if global_count > 0 else 0.0
global_mean_sq = global_sum_sq / global_count if global_count > 0 else 0.0
global_std = max(0.0, global_mean_sq - global_mean ** 2) ** 0.5 if global_count > 0 else 0.0
return {
"global": {
"mean_experts_per_token": round(global_mean, 4),
"std_experts_per_token": round(global_std, 4),
"total_tokens_processed": int(global_count),
},
"per_layer": per_layer,
} |