Text Generation
Transformers
Safetensors
Korean
English
aether_v2_7way
foundation-model
sovereign-ai
fully-open
open-source
mixture-of-experts
Mixture of Experts
heterogeneous-attention
latin-square
from-scratch
reproducible
pretrained
korean
vidraft
aether
conversational
custom_code
Instructions to use FINAL-Bench/Aether-7B-5Attn with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use FINAL-Bench/Aether-7B-5Attn with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="FINAL-Bench/Aether-7B-5Attn", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("FINAL-Bench/Aether-7B-5Attn", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use FINAL-Bench/Aether-7B-5Attn with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "FINAL-Bench/Aether-7B-5Attn" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FINAL-Bench/Aether-7B-5Attn", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/FINAL-Bench/Aether-7B-5Attn
- SGLang
How to use FINAL-Bench/Aether-7B-5Attn 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 "FINAL-Bench/Aether-7B-5Attn" \ --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": "FINAL-Bench/Aether-7B-5Attn", "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 "FINAL-Bench/Aether-7B-5Attn" \ --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": "FINAL-Bench/Aether-7B-5Attn", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use FINAL-Bench/Aether-7B-5Attn with Docker Model Runner:
docker model run hf.co/FINAL-Bench/Aether-7B-5Attn
fix: make model loadable via AutoModelForCausalLM (add auto_map, flatten module files to repo root, inherit GenerationMixin)
Browse files- differential.py +135 -0
differential.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Differential Transformer (PRODUCTION - causal-safe)
|
| 3 |
+
====================================================
|
| 4 |
+
|
| 5 |
+
Microsoft 2410.05258 (ICLR 2025)
|
| 6 |
+
Cancels noise via dual-softmax attention map subtraction.
|
| 7 |
+
|
| 8 |
+
Core formula:
|
| 9 |
+
DiffAttn(X) = (softmax(Q1 K1^T / sqrt(d)) - λ × softmax(Q2 K2^T / sqrt(d))) V
|
| 10 |
+
λ = exp(λ_q1 · λ_k1) - exp(λ_q2 · λ_k2) + λ_init
|
| 11 |
+
|
| 12 |
+
Implementation notes:
|
| 13 |
+
- GroupNorm (sequence-spanning) → LayerNorm(head_dim) (per-token, causal-safe)
|
| 14 |
+
- Causal triu mask explicit (was relying on SDPA, but split + softmax direct now)
|
| 15 |
+
- forward signature: layer_idx kwarg + (Tensor, past_kv) tuple return for modeling compat
|
| 16 |
+
|
| 17 |
+
Hyperparameter (configuration_aether_v2_7way.py):
|
| 18 |
+
- diff_lambda_init = 0.8
|
| 19 |
+
"""
|
| 20 |
+
from __future__ import annotations
|
| 21 |
+
import math
|
| 22 |
+
from typing import Optional, Tuple
|
| 23 |
+
|
| 24 |
+
import torch
|
| 25 |
+
import torch.nn as nn
|
| 26 |
+
import torch.nn.functional as F
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class DifferentialAttention(nn.Module):
|
| 30 |
+
"""λ-gated dual-softmax differential attention with causal mask + LayerNorm."""
|
| 31 |
+
|
| 32 |
+
def __init__(self, config, layer_idx: int = 0):
|
| 33 |
+
super().__init__()
|
| 34 |
+
self.layer_idx = layer_idx
|
| 35 |
+
self.h = config.hidden_size
|
| 36 |
+
self.num_heads = config.num_attention_heads
|
| 37 |
+
self.num_kv_heads = config.num_key_value_heads
|
| 38 |
+
self.head_dim = config.head_dim
|
| 39 |
+
# Differential splits head_dim in half
|
| 40 |
+
self.diff_head_dim = self.head_dim // 2
|
| 41 |
+
|
| 42 |
+
# Layer-depth lambda init (paper Eq. 3): λ_init = 0.8 - 0.6 * exp(-0.3 * (depth - 1))
|
| 43 |
+
# Use config base + depth decay if provided.
|
| 44 |
+
base = getattr(config, "diff_lambda_init", 0.8)
|
| 45 |
+
decay = getattr(config, "diff_lambda_layer_decay", 0.6)
|
| 46 |
+
# Simple per-layer init
|
| 47 |
+
self.lambda_init = base - decay * math.exp(-0.3 * max(layer_idx - 1, 0))
|
| 48 |
+
|
| 49 |
+
# Q/K/V/O projections
|
| 50 |
+
self.q_proj = nn.Linear(self.h, self.num_heads * self.head_dim, bias=False)
|
| 51 |
+
self.k_proj = nn.Linear(self.h, self.num_kv_heads * self.head_dim, bias=False)
|
| 52 |
+
self.v_proj = nn.Linear(self.h, self.num_kv_heads * self.head_dim, bias=False)
|
| 53 |
+
self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.h, bias=False)
|
| 54 |
+
|
| 55 |
+
# Lambda parameters per-head
|
| 56 |
+
self.lambda_q1 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
|
| 57 |
+
self.lambda_k1 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
|
| 58 |
+
self.lambda_q2 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
|
| 59 |
+
self.lambda_k2 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
|
| 60 |
+
|
| 61 |
+
# ★ FIX 5/7: LayerNorm(head_dim) — per-token norm, causal-safe.
|
| 62 |
+
# Was nn.GroupNorm(num_groups=num_heads, num_channels=num_heads*head_dim) which
|
| 63 |
+
# normalized over sequence dim and leaked future info.
|
| 64 |
+
self.subln = nn.LayerNorm(self.head_dim, eps=getattr(config, "rms_norm_eps", 1e-6))
|
| 65 |
+
|
| 66 |
+
def forward(
|
| 67 |
+
self,
|
| 68 |
+
hidden_states: torch.Tensor,
|
| 69 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 70 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 71 |
+
past_key_value=None,
|
| 72 |
+
use_cache: bool = False,
|
| 73 |
+
**kwargs,
|
| 74 |
+
) -> Tuple[torch.Tensor, Optional[object]]:
|
| 75 |
+
B, S, _ = hidden_states.shape
|
| 76 |
+
|
| 77 |
+
q = self.q_proj(hidden_states).view(B, S, self.num_heads, self.head_dim)
|
| 78 |
+
k = self.k_proj(hidden_states).view(B, S, self.num_kv_heads, self.head_dim)
|
| 79 |
+
v = self.v_proj(hidden_states).view(B, S, self.num_kv_heads, self.head_dim)
|
| 80 |
+
|
| 81 |
+
# AetherCache: cache full k,v (pre-split) in HF layout [B, kv_h, S, D]
|
| 82 |
+
if past_key_value is not None:
|
| 83 |
+
kc, vc = past_key_value.update(k.transpose(1, 2), v.transpose(1, 2), getattr(self, "cache_idx", self.layer_idx))
|
| 84 |
+
k = kc.transpose(1, 2)
|
| 85 |
+
v = vc.transpose(1, 2)
|
| 86 |
+
S_kv = k.shape[1]
|
| 87 |
+
|
| 88 |
+
# Split Q, K halves
|
| 89 |
+
q1, q2 = q.split(self.diff_head_dim, dim=-1) # [B, S, H, d/2]
|
| 90 |
+
k1, k2 = k.split(self.diff_head_dim, dim=-1) # [B, S_kv, kv_h, d/2]
|
| 91 |
+
|
| 92 |
+
# GQA repeat
|
| 93 |
+
repeat = self.num_heads // self.num_kv_heads
|
| 94 |
+
k1 = k1.repeat_interleave(repeat, dim=2)
|
| 95 |
+
k2 = k2.repeat_interleave(repeat, dim=2)
|
| 96 |
+
v = v.repeat_interleave(repeat, dim=2)
|
| 97 |
+
|
| 98 |
+
# Transpose to [B, H, S, d]
|
| 99 |
+
q1 = q1.transpose(1, 2)
|
| 100 |
+
q2 = q2.transpose(1, 2)
|
| 101 |
+
k1 = k1.transpose(1, 2)
|
| 102 |
+
k2 = k2.transpose(1, 2)
|
| 103 |
+
v = v.transpose(1, 2)
|
| 104 |
+
|
| 105 |
+
scale = 1.0 / math.sqrt(self.diff_head_dim)
|
| 106 |
+
scores1 = torch.matmul(q1, k1.transpose(-2, -1)) * scale
|
| 107 |
+
scores2 = torch.matmul(q2, k2.transpose(-2, -1)) * scale
|
| 108 |
+
|
| 109 |
+
# ★ FIX 5/7: causal mask (triu(1) blocks future)
|
| 110 |
+
# AetherCache: query i is at absolute pos (S_kv - S + i) -> shift the diagonal
|
| 111 |
+
causal = torch.ones(S, S_kv, device=q1.device, dtype=torch.bool).triu(1 + S_kv - S)
|
| 112 |
+
scores1 = scores1.masked_fill(causal, float("-inf"))
|
| 113 |
+
scores2 = scores2.masked_fill(causal, float("-inf"))
|
| 114 |
+
|
| 115 |
+
attn1 = F.softmax(scores1, dim=-1)
|
| 116 |
+
attn2 = F.softmax(scores2, dim=-1)
|
| 117 |
+
|
| 118 |
+
# Lambda per-head (paper Eq. 3)
|
| 119 |
+
lam_q1k1 = (self.lambda_q1 * self.lambda_k1).sum(dim=-1) # [H]
|
| 120 |
+
lam_q2k2 = (self.lambda_q2 * self.lambda_k2).sum(dim=-1)
|
| 121 |
+
lam = torch.exp(lam_q1k1) - torch.exp(lam_q2k2) + self.lambda_init # [H]
|
| 122 |
+
lam = lam.view(1, -1, 1, 1)
|
| 123 |
+
|
| 124 |
+
diff_attn = attn1 - lam * attn2
|
| 125 |
+
|
| 126 |
+
out = torch.matmul(diff_attn, v) # [B, H, S, head_dim]
|
| 127 |
+
# ★ FIX 5/7: per-token LayerNorm (was sequence-spanning GroupNorm = leak)
|
| 128 |
+
out = self.subln(out)
|
| 129 |
+
out = out * (1 - self.lambda_init)
|
| 130 |
+
|
| 131 |
+
out = out.transpose(1, 2).reshape(B, S, -1)
|
| 132 |
+
return self.o_proj(out), past_key_value
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
__all__ = ["DifferentialAttention"]
|