Text Generation
TensorRT
Safetensors
PyTorch
English
llama
code
developer-agent
blackwell
rtx-5070
slm
conversational
Instructions to use Vivid86/MiniTransformer-91M with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- TensorRT
How to use Vivid86/MiniTransformer-91M with TensorRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 6,546 Bytes
a2ec932 | 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 | """
CausalSelfAttention
ββββββββββββββββββββ
Modern causal self-attention with:
1. SCALED DOT-PRODUCT ATTENTION (SDPA)
torch.nn.functional.scaled_dot_product_attention dispatches to Flash
Attention 2 on CUDA automatically. Flash Attention rewrites the standard
O(NΒ²) memory algorithm as a tiled, IO-efficient kernel β peak memory is
O(N) instead of O(NΒ²), enabling much longer contexts on the same GPU.
2. ROTARY POSITION EMBEDDINGS (RoPE)
Applied to Q and K before attention. Encodes relative position as a
rotation in head-dimension space β see positional_encoding.py.
3. GROUPED-QUERY ATTENTION (GQA)
Standard MHA uses n_heads Q, K, V projections.
GQA shares fewer KV heads across multiple Q heads:
- n_kv_heads == n_heads β standard MHA (original Transformer)
- n_kv_heads < n_heads β GQA (Llama 3, Mistral)
- n_kv_heads == 1 β MQA (one shared KV pair)
GQA reduces KV-cache memory at inference by a factor of (n_heads / n_kv_heads)
with minimal quality loss.
4. KV-CACHE
During autoregressive inference, we only ever process one new token but
recompute all previous K, V from scratch if we run the full sequence each
step. The KV-cache stores previous K, V tensors and appends the new ones,
reducing each inference step from O(TΒ²) to O(T) compute.
5. BIAS-FREE PROJECTIONS
All linear projections use bias=False, matching Llama/Mistral practice.
Biases provide negligible benefit in large models and waste memory.
"""
import torch
import torch.nn as nn
import torch.nn.functional as F
from model.positional_encoding import apply_rotary_emb
class CausalSelfAttention(nn.Module):
"""
Multi-head causal self-attention with RoPE, GQA, SDPA, and KV-cache.
Args:
d_model: Model hidden dimension.
n_heads: Number of query attention heads.
n_kv_heads: Number of key/value heads (β€ n_heads). For standard MHA
set n_kv_heads == n_heads.
dropout: Attention dropout probability (0.0 recommended at scale).
"""
def __init__(
self,
d_model: int,
n_heads: int,
n_kv_heads: int,
dropout: float = 0.0,
):
super().__init__()
assert d_model % n_heads == 0, (
f"d_model ({d_model}) must be divisible by n_heads ({n_heads})"
)
assert n_heads % n_kv_heads == 0, (
f"n_heads ({n_heads}) must be divisible by n_kv_heads ({n_kv_heads})"
)
self.n_heads = n_heads
self.n_kv_heads = n_kv_heads
self.head_dim = d_model // n_heads
self.dropout = dropout
self.kv_groups = n_heads // n_kv_heads # how many Q heads share each KV head
# Separate Q/K/V projections β sizes differ for GQA
self.q_proj = nn.Linear(d_model, n_heads * self.head_dim, bias=False)
self.k_proj = nn.Linear(d_model, n_kv_heads * self.head_dim, bias=False)
self.v_proj = nn.Linear(d_model, n_kv_heads * self.head_dim, bias=False)
self.o_proj = nn.Linear(d_model, d_model, bias=False)
def forward(
self,
x: torch.Tensor,
cos: torch.Tensor,
sin: torch.Tensor,
past_kv: tuple[torch.Tensor, torch.Tensor] | None = None,
) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
"""
Args:
x: Input, shape [B, T, d_model].
cos: RoPE cosines, shape [1, 1, T, head_dim].
sin: RoPE sines, shape [1, 1, T, head_dim].
past_kv: Optional cached (k, v) from previous decode steps.
- None β training / first inference step (is_causal=True)
- tuple β incremental decode step (append to cache)
Returns:
out: Attention output, shape [B, T, d_model].
present_kv: Updated (k, v) cache tuple for use in the next step.
"""
B, T, _ = x.shape
# ββ Project Q, K, V ββββββββββββββββββββββββββββββββββββββββββββββββββ
q = self.q_proj(x).view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
k = self.k_proj(x).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2)
v = self.v_proj(x).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2)
# Shapes after transpose: [B, heads, T, head_dim]
# ββ Apply Rotary Embeddings βββββββββββββββββββββββββββββββββββββββββββ
q, k = apply_rotary_emb(q, k, cos, sin)
# ββ KV-Cache (inference only) βββββββββββββββββββββββββββββββββββββββββ
# Append new K/V to the cached history so we never recompute old tokens.
if past_kv is not None:
k = torch.cat([past_kv[0], k], dim=2) # grow along sequence axis
v = torch.cat([past_kv[1], v], dim=2)
present_kv = (k, v) # return updated cache
# ββ GQA: broadcast KV heads to match Q heads βββββββββββββββββββββββββ
# Each group of (n_heads/n_kv_heads) Q heads attends to the same KV pair.
if self.kv_groups > 1:
k = k.repeat_interleave(self.kv_groups, dim=1) # [B, n_heads, S, head_dim]
v = v.repeat_interleave(self.kv_groups, dim=1)
# ββ Scaled Dot-Product Attention ββββββββββββββββββββββββββββββββββββββ
# is_causal=True β auto-builds a causal mask (training / first step)
# is_causal=False β no mask (KV-cache handles causality by construction)
# PyTorch dispatches this to Flash Attention 2 on CUDA when available.
is_causal = past_kv is None
attn_out = F.scaled_dot_product_attention(
q, k, v,
dropout_p = self.dropout if self.training else 0.0,
is_causal = is_causal,
)
# ββ Merge heads and project βββββββββββββββββββββββββββββββββββββββββββ
out = attn_out.transpose(1, 2).contiguous().view(B, T, -1)
return self.o_proj(out), present_kv
|