Files
2026-07-13 13:24:13 +08:00

223 lines
9.5 KiB
Python

import random
import torch
from torch import nn
from torch.nn import functional as F
from einops import rearrange, repeat
from typing import Optional, Tuple, List
from dataclasses import dataclass
from apex.normalization.fused_layer_norm import fused_rms_norm_affine
from kernel.flash_sparse_decoding import flash_block_sparse_decoding
from kernel.flash_attention_with_kv_cache import flash_attention_with_kv_cache
from kernel.rotary import apply_rotary_emb
from flash_attn import flash_attn_with_kvcache
import math
import logging
logger = logging.getLogger(__name__)
from .context_manager import KVManager
@dataclass
class ModelArgs:
dim: int
n_layers: int
hidden_dim: int
n_heads: int
n_kv_heads: int
vocab_size: Optional[int] = None
max_batch_size: int = 0
max_seq_len: int = -1
model_parallel_size: int = 1
rope_theta: float = 10000.0
norm_eps: float = 1e-5
tie_word_embeddings: bool = False
save_feature: str = None
# decoding config
temperature: float = 0.6
top_p: float = 0.9
# SPA config
resa_rec_freq: int = 32
resa_block_size: int = 16
resa_sparse_ratio: float = 0.1
resa_local_block_num: int = 1
resa_min_block_num: int = 16
class RMSNorm(nn.Module):
def __init__(self, dim: int, eps: float = 1e-5):
super().__init__()
self.eps = eps
self.weight = nn.Parameter(torch.ones(dim))
self.normalized_shape = torch.Size((dim,))
def forward(self, x):
return fused_rms_norm_affine(x, self.weight, self.normalized_shape, self.eps)
def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0):
freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
t = torch.arange(end, device=freqs.device, dtype=torch.float32)
freqs = torch.outer(t, freqs)
return freqs
class Attention(nn.Module):
def __init__(self, index: int, args: ModelArgs):
super(Attention, self).__init__()
self.args = args
self.layer_index = index
self.head_dim = args.dim // args.n_heads
self.kv_head = args.n_kv_heads
self.head = args.n_heads
self.qkv_proj = nn.Linear(self.args.dim, (self.head + self.kv_head * 2) * self.head_dim, bias=True)
self.o_proj = nn.Linear(self.head * self.head_dim, self.args.dim, bias=False)
# from kernel.tilelang_sparse_decoding import SparseFlashAttn
# self.sparse_kernel = SparseFlashAttn(self.head, self.kv_head, self.head_dim, self.head_dim, self.args.resa_block_size)
def forward(
self,
x: torch.Tensor,
rel_pos: Tuple[torch.Tensor, torch.Tensor],
cu_seqlens_q: torch.Tensor,
cu_seqlens_k: torch.Tensor,
kv_cache_index: Tuple[torch.Tensor, torch.Tensor] = None,
kv_cache: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
) -> torch.Tensor:
bsz, seqlen = x.shape[0], x.shape[1]
seq_bsz = cu_seqlens_q.shape[0] - 1
seqlens_q = cu_seqlens_q[1:] - cu_seqlens_q[:-1]
seqlens_k = cu_seqlens_k[1:] - cu_seqlens_k[:-1]
xqkv = self.qkv_proj(x)
xqkv = rearrange(xqkv, 'b n (h d) -> (b n) h d', d=self.head_dim)
xqk, xv = xqkv.split([self.head + self.kv_head, self.kv_head], dim=-2)
xqk = apply_rotary_emb(xqk.unsqueeze(0), *rel_pos, inplace=True).squeeze(0)
xq, xk = xqk.split([self.head, self.kv_head], dim=-2)
if kv_cache is not None:
batch_index, seq_index = kv_cache_index
kv_cache = kv_cache[self.layer_index]
kv_cache[0][batch_index, seq_index] = xk
kv_cache[1][batch_index, seq_index] = xv
if self.args.resa_sparse_ratio < 1.0 and seqlen == 1:
assert kv_cache is not None, "kv_cache should not be None for generation"
kv_manager = kv_cache[2]
if kv_manager.num_elements is None:
kv_manager.init_centeroids(kv_cache[0][:seq_bsz], seqlens_k)
else:
kv_manager.update_centeroids(xk, seqlens_k)
sparse_indices = kv_manager.get_kv_cache_indices_fast(xq, seqlens_k)
output = flash_block_sparse_decoding(xq, kv_cache[0], kv_cache[1], seqlens_k, sparse_indices, block_size=self.args.resa_block_size)
else:
max_seqlen_q = seqlens_q.max().item()
xq_pad = torch.zeros((seq_bsz, max_seqlen_q, self.head, self.head_dim), device=xq.device, dtype=xq.dtype)
xq_pad_mask = torch.arange(max_seqlen_q, device=xq.device)[None, :] >= max_seqlen_q - seqlens_q[:, None]
xq_pad[xq_pad_mask] = xq
if max_seqlen_q <= 32:
output = flash_attention_with_kv_cache(xq_pad, kv_cache[0], kv_cache[1], cache_seqlens=seqlens_k)
else:
output = flash_attn_with_kvcache(xq_pad, kv_cache[0], kv_cache[1], cache_seqlens=seqlens_k, causal=True)
output = output[xq_pad_mask]
output = rearrange(output, '(b n) h d -> b n (h d)', b=bsz)
output = self.o_proj(output)
return output
class FeedForwardNetwork(nn.Module):
def __init__(
self,
embed_dim,
ffn_dim,
):
super().__init__()
self.embed_dim = embed_dim
self.up_proj = nn.Linear(self.embed_dim, ffn_dim, bias=False)
self.down_proj = nn.Linear(ffn_dim, self.embed_dim, bias=False)
self.gate_proj = nn.Linear(self.embed_dim, ffn_dim, bias=False)
def forward(self, x):
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
class Block(nn.Module):
def __init__(self, index: int, args: ModelArgs):
super(Block, self).__init__()
self.args = args
self.self_attn = Attention(index, args)
self.mlp = FeedForwardNetwork(args.dim, args.hidden_dim)
self.input_layernorm = RMSNorm(args.dim, eps=args.norm_eps)
self.post_attention_layernorm = RMSNorm(args.dim, eps=args.norm_eps)
def forward(
self,
x: torch.Tensor,
rel_pos: Tuple[torch.Tensor, torch.Tensor],
cu_seqlens_q: torch.Tensor,
cu_seqlens_k: torch.Tensor,
kv_cache_index: Tuple[torch.Tensor, torch.Tensor],
kv_cache: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
) -> torch.Tensor:
h = x + self.self_attn(self.input_layernorm(x), rel_pos=rel_pos, cu_seqlens_q=cu_seqlens_q, cu_seqlens_k=cu_seqlens_k, kv_cache_index=kv_cache_index, kv_cache=kv_cache)
out = h + self.mlp(self.post_attention_layernorm(h))
return out
class Model(nn.Module):
def __init__(self, args: ModelArgs):
super(Model, self).__init__()
self.args = args
self.tok_embeddings = nn.Embedding(args.vocab_size, args.dim)
nn.init.normal_(self.tok_embeddings.weight, mean=0, std=args.dim ** -0.5)
self.layers = nn.ModuleList()
for index in range(args.n_layers):
block = Block(index,args)
self.layers.append(block)
self.norm = RMSNorm(args.dim, eps=args.norm_eps)
self.output = nn.Linear(args.dim, args.vocab_size, bias=False)
if args.tie_word_embeddings:
self.output.weight = self.tok_embeddings.weight
self._precompute_freqs_cis(args.max_seq_len)
def _precompute_freqs_cis(self, max_seqlen):
freqs_cis = precompute_freqs_cis(self.args.dim // self.args.n_heads, max_seqlen, theta=self.args.rope_theta)
self.cos = freqs_cis.cos()
self.sin = freqs_cis.sin()
def forward(
self,
tokens: torch.Tensor,
start_pos: Optional[torch.Tensor] = None,
cu_seqlens: Optional[torch.Tensor] = None,
kv_cache: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
last_hidden_only: bool = False,
) -> torch.Tensor:
assert kv_cache is not None, "kv_cache should not be None for decoding only code"
seqlens_q = cu_seqlens[1:] - cu_seqlens[:-1]
seqlens_k = start_pos + seqlens_q
cu_seqlens_q = torch.cat((torch.tensor([0], device=tokens.device), seqlens_q.cumsum(dim=0)), dim=0).to(torch.int32)
cu_seqlens_k = torch.cat((torch.tensor([0], device=tokens.device), seqlens_k.cumsum(dim=0)), dim=0).to(torch.int32)
h = self.tok_embeddings(tokens)
batch_index = torch.cat([torch.full((seqlens_q[i],), fill_value=i) for i in range(len(seqlens_q))])
seq_index = torch.cat([torch.arange(start_pos[i], seqlens_k[i], device=h.device) for i in range(len(seqlens_q))])
self.cos, self.sin = self.cos.to(h), self.sin.to(h)
rel_pos = (self.cos[seq_index], self.sin[seq_index])
for i, layer in enumerate(self.layers):
h = layer(h, rel_pos=rel_pos, cu_seqlens_q=cu_seqlens_q, cu_seqlens_k=cu_seqlens_k, kv_cache_index=(batch_index, seq_index), kv_cache=kv_cache)
h = self.norm(h)
if last_hidden_only:
return h
else:
logits = self.output(h)
return logits
def create_kv_cache(args: ModelArgs, batch_size: int, dtype: torch.dtype = torch.float16, device: torch.device = torch.device('cuda')) -> List[Tuple[torch.Tensor, torch.Tensor]]:
kv_cache = []
for _ in range(args.n_layers):
k_cache = torch.zeros(batch_size, args.max_seq_len,
args.n_kv_heads, args.dim // args.n_heads, dtype=dtype, device=device)
v_cache = torch.zeros(batch_size, args.max_seq_len,
args.n_kv_heads, args.dim // args.n_heads, dtype=dtype, device=device)
kv_manager = KVManager(args.n_kv_heads, args.resa_block_size, args.resa_sparse_ratio, args.resa_local_block_num, args.resa_min_block_num)
kv_cache.append([k_cache, v_cache, kv_manager])
return kv_cache