File size: 7,787 Bytes
53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 53d8e12 89bd596 | 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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | ---
language:
- en
license: apache-2.0
library_name: pytorch
pipeline_tag: text-generation
tags:
- stacklm
- multi-task
- lora-composition
- query-time-fit
- unlearning
- custom-architecture
- tiny
- research
model-index:
- name: stacklm-tiny
results:
- task:
type: text-generation
name: Multi-task composition
dataset:
name: Synthetic Markov chains
type: synthetic-markov-chains
metrics:
- name: Query-fit vs oracle (ratio)
type: query_oracle_ratio
value: 1.005
- name: Query-fit vs softmax (ratio)
type: query_softmax_ratio
value: 0.915
- name: Anti-stack cancellation
type: cancellation_ratio
value: 0.091
- name: Composition linearity
type: linearity_log_diff
value: 0.023
- name: Per-sample vs joint alpha (ratio)
type: per_sample_joint_ratio
value: 0.928
---
# stacklm-tiny
A tiny transformer (~15K parameters) demonstrating **additive stack composition** for multi-task language modeling.
## Architecture
Frozen base transformer + N additive residual stacks on output logits. No router parameters. Alpha (stack mixing weights) is fit at query time on a small labeled example set.
The base is a 1-layer causal transformer with `d_model=32`, 4 heads, and a 16-token vocabulary. Each stack is a rank-8 low-rank projection from the base's hidden state to the output logit space. Stacks are trained sequentially: stack `i` fits the residual left by `base + stacks[0..i-1]` on task `i`.
At inference, no router is used. The mixing weights `α` are fit directly on a query batch by gradient descent on a cross-entropy objective.
## Validated claims
All numbers below are **mean ± std across 3 seeds** (seed 0, 1, 2). The model card template recommends reporting evaluation results in a structured format . Run `python stacklm_tiny.py --seed {0,1,2}` to reproduce.
| Claim | Mean ± std | Baseline | Interpretation |
|---|---|---|---|
| Query-fit α ≈ oracle | **1.005 ± 0.002** | 20 labeled examples | Query-fit matches oracle within 0.5% |
| Query-fit vs softmax | **0.915 ± 0.009** | Trained router | Query-fit beats softmax by 8.5% |
| Anti-stack cancellation | **0.091 ± 0.029** | log-space ratio | ~91% cancellation |
| Composition linearity | **0.023 ± 0.006** | [1,1] vs [2,0] | 2.3% deviation from exact |
| Per-sample vs joint α | **0.928 ± 0.003** | 7.2% improvement | Per-sample α is consistently better |
### What each claim means
**1. Query-fit ≈ oracle.** Fitting α on 20 labeled examples produces perplexity within 0.5% of fitting α on the full test set. The mixing weights do not need a trained router; they can be solved at query time.
**2. Query-fit vs softmax.** A softmax router (a task classifier trained on 6,000 examples) is 8.5% worse than query-fit. The softmax router learns to predict a task ID from input tokens; query-fit learns the optimal mixing weights directly from labeled examples. The latter is more robust because it doesn't require the input to carry a task-identifying signal.
**3. Anti-stack cancellation.** Training a stack to fit `−stack_0` reduces the composed output's divergence from the base by ~91%. This is partial cancellation, not exact erasure. For "unlearning" in the regulatory sense, this is not sufficient. For soft revocation or A/B testing, it is.
**4. Composition linearity.** `[1,1]` weights on (stack, copy-stack) approximates `[2,0]` weights on (stack, zero) to within 2.3% in log-space. The raw stack logits are exactly linear; the deviation comes from the softmax, which is nonlinear. Composition is approximately linear, not exactly.
**5. Per-sample α.** Fitting a separate α vector for each input sample beats fitting a single α vector for the whole batch by 7.2%, reproducibly across all 3 seeds. This is the strongest single result: the optimal mixing weights genuinely vary per input, not just per task.
## Usage
```python
from stacklm_tiny import StackLM, StackLMConfig, TrainConfig
import torch
# Load the model
model = StackLM.from_pretrained("./stacklm-tiny")
tcfg = TrainConfig()
# Fit alpha on 20 labeled examples
X_adapt, Y_adapt = get_adapt_examples() # shape (20, seq_len-1)
alpha = model.fit_alpha_joint(X_adapt, Y_adapt, model.n_active, tcfg)
# Inference
logits = model(X_test, alpha=alpha)
# Per-sample refinement (better quality, same 20 examples)
alpha_ps = model.fit_alpha_per_sample(X_test, Y_test, model.n_active, tcfg)
logits = model(X_test, alpha=alpha_ps)
```
### Revocation
```python
# Train an anti-stack to cancel stack 0
anti_idx = model.train_anti_stack(task, target_idx=0, tcfg=tcfg)
# Apply both: base + stack0 + anti ≈ base (91% cancellation)
alpha = torch.tensor([1., 1.])
out = model(X, alpha=alpha, n=2)
```
## Training data
Synthetic Markov chains over a 16-token vocabulary. Five chains: one for the base model (task 0) and four for the stacks (tasks 1–4). Chains share 70% of their transition structure and have 30% task-specific structure. Each task has a distinct initial-token bias to give the router a weak input signal.
This is a **demonstration dataset**, not a language modeling benchmark. It is designed to make the composition mechanics observable, not to test language quality.
## Training procedure
- **Base**: 400 steps, AdamW, lr 1e-3, weight decay 0.05, early stopping on validation loss
- **Stacks**: 300 steps each, Adam, lr 3e-3, fit on the residual left by prior stacks
- **α fit**: 80 Adam steps on a length-N parameter, lr 5e-2
- **Per-sample α**: 20 Adam steps on a (B, N) parameter
Hardware: CPU only. Total training time: ~90–106 seconds per seed.
## Evaluation
Evaluated on 300 held-out sequences per task. The primary metric is perplexity (exponentiated cross-entropy on the task's test split). All claims are measured with the same code that produces the numbers. No cherry-picking.
## Limitations
- **Tiny scale.** 15K parameters, 16-token vocabulary, 20-token sequences. Nothing about this model generalizes to real LLMs without re-testing.
- **Synthetic tasks.** Markov chains, not natural language. Composition mechanics may behave differently on real text.
- **No causal masking bug check.** The base uses a standard causal mask; the composition is applied to output logits post-attention.
- **Single architecture.** Only one base shape tested. Different depths or attention patterns may produce different composition behavior.
- **Cancellation is partial.** ~91% is not 100%. Do not rely on this for data erasure.
- **Per-sample α is stochastic.** The 7.2% improvement is consistent across seeds but the mechanism is not understood. It may be an artifact of the specific synthetic setup.
## What this is / is not
**Is:** a proof-of-concept demonstrating that (a) multi-task can be additive rather than routed, (b) mixing weights are optimally fitted at query time, (c) adapters can be partially revoked by adding a cancellation stack, (d) per-sample mixing weights beat batch-level weights.
**Is not:** a useful language model, a benchmark result, or evidence that these claims hold at scale. For real use cases, the same architecture would apply to LoRA stacks on a real base model, and all claims would need re-testing.
## Files
- `pytorch_model.bin` — base + stack weights
- `config.json` — architecture config and `n_active` (number of trained stacks)
- `stacklm_tiny.py` — model code (self-contained)
- `README.md` — this file
## Citation
```bibtex
@misc{stacklm-tiny,
title={stacklm-tiny: Additive Stack Composition for Multi-Task Language Modeling},
author={zeechimp},
year={2026},
howpublished={\url{https://huggingface.co/zeechimp/stacklm-tiny}}
}
```
## Contact
For questions or to report issues, open a discussion on the model repository. |