Text Generation
English
"""
Standalone inference script for AxionLab-official/RizzAura-100k (RizzLLaMA arch).
No trust_remote_code. Requires: torch, huggingface_hub, tokenizers
"""

import json
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from huggingface_hub import hf_hub_download
from tokenizers import Tokenizer

REPO_ID = "AxionLab-official/RizzAura-100k"


# ---------------- model ----------------

class RMSNorm(nn.Module):
    def __init__(self, dim, eps=1e-6):
        super().__init__()
        self.weight = nn.Parameter(torch.ones(dim))
        self.eps = eps

    def forward(self, x):
        x = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
        return x * self.weight


def rope_freqs(head_dim, max_len, base=10000.0, device="cpu"):
    inv_freq = 1.0 / (base ** (torch.arange(0, head_dim, 2, device=device).float() / head_dim))
    t = torch.arange(max_len, device=device).float()
    freqs = torch.outer(t, inv_freq)
    return torch.cos(freqs), torch.sin(freqs)


def apply_rope(x, cos, sin):
    # x: (B, H, T, D)
    x1, x2 = x[..., 0::2], x[..., 1::2]
    cos = cos[None, None, :x.shape[2], :]
    sin = sin[None, None, :x.shape[2], :]
    rx1 = x1 * cos - x2 * sin
    rx2 = x1 * sin + x2 * cos
    out = torch.stack([rx1, rx2], dim=-1).flatten(-2)
    return out


class Attention(nn.Module):
    def __init__(self, dim, n_heads):
        super().__init__()
        self.n_heads = n_heads
        self.head_dim = dim // n_heads
        self.qkv = nn.Linear(dim, 3 * dim, bias=False)
        self.proj = nn.Linear(dim, dim, bias=False)

    def forward(self, x, cos, sin, mask):
        B, T, C = x.shape
        qkv = self.qkv(x)
        q, k, v = qkv.split(C, dim=-1)
        q = q.view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
        k = k.view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
        v = v.view(B, T, self.n_heads, self.head_dim).transpose(1, 2)

        q = apply_rope(q, cos, sin)
        k = apply_rope(k, cos, sin)

        att = (q @ k.transpose(-2, -1)) / math.sqrt(self.head_dim)
        att = att.masked_fill(mask[:, :, :T, :T] == 0, float("-inf"))
        att = F.softmax(att, dim=-1)
        out = att @ v
        out = out.transpose(1, 2).contiguous().view(B, T, C)
        return self.proj(out)


class FFN(nn.Module):
    def __init__(self, dim, hidden_mult):
        super().__init__()
        hidden = int(dim * hidden_mult)
        self.w1 = nn.Linear(dim, hidden, bias=False)
        self.w3 = nn.Linear(dim, hidden, bias=False)
        self.w2 = nn.Linear(hidden, dim, bias=False)

    def forward(self, x):
        return self.w2(F.silu(self.w1(x)) * self.w3(x))


class Block(nn.Module):
    def __init__(self, dim, n_heads, hidden_mult):
        super().__init__()
        self.attn_norm = RMSNorm(dim)
        self.attn = Attention(dim, n_heads)
        self.ffn_norm = RMSNorm(dim)
        self.ffn = FFN(dim, hidden_mult)

    def forward(self, x, cos, sin, mask):
        x = x + self.attn(self.attn_norm(x), cos, sin, mask)
        x = x + self.ffn(self.ffn_norm(x))
        return x


class RizzLLaMA(nn.Module):
    def __init__(self, vocab_size, dim, n_layers, n_heads, hidden_mult, max_len):
        super().__init__()
        self.max_len = max_len
        self.tok_emb = nn.Embedding(vocab_size, dim)
        self.blocks = nn.ModuleList(
            [Block(dim, n_heads, hidden_mult) for _ in range(n_layers)]
        )
        self.norm = RMSNorm(dim)
        self.head = nn.Linear(dim, vocab_size, bias=False)

        head_dim = dim // n_heads
        cos, sin = rope_freqs(head_dim, max_len)
        self.register_buffer("cos", cos, persistent=False)
        self.register_buffer("sin", sin, persistent=False)
        self.register_buffer(
            "mask", torch.tril(torch.ones(max_len, max_len)).view(1, 1, max_len, max_len),
            persistent=False,
        )

    def forward(self, idx):
        x = self.tok_emb(idx)
        for blk in self.blocks:
            x = blk(x, self.cos, self.sin, self.mask)
        x = self.norm(x)
        return self.head(x)


# ---------------- load ----------------

def load_model(device="cpu"):
    model_path = hf_hub_download(REPO_ID, "model.pt")
    ckpt = torch.load(model_path, map_location="cpu", weights_only=False)
    cfg = ckpt["config"]

    model = RizzLLaMA(
        vocab_size=ckpt["vocab_size"],
        dim=cfg["dim"],
        n_layers=cfg["n_layers"],
        n_heads=cfg["n_heads"],
        hidden_mult=cfg["hidden_mult"],
        max_len=ckpt["max_len"],
    )
    model.load_state_dict(ckpt["model_state"])
    model.to(device).eval()
    return model, ckpt


def load_tokenizer():
    tok_path = hf_hub_download(REPO_ID, "tokenizer.json")
    return Tokenizer.from_file(tok_path)


# ---------------- generation ----------------

@torch.no_grad()
def generate(model, tokenizer, prompt, max_new_tokens=64, temperature=0.8, top_p=0.9, device="cpu"):
    bos = tokenizer.token_to_id("<|bos|>")
    eos = tokenizer.token_to_id("<|eos|>")
    user_tok = tokenizer.token_to_id("<|user|>")
    assistant_tok = tokenizer.token_to_id("<|assistant|>")

    ids = [bos, user_tok] + tokenizer.encode(prompt).ids + [assistant_tok]
    idx = torch.tensor([ids], dtype=torch.long, device=device)

    for _ in range(max_new_tokens):
        idx_cond = idx[:, -model.max_len:]
        logits = model(idx_cond)[:, -1, :]
        logits = logits / max(temperature, 1e-5)

        probs = F.softmax(logits, dim=-1)
        sorted_probs, sorted_idx = torch.sort(probs, descending=True)
        cum_probs = torch.cumsum(sorted_probs, dim=-1)
        cutoff = cum_probs > top_p
        cutoff[..., 1:] = cutoff[..., :-1].clone()
        cutoff[..., 0] = False
        sorted_probs[cutoff] = 0.0
        sorted_probs = sorted_probs / sorted_probs.sum(dim=-1, keepdim=True)

        next_sorted = torch.multinomial(sorted_probs, num_samples=1)
        next_id = sorted_idx.gather(-1, next_sorted)

        idx = torch.cat([idx, next_id], dim=1)
        if next_id.item() == eos or idx.shape[1] >= model.max_len:
            break

    out_ids = idx[0].tolist()
    gen_ids = out_ids[out_ids.index(assistant_tok) + 1:]
    if eos in gen_ids:
        gen_ids = gen_ids[: gen_ids.index(eos)]
    return tokenizer.decode(gen_ids)


if __name__ == "__main__":
    device = "cuda" if torch.cuda.is_available() else "cpu"
    model, ckpt = load_model(device)
    tokenizer = load_tokenizer()

    print(f"RizzAura-100k carregado ({sum(p.numel() for p in model.parameters())} params) em {device}")

    while True:
        prompt = input("\nuser> ")
        if not prompt.strip():
            break
        reply = generate(model, tokenizer, prompt, device=device)
        print(f"assistant> {reply}")
Downloads last month
193
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Dataset used to train AxionLab-official/RizzAura-100k