Text Generation
Transformers
Safetensors
English
jugnu_vr
tiny-lm
qwen3
value-residual
resformer
muon
ablation
custom_code
Instructions to use altslate/JugnuLM-110M-R2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use altslate/JugnuLM-110M-R2 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="altslate/JugnuLM-110M-R2", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("altslate/JugnuLM-110M-R2", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use altslate/JugnuLM-110M-R2 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "altslate/JugnuLM-110M-R2" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "altslate/JugnuLM-110M-R2", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/altslate/JugnuLM-110M-R2
- SGLang
How to use altslate/JugnuLM-110M-R2 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "altslate/JugnuLM-110M-R2" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "altslate/JugnuLM-110M-R2", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "altslate/JugnuLM-110M-R2" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "altslate/JugnuLM-110M-R2", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use altslate/JugnuLM-110M-R2 with Docker Model Runner:
docker model run hf.co/altslate/JugnuLM-110M-R2
JugnuLM-110M-R2: value residuals + Muon (ablation rung R2)
Browse files- README.md +88 -0
- config.json +62 -0
- generation_config.json +10 -0
- model.safetensors +3 -0
- modeling_jugnu_vr.py +54 -0
- tokenizer.json +0 -0
- tokenizer_config.json +34 -0
README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
library_name: transformers
|
| 6 |
+
pipeline_tag: text-generation
|
| 7 |
+
tags:
|
| 8 |
+
- tiny-lm
|
| 9 |
+
- qwen3
|
| 10 |
+
- value-residual
|
| 11 |
+
- resformer
|
| 12 |
+
- muon
|
| 13 |
+
- ablation
|
| 14 |
+
datasets:
|
| 15 |
+
- HuggingFaceFW/fineweb-edu
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
# JugnuLM-110M-R2 (value residuals + Muon)
|
| 19 |
+
|
| 20 |
+
**What "R2" means.** This is **rung 2 of the JugnuLM phase-2 ablation ladder.** We take
|
| 21 |
+
rung **R1** — [JugnuLM-110M-R1](https://huggingface.co/altslate/JugnuLM-110M-R1) (value
|
| 22 |
+
residuals) — and add **one** change: we swap the optimizer to **Muon** for the 2D hidden
|
| 23 |
+
matrices, holding *everything else fixed* (same value-residual architecture, data, tokens,
|
| 24 |
+
schedule shape, batch, seed). The ladder keeps a lever only if it beats the previous rung.
|
| 25 |
+
**R2 does, so it's kept.**
|
| 26 |
+
|
| 27 |
+
## What changed: the Muon optimizer
|
| 28 |
+
|
| 29 |
+
R0 and R1 trained with AdamW on every parameter. R2 uses **Muon** — Newton-Schulz
|
| 30 |
+
**orthogonalized momentum** updates — on the 2D hidden weight matrices (attention + MLP,
|
| 31 |
+
81.4M params), and **keeps AdamW** for the rest (tied embedding/head, RMSNorm gains, and
|
| 32 |
+
the 22 value-residual `vr_lambda` scalars, 28.3M params). Muon's advantage is known to be
|
| 33 |
+
**largest at exactly this scale** (sub-150M) and to shrink as models grow.
|
| 34 |
+
|
| 35 |
+
Both optimizers ride one shared cosine LR multiplier: Muon peak `2e-2`, AdamW peak `1.5e-3`,
|
| 36 |
+
each annealed to 10% of peak.
|
| 37 |
+
|
| 38 |
+
## Result vs the R1 and R0 rungs
|
| 39 |
+
|
| 40 |
+
| 110M rung | BLiMP ↑ | ARC-Easy ↑ | WikiText-2 byte-ppl ↓ |
|
| 41 |
+
|---|---|---|---|
|
| 42 |
+
| R0 — baseline | 81.25 | 52.48 | 1.95 |
|
| 43 |
+
| R1 — + value residuals | 81.10 | 54.67 | 1.940 |
|
| 44 |
+
| **R2 — + Muon** | 80.78 | **56.10** | **1.932** |
|
| 45 |
+
|
| 46 |
+
**Muon lifts ARC-Easy by +1.43 over R1 (54.67 → 56.10) and lowers perplexity, at a small
|
| 47 |
+
BLiMP dip (−0.32, ~2× SE).** Across the two ladder rungs ARC-Easy has climbed **+3.6**
|
| 48 |
+
(52.48 → 56.10) while BLiMP stayed ~flat — steadily closing the reasoning gap to the
|
| 49 |
+
125–143M leaderboard models. Evaluated with EleutherAI `lm-evaluation-harness`.
|
| 50 |
+
|
| 51 |
+
**Training-efficiency note.** Muon's convergence lead was largest early — val-perplexity
|
| 52 |
+
was **−26% vs R1 at step 1000** — and compressed to ~−1% by the end of the fixed 8.4B-token
|
| 53 |
+
budget (the classic "Muon wins the sprint, converges toward AdamW" pattern). Notably, the
|
| 54 |
+
**downstream ARC gain persisted** even as the final perplexity gap narrowed.
|
| 55 |
+
|
| 56 |
+
## ⚠️ Loading — requires `trust_remote_code`
|
| 57 |
+
|
| 58 |
+
Value residuals are a **custom attention pathway**, so this model must be loaded with the
|
| 59 |
+
included modeling file. Loading it as a stock Qwen3 **silently drops the residual** and
|
| 60 |
+
understates quality.
|
| 61 |
+
|
| 62 |
+
```python
|
| 63 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 64 |
+
tok = AutoTokenizer.from_pretrained("altslate/JugnuLM-110M-R2")
|
| 65 |
+
model = AutoModelForCausalLM.from_pretrained("altslate/JugnuLM-110M-R2", trust_remote_code=True)
|
| 66 |
+
ids = tok("The theory of relativity was developed by", return_tensors="pt").input_ids
|
| 67 |
+
print(tok.decode(model.generate(ids, max_new_tokens=30, repetition_penalty=1.3)[0], skip_special_tokens=True))
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
## Architecture & training
|
| 71 |
+
|
| 72 |
+
Identical architecture to R1: Qwen3-arch + value-residual pathway, **23 layers × 576**,
|
| 73 |
+
GQA 9/3, RoPE, SwiGLU, RMSNorm, QK-Norm, tied embeddings, SmolLM2 tokenizer (49,152),
|
| 74 |
+
z-loss 1e-4. Trained from scratch on ~8.4B tokens of FineWeb-Edu (sample-10BT), shared
|
| 75 |
+
cosine schedule (Muon 2e-2, AdamW 1.5e-3, → 10% floor), ~0.5M-token global batch, bf16,
|
| 76 |
+
DDP on 4× RTX PRO 4500 Blackwell. Only the optimizer differs from R1.
|
| 77 |
+
|
| 78 |
+
## Intended use & limitations
|
| 79 |
+
|
| 80 |
+
Research **base** model (not instruction-tuned). Fluent English continuation and
|
| 81 |
+
reasonable recall for its size; limited multi-step reasoning, occasional repetition,
|
| 82 |
+
English-only. Not for production.
|
| 83 |
+
|
| 84 |
+
## Links
|
| 85 |
+
|
| 86 |
+
- Previous rung: [altslate/JugnuLM-110M-R1](https://huggingface.co/altslate/JugnuLM-110M-R1)
|
| 87 |
+
- Baseline: [altslate/JugnuLM-110M](https://huggingface.co/altslate/JugnuLM-110M)
|
| 88 |
+
- Training code & ablation ladder: https://github.com/AltSlate-Labs/jugnu
|
config.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"JugnuVRForCausalLM"
|
| 4 |
+
],
|
| 5 |
+
"attention_bias": false,
|
| 6 |
+
"attention_dropout": 0.0,
|
| 7 |
+
"auto_map": {
|
| 8 |
+
"AutoConfig": "modeling_jugnu_vr.JugnuVRConfig",
|
| 9 |
+
"AutoModelForCausalLM": "modeling_jugnu_vr.JugnuVRForCausalLM"
|
| 10 |
+
},
|
| 11 |
+
"bos_token_id": 0,
|
| 12 |
+
"dtype": "bfloat16",
|
| 13 |
+
"eos_token_id": 0,
|
| 14 |
+
"head_dim": 64,
|
| 15 |
+
"hidden_act": "silu",
|
| 16 |
+
"hidden_size": 576,
|
| 17 |
+
"initializer_range": 0.02,
|
| 18 |
+
"intermediate_size": 1536,
|
| 19 |
+
"layer_types": [
|
| 20 |
+
"full_attention",
|
| 21 |
+
"full_attention",
|
| 22 |
+
"full_attention",
|
| 23 |
+
"full_attention",
|
| 24 |
+
"full_attention",
|
| 25 |
+
"full_attention",
|
| 26 |
+
"full_attention",
|
| 27 |
+
"full_attention",
|
| 28 |
+
"full_attention",
|
| 29 |
+
"full_attention",
|
| 30 |
+
"full_attention",
|
| 31 |
+
"full_attention",
|
| 32 |
+
"full_attention",
|
| 33 |
+
"full_attention",
|
| 34 |
+
"full_attention",
|
| 35 |
+
"full_attention",
|
| 36 |
+
"full_attention",
|
| 37 |
+
"full_attention",
|
| 38 |
+
"full_attention",
|
| 39 |
+
"full_attention",
|
| 40 |
+
"full_attention",
|
| 41 |
+
"full_attention",
|
| 42 |
+
"full_attention"
|
| 43 |
+
],
|
| 44 |
+
"max_position_embeddings": 2048,
|
| 45 |
+
"max_window_layers": 28,
|
| 46 |
+
"model_type": "jugnu_vr",
|
| 47 |
+
"num_attention_heads": 9,
|
| 48 |
+
"num_hidden_layers": 23,
|
| 49 |
+
"num_key_value_heads": 3,
|
| 50 |
+
"pad_token_id": 0,
|
| 51 |
+
"rms_norm_eps": 1e-06,
|
| 52 |
+
"rope_parameters": {
|
| 53 |
+
"rope_theta": 10000.0,
|
| 54 |
+
"rope_type": "default"
|
| 55 |
+
},
|
| 56 |
+
"sliding_window": null,
|
| 57 |
+
"tie_word_embeddings": true,
|
| 58 |
+
"transformers_version": "5.2.0",
|
| 59 |
+
"use_cache": true,
|
| 60 |
+
"use_sliding_window": false,
|
| 61 |
+
"vocab_size": 49152
|
| 62 |
+
}
|
generation_config.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"bos_token_id": 0,
|
| 4 |
+
"eos_token_id": 0,
|
| 5 |
+
"output_attentions": false,
|
| 6 |
+
"output_hidden_states": false,
|
| 7 |
+
"pad_token_id": 0,
|
| 8 |
+
"transformers_version": "5.2.0",
|
| 9 |
+
"use_cache": true
|
| 10 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ba6f6d2cf935d4bcba4f50c12e0a1af027c2be8bf737dd6a870c8eca8b0c66ac
|
| 3 |
+
size 219505412
|
modeling_jugnu_vr.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""JugnuLM-110M-R1 — Qwen3 decoder + value residuals (ResFormer).
|
| 2 |
+
|
| 3 |
+
Each layer's value projection gains a learned-gated residual from the FIRST layer's
|
| 4 |
+
value: v_i = v_proj_i(x) + lambda_i * v_0 (v_0 = layer-0 value; lambda_i learned).
|
| 5 |
+
Implemented by replacing each layer's v_proj with a residual Linear that shares a
|
| 6 |
+
per-forward context; layer 0 writes v_0, later layers add lambda_i * v_0.
|
| 7 |
+
|
| 8 |
+
Loadable via: AutoModelForCausalLM.from_pretrained("altslate/JugnuLM-110M-R1", trust_remote_code=True)
|
| 9 |
+
(Loading as a stock Qwen3 silently drops the residual pathway.)
|
| 10 |
+
"""
|
| 11 |
+
import torch
|
| 12 |
+
import torch.nn as nn
|
| 13 |
+
from transformers import Qwen3Config, Qwen3ForCausalLM
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class JugnuVRConfig(Qwen3Config):
|
| 17 |
+
model_type = "jugnu_vr"
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class _VResidualLinear(nn.Linear):
|
| 21 |
+
def __init__(self, in_features, out_features, is_first, bias=False):
|
| 22 |
+
super().__init__(in_features, out_features, bias=bias)
|
| 23 |
+
self._vr_is_first = is_first
|
| 24 |
+
self._vr_ctx = None
|
| 25 |
+
if not is_first:
|
| 26 |
+
self.vr_lambda = nn.Parameter(torch.zeros(1))
|
| 27 |
+
|
| 28 |
+
def forward(self, x):
|
| 29 |
+
v = super().forward(x)
|
| 30 |
+
ctx = self._vr_ctx
|
| 31 |
+
if ctx is None:
|
| 32 |
+
return v
|
| 33 |
+
if self._vr_is_first:
|
| 34 |
+
ctx["v0"] = v
|
| 35 |
+
else:
|
| 36 |
+
v0 = ctx.get("v0")
|
| 37 |
+
if v0 is not None:
|
| 38 |
+
v = v + self.vr_lambda * v0
|
| 39 |
+
return v
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class JugnuVRForCausalLM(Qwen3ForCausalLM):
|
| 43 |
+
config_class = JugnuVRConfig
|
| 44 |
+
|
| 45 |
+
def __init__(self, config):
|
| 46 |
+
super().__init__(config)
|
| 47 |
+
ctx = {}
|
| 48 |
+
for i, layer in enumerate(self.model.layers):
|
| 49 |
+
old = layer.self_attn.v_proj
|
| 50 |
+
new = _VResidualLinear(old.in_features, old.out_features,
|
| 51 |
+
is_first=(i == 0), bias=(old.bias is not None))
|
| 52 |
+
new._vr_ctx = ctx
|
| 53 |
+
layer.self_attn.v_proj = new
|
| 54 |
+
self.post_init()
|
tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"backend": "tokenizers",
|
| 4 |
+
"bos_token": "<|endoftext|>",
|
| 5 |
+
"clean_up_tokenization_spaces": false,
|
| 6 |
+
"eos_token": "<|endoftext|>",
|
| 7 |
+
"errors": "replace",
|
| 8 |
+
"extra_special_tokens": [
|
| 9 |
+
"<|endoftext|>",
|
| 10 |
+
"<|im_start|>",
|
| 11 |
+
"<|im_end|>",
|
| 12 |
+
"<repo_name>",
|
| 13 |
+
"<reponame>",
|
| 14 |
+
"<file_sep>",
|
| 15 |
+
"<filename>",
|
| 16 |
+
"<gh_stars>",
|
| 17 |
+
"<issue_start>",
|
| 18 |
+
"<issue_comment>",
|
| 19 |
+
"<issue_closed>",
|
| 20 |
+
"<jupyter_start>",
|
| 21 |
+
"<jupyter_text>",
|
| 22 |
+
"<jupyter_code>",
|
| 23 |
+
"<jupyter_output>",
|
| 24 |
+
"<jupyter_script>",
|
| 25 |
+
"<empty_output>"
|
| 26 |
+
],
|
| 27 |
+
"is_local": true,
|
| 28 |
+
"local_files_only": false,
|
| 29 |
+
"model_max_length": 8192,
|
| 30 |
+
"pad_token": "<|endoftext|>",
|
| 31 |
+
"tokenizer_class": "TokenizersBackend",
|
| 32 |
+
"unk_token": "<|endoftext|>",
|
| 33 |
+
"vocab_size": 49152
|
| 34 |
+
}
|