Text Generation
PEFT
Safetensors
PyTorch
English
causal-lm
lora
qwen
sft
dpo
seal
self-adaptation
hitl
Instructions to use aaronr43210/MiniSEAL with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use aaronr43210/MiniSEAL with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Download src/model/llm.py from aaronr43210/MiniSEAL: direct link, hf CLI and curl.
- Browser
- Download file 5 kB
-
https://huggingface.co/aaronr43210/MiniSEAL/resolve/main/src/model/llm.py
- Command line
-
hf download hf://aaronr43210/MiniSEAL/src/model/llm.py
-
curl -L -o llm.py https://huggingface.co/aaronr43210/MiniSEAL/resolve/main/src/model/llm.py
5 kB
| from typing import Optional | |
| """ | |
| Decoder-only Transformer language model. | |
| Training objective: | |
| Next-token prediction. | |
| Input: | |
| input_ids: [batch, seq] | |
| Output: | |
| logits: [batch, seq, vocab] | |
| loss: optional cross-entropy loss if targets are given. | |
| """ | |
| import math | |
| from dataclasses import asdict | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from src.model.config import ModelConfig | |
| from src.model.layers import RMSNorm, TransformerBlock | |
| class DecoderOnlyTransformer(nn.Module): | |
| """ | |
| GPT/LLaMA-style decoder-only language model. | |
| """ | |
| def __init__(self, config: ModelConfig): | |
| super().__init__() | |
| self.config = config | |
| self.tok_embeddings = nn.Embedding(config.vocab_size, config.n_embd) | |
| self.dropout = nn.Dropout(config.dropout) | |
| self.blocks = nn.ModuleList( | |
| [TransformerBlock(config) for _ in range(config.n_layer)] | |
| ) | |
| self.norm = RMSNorm(config.n_embd, config.norm_eps) | |
| self.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False) | |
| self.apply(self._init_weights) | |
| # Weight tying: common in GPT models. | |
| self.lm_head.weight = self.tok_embeddings.weight | |
| # GPT-style scaled residual initialization. | |
| for name, param in self.named_parameters(): | |
| if name.endswith("out_proj.weight") or name.endswith("down_proj.weight"): | |
| nn.init.normal_( | |
| param, | |
| mean=0.0, | |
| std=0.02 / math.sqrt(2 * config.n_layer), | |
| ) | |
| def _init_weights(self, module: nn.Module) -> None: | |
| """ | |
| Initializes model weights. | |
| """ | |
| if isinstance(module, nn.Linear): | |
| nn.init.normal_(module.weight, mean=0.0, std=0.02) | |
| if module.bias is not None: | |
| nn.init.zeros_(module.bias) | |
| elif isinstance(module, nn.Embedding): | |
| nn.init.normal_(module.weight, mean=0.0, std=0.02) | |
| def forward( | |
| self, | |
| input_ids: torch.Tensor, | |
| targets: Optional[torch.Tensor] = None, | |
| ): | |
| """ | |
| Input: | |
| input_ids: [batch, seq] | |
| targets: [batch, seq], optional | |
| Output: | |
| logits: [batch, seq, vocab] | |
| loss: scalar tensor if targets are provided. | |
| """ | |
| batch, seq_len = input_ids.shape | |
| if seq_len > self.config.block_size: | |
| raise ValueError( | |
| f"Sequence length {seq_len} exceeds block_size {self.config.block_size}" | |
| ) | |
| x = self.tok_embeddings(input_ids) | |
| x = self.dropout(x) | |
| for block in self.blocks: | |
| x = block(x) | |
| x = self.norm(x) | |
| logits = self.lm_head(x) | |
| loss = None | |
| if targets is not None: | |
| loss = F.cross_entropy( | |
| logits.reshape(-1, logits.size(-1)), | |
| targets.reshape(-1), | |
| ) | |
| return logits, loss | |
| def generate( | |
| self, | |
| input_ids: torch.Tensor, | |
| max_new_tokens: int, | |
| temperature: float = 1.0, | |
| top_k: Optional[int] = None, | |
| eos_token_id: Optional[int] = None, | |
| ) -> torch.Tensor: | |
| """ | |
| Input: | |
| input_ids: [batch, seq] | |
| max_new_tokens: number of tokens to generate. | |
| temperature: sampling temperature. | |
| top_k: keep only top-k logits if provided. | |
| eos_token_id: stop generation if this token is produced. | |
| Output: | |
| Generated token IDs: [batch, seq + max_new_tokens] | |
| """ | |
| self.eval() | |
| # Track which sequences in the batch have already emitted EOS so we can | |
| # stop early only once *every* sequence is finished (single-example | |
| # callers get the same behavior with batch size 1). | |
| batch = input_ids.size(0) | |
| finished = torch.zeros(batch, dtype=torch.bool, device=input_ids.device) | |
| for _ in range(max_new_tokens): | |
| context = input_ids[:, -self.config.block_size:] | |
| logits, _ = self(context) | |
| logits = logits[:, -1, :] / temperature | |
| if top_k is not None: | |
| values, _ = torch.topk(logits, min(top_k, logits.size(-1))) | |
| logits[logits < values[:, [-1]]] = -float("inf") | |
| probs = F.softmax(logits, dim=-1) | |
| next_token = torch.multinomial(probs, num_samples=1) | |
| input_ids = torch.cat([input_ids, next_token], dim=1) | |
| if eos_token_id is not None: | |
| finished = finished | (next_token.squeeze(-1) == eos_token_id) | |
| if bool(finished.all()): | |
| break | |
| return input_ids | |
| def get_num_params(self) -> int: | |
| """ | |
| Output: | |
| Number of trainable model parameters. | |
| """ | |
| return sum(p.numel() for p in self.parameters() if p.requires_grad) | |
| def config_dict(self) -> dict: | |
| return asdict(self.config) | |