Instructions to use RomanCohort/RNAQwen with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use RomanCohort/RNAQwen with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("RomanCohort/RNAQwen", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download scripts/43_fsq_v4_decoder.py from RomanCohort/RNAQwen: direct link, hf CLI and curl.
- Browser
- Download file 6.09 kB
-
https://huggingface.co/RomanCohort/RNAQwen/resolve/main/scripts/43_fsq_v4_decoder.py
- Command line
-
hf download hf://RomanCohort/RNAQwen/scripts/43_fsq_v4_decoder.py
-
curl -L -o 43_fsq_v4_decoder.py https://huggingface.co/RomanCohort/RNAQwen/resolve/main/scripts/43_fsq_v4_decoder.py
6.09 kB
| """路线 C 的定方向实验:修公式 + 换解码器。 | |
| 两个改动: | |
| ① 修 FSQ 公式(v3 的 l=2 恒等输出零,是 bug 不是发现) | |
| v3: q = round(tanh(z) * (l-1)/2) / ((l-1)/2) -> l=2 时 tanh(z)*0.5 ∈(-0.5,0.5),round 恒 0 | |
| v4: k = round((tanh(z)+1)/2 * (l-1)) -> k ∈ {0..l-1},正好 l 档 | |
| q = k/(l-1)*2 - 1 -> 落在 [-1,1] | |
| ② 解码器 Linear -> MLP | |
| 假设:"err 0.64 是解码器太弱,不是词表不够大" | |
| 若换 MLP 后 err 大降 -> 瓶颈是解码器(好消息,词表可以小) | |
| 若几乎不动 -> 真的是词表容量不足,路线要重估 | |
| 判据(决定路线成不成): | |
| err —— 能不能留住信息(< 1 才比"输出均值"好) | |
| 词内方差 —— 同一个码对应的输入有多像(越低 = 码字越有意义) | |
| 最大码占比 —— 塌缩检测(RiboSphere: 有选择性的稀疏是好的,塌是坏的) | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import math | |
| import sys | |
| import time | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT / "src")) | |
| import rnaqwen # noqa: F401,E402 | |
| import torch # noqa: E402 | |
| import torch.nn as nn # noqa: E402 | |
| import torch.nn.functional as F # noqa: E402 | |
| from rnaqwen.models.encoder import RnaEncoder # noqa: E402 | |
| DEV = "cuda" if torch.cuda.is_available() else "cpu" | |
| N_SEQ, STEPS = 64, 2000 | |
| DATA = ROOT / "data/processed/rnaqa_n6_merged.jsonl" | |
| CONFIGS = [ | |
| (4096, 6, 4), (4096, 4, 8), | |
| (65536, 8, 4), (65536, 4, 16), | |
| ] | |
| def fsq(z, levels): | |
| """v4 公式:正好 levels 档,l=2 时是 {0,1},不退化。""" | |
| k = torch.round((torch.tanh(z) + 1) / 2 * (levels - 1)) | |
| q = k / (levels - 1) * 2 - 1 | |
| q = q + ((torch.tanh(z) + 1) / 2 * (levels - 1) - k).detach() * 0 # 纯 STE | |
| q = q + (((torch.tanh(z) + 1) / 2 * (levels - 1)) - ((torch.tanh(z) + 1) / 2 * (levels - 1)).detach()) | |
| return q, k.long() | |
| class AE(nn.Module): | |
| def __init__(self, dim, latent, levels, dec="linear"): | |
| super().__init__() | |
| self.enc = nn.Linear(dim, latent) | |
| self.levels = levels | |
| if dec == "linear": | |
| self.dec = nn.Linear(latent, dim) | |
| else: | |
| self.dec = nn.Sequential( | |
| nn.Linear(latent, 128), nn.GELU(), | |
| nn.Linear(128, 256), nn.GELU(), | |
| nn.Linear(256, dim)) | |
| def forward(self, x): | |
| q, k = fsq(self.enc(x), self.levels) | |
| return self.dec(q), k | |
| def main() -> int: | |
| recs = [] | |
| with open(DATA, encoding="utf-8") as f: | |
| for line in f: | |
| if line.strip(): | |
| recs.append(json.loads(line)) | |
| recs.sort(key=lambda r: len(r.get("sequence") or "")) | |
| pick = [recs[int(i * (len(recs) - 1) / (N_SEQ - 1))] for i in range(N_SEQ)] | |
| seqs = [r["sequence"] for r in pick if r.get("sequence")] | |
| enc = RnaEncoder(str(ROOT / "models/ernierna"), dtype=torch.float32).to(DEV).eval() | |
| with torch.no_grad(): | |
| o = enc(seqs) | |
| x = o.hidden.float().to(DEV)[o.mask.to(DEV).squeeze(-1) > 0] | |
| N, D = x.shape | |
| var_tot = float(x.var(dim=0).sum()) | |
| print(f"[v4] {len(seqs)} 条序列,位置 {N},维度 {D}") | |
| res = [] | |
| for vocab, latent, levels in CONFIGS: | |
| assert levels ** latent == vocab | |
| for dec in ("linear", "mlp"): | |
| torch.manual_seed(0) | |
| ae = AE(D, latent, levels, dec).to(DEV) | |
| opt = torch.optim.AdamW(ae.parameters(), lr=3e-3) | |
| t0 = time.time() | |
| for _ in range(STEPS): | |
| p = torch.randperm(N, device=DEV)[:512] | |
| xb = x[p] | |
| rec, _ = ae(xb) | |
| loss = F.mse_loss(rec, xb) * D | |
| opt.zero_grad(); loss.backward(); opt.step() | |
| ae.eval() | |
| with torch.no_grad(): | |
| rec, k = ae(x) | |
| err = float(((rec - x) ** 2).sum(1).mean() / var_tot) | |
| code = torch.zeros(N, dtype=torch.long, device=DEV) | |
| for d_ in range(latent): | |
| code = code * levels + k[:, d_] | |
| uniq, inv, cnt = torch.unique(code, return_inverse=True, return_counts=True) | |
| sums = torch.zeros(uniq.numel(), D, device=DEV) | |
| sums.index_add_(0, inv, x) | |
| means = sums / cnt.unsqueeze(1) | |
| within = float(((x - means[inv]) ** 2).sum(1).mean() / var_tot) | |
| p_ = cnt.float() / N | |
| ent = float(-(p_ * (p_ + 1e-12).log()).sum()) / math.log(vocab) | |
| top1 = float(cnt.max()) / N | |
| res.append({"vocab": vocab, "latent": latent, "levels": levels, "dec": dec, | |
| "err": err, "codes_used": int(uniq.numel()), | |
| "util": float(uniq.numel()) / vocab, "within_var": within, | |
| "entropy_norm": ent, "top1_share": top1, "sec": round(time.time()-t0)}) | |
| print(f" vocab {vocab:>6} latent={latent:>2} l={levels:>2} dec={dec:<6} " | |
| f"err {err:.4f} 码字 {int(uniq.numel()):>5} ({100*uniq.numel()/vocab:>5.1f}%) " | |
| f"词内方差 {within:.4f} 归一熵 {ent:.3f} 最大码 {100*top1:.2f}% {time.time()-t0:.0f}s") | |
| out = ROOT / "reports/fsq_v4_decoder.json" | |
| out.parent.mkdir(parents=True, exist_ok=True) | |
| out.write_text(json.dumps(res, indent=2, ensure_ascii=False), encoding="utf-8") | |
| print(f"\n[v4] -> {out}") | |
| print() | |
| print(" === 解码器是不是瓶颈 ===") | |
| for vocab, latent, levels in CONFIGS: | |
| a = next(r for r in res if r["vocab"] == vocab and r["dec"] == "linear") | |
| b = next(r for r in res if r["vocab"] == vocab and r["dec"] == "mlp") | |
| drop = 1 - b["err"] / max(a["err"], 1e-9) | |
| print(f" vocab {vocab:>6} latent={latent} l={levels}: " | |
| f"linear {a['err']:.4f} -> mlp {b['err']:.4f} ({100*drop:+.1f}%)") | |
| print() | |
| print(" === l=2 是否还退化(修公式的验证)===") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |