Text Generation
Transformers
Safetensors
PyTorch
English
fineweb_decoder
causal-lm
custom-code
educational
custom_code
fineweb-12m-sft / modeling_fineweb.py
PeterRabbit's picture
Publish model weights, tokenizer, code, and model card
9505dc3 verified
Raw
History Blame Contribute Delete
5.65 kB
"""Decoder-only Transformer used by the educational FineWeb model family."""
import torch
import torch.nn as nn
import torch.nn.functional as F
import transformers
from transformers import PreTrainedModel
from transformers.generation import GenerationMixin
from transformers.modeling_outputs import CausalLMOutput
from .configuration_fineweb import FineWebConfig
class RMSNorm(nn.Module):
def __init__(self, width, eps=1e-6):
super().__init__()
self.weight = nn.Parameter(torch.ones(width))
self.eps = eps
def forward(self, x):
scale = torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps)
return x * scale * self.weight
def apply_rope(x, cos, sin):
even = x[..., 0::2]
odd = x[..., 1::2]
rotated = torch.stack((even * cos - odd * sin, even * sin + odd * cos), dim=-1)
return rotated.flatten(start_dim=-2)
class CausalSelfAttention(nn.Module):
def __init__(self, width, heads, context_length):
super().__init__()
if width % heads:
raise ValueError("d_model must be divisible by n_heads")
self.heads = heads
self.head_dim = width // heads
self.context_length = context_length
self.qkv = nn.Linear(width, 3 * width, bias=False)
self.output = nn.Linear(width, width, bias=False)
def forward(self, x):
batch, tokens, width = x.shape
if tokens > self.context_length:
raise ValueError("Input exceeds configured context length")
qkv = self.qkv(x).view(batch, tokens, 3, self.heads, self.head_dim)
query, key, value = qkv.unbind(dim=2)
query = query.transpose(1, 2)
key = key.transpose(1, 2)
value = value.transpose(1, 2)
inv_frequency = 1.0 / (
10000
** (
torch.arange(0, self.head_dim, 2, device=x.device).float()
/ self.head_dim
)
)
frequencies = torch.outer(
torch.arange(tokens, device=x.device, dtype=torch.float), inv_frequency
)
cos = frequencies.cos().to(dtype=query.dtype)[None, None, :, :]
sin = frequencies.sin().to(dtype=query.dtype)[None, None, :, :]
query = apply_rope(query, cos, sin)
key = apply_rope(key, cos, sin)
attended = F.scaled_dot_product_attention(query, key, value, is_causal=True)
attended = attended.transpose(1, 2).contiguous().view(batch, tokens, width)
return self.output(attended)
class SwiGLU(nn.Module):
def __init__(self, width, hidden):
super().__init__()
self.gate_and_up = nn.Linear(width, 2 * hidden, bias=False)
self.down = nn.Linear(hidden, width, bias=False)
def forward(self, x):
gate, up = self.gate_and_up(x).chunk(2, dim=-1)
return self.down(F.silu(gate) * up)
class TransformerBlock(nn.Module):
def __init__(self, config):
super().__init__()
self.attention_norm = RMSNorm(config.d_model, config.rms_norm_eps)
self.attention = CausalSelfAttention(
config.d_model, config.n_heads, config.context_length
)
self.mlp_norm = RMSNorm(config.d_model, config.rms_norm_eps)
self.mlp = SwiGLU(config.d_model, config.mlp_hidden)
def forward(self, x):
x = x + self.attention(self.attention_norm(x))
return x + self.mlp(self.mlp_norm(x))
class FineWebForCausalLM(PreTrainedModel, GenerationMixin):
model_type = "fineweb_decoder"
config_class = FineWebConfig
base_model_prefix = "fineweb"
main_input_name = "input_ids"
_tied_weights_keys = (
{"lm_head.weight": "embedding.weight"}
if int(transformers.__version__.split(".", 1)[0]) >= 5
else ["lm_head.weight"]
)
def __init__(self, config):
super().__init__(config)
self.embedding = nn.Embedding(config.vocab_size, config.d_model)
self.blocks = nn.ModuleList(
[TransformerBlock(config) for _ in range(config.n_layers)]
)
self.final_norm = RMSNorm(config.d_model, config.rms_norm_eps)
self.lm_head = nn.Linear(config.d_model, config.vocab_size, bias=False)
self.post_init()
def _init_weights(self, module):
if isinstance(module, (nn.Linear, nn.Embedding)):
nn.init.normal_(module.weight, mean=0.0, std=0.02)
def get_input_embeddings(self):
return self.embedding
def set_input_embeddings(self, value):
self.embedding = value
def get_output_embeddings(self):
return self.lm_head
def set_output_embeddings(self, value):
self.lm_head = value
def forward(self, input_ids=None, labels=None, return_dict=True, **kwargs):
if input_ids is None:
raise ValueError("input_ids is required")
input_ids = input_ids[:, -self.config.context_length :]
x = self.embedding(input_ids)
for block in self.blocks:
x = block(x)
logits = self.lm_head(self.final_norm(x))
loss = None
if labels is not None:
labels = labels[:, -input_ids.size(1) :]
loss = F.cross_entropy(
logits[:, :-1].contiguous().view(-1, self.config.vocab_size),
labels[:, 1:].contiguous().view(-1),
ignore_index=-100,
)
if not return_dict:
return (loss, logits) if loss is not None else (logits,)
return CausalLMOutput(loss=loss, logits=logits)
def prepare_inputs_for_generation(self, input_ids, **kwargs):
return {"input_ids": input_ids[:, -self.config.context_length :], "use_cache": False}