Instructions to use ryoji-info/Gemma-4-12B-PsiLM with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use ryoji-info/Gemma-4-12B-PsiLM with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir Gemma-4-12B-PsiLM ryoji-info/Gemma-4-12B-PsiLM
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
MANIFEST β Hugging Face repo ryoji-info/Gemma-4-12B-PsiLM
Everything in this directory (release/gemma-4-12b-psilm/) is uploaded as-is to the
model repo; nothing outside it is needed. The backbone (mlx-community/gemma-4-12B-it-4bit)
is not uploaded β the script downloads it at first run.
Files to upload (and where each one came from)
| path in the HF repo | source in the GitHub checkout | size | sha256 |
|---|---|---|---|
README.md |
written for this release (the HF model card, YAML front matter) | 17 KB | β |
psilm_infer.py |
written for this release | 42 KB | β |
requirements.txt |
written for this release | 1 KB | β |
MANIFEST.md |
this file (harmless to upload; drop it if you prefer) | β | β |
psilm-banner.png |
assets/psilm-banner.png (1600 px wide) |
1.35 MB | 4cd65f32fe4aab5b49b66681a841b0128628e8d94c75494ae84f941b49c48089 |
bridges/gemma-4-12b-4bit-mlx-1d-value-selective/bridges.safetensors |
results/hf_export/bridges/gemma-4-12b-4bit-mlx-1d-value-selective/bridges.safetensors (= results/stage2_gemma12b/bridges.npz, step 7000, learned-pointer tensors dropped) |
102,068,660 B | f6ef8946c41b3cfa17df7c22bcab2c5cffbd856c2dd608970a364cc14d5e8f7d |
bridges/gemma-4-12b-4bit-mlx-1d-value-selective/config.json |
results/hf_export/bridges/gemma-4-12b-4bit-mlx-1d-value-selective/config.json |
1,287 B | 8a5add382beb65a0214f5e8b0b640e5d5df6f19e9a6caf1945400d2fe1e6bba5 |
physics/fno_burgers_singlemode.safetensors |
results/hf_export/physics/fno_burgers_singlemode.safetensors (= results/stage2/fno.pt; loaders verified identical, max weight and field difference 0.0) |
552,076 B | 7bb0076c85cdcf2505a9079c05964e3eb77ac4a776eccf34216953f3c37bfcdd |
The copies were made with cp on 2026-09-06 and the hashes match the sources
(shasum -a 256). Not uploaded: __pycache__/, .DS_Store.
To add later (the two runs in progress)
psilm_infer.py has the --task {1d,multimode,2d} switch (2026-09-06; the 1D path is
unchanged: on the 0.5B the previous script and this one print the same numbers and text,
--question-only byte-for-byte, full runs differing only in the timings). When the Gemma
multi-mode and 2D runs finish, export them and add:
| path in the HF repo | source in the GitHub checkout | size | sha256 |
|---|---|---|---|
bridges/gemma-4-12b-4bit-mlx-multimode/bridges.safetensors |
the stage-2b Gemma checkpoint results/stage2b_gemma12b_2b/bridges.npz (see the export recipe below) |
β | β |
bridges/gemma-4-12b-4bit-mlx-multimode/config.json |
written from results/stage2b_gemma12b_2b/bridges.npz.meta in the schema below |
β | β |
physics/fno_burgers_multimode.safetensors |
results/hf_export/physics/fno_burgers_multimode.safetensors (= results/stage2b/fno.pt; loads with load_fno_safetensors, verified against the torch FNO1d to 4e-7 in the smoke below) |
552,076 B | 8cebd7a82d0f5da13ae1cfb74848d74d43b98b98cd09767655f6c4ac069f879b |
bridges/gemma-4-12b-4bit-mlx-2d-dpot/bridges.safetensors |
the stage-2d Gemma checkpoint results/stage2d_gemma12b_2d/bridges.npz (tag as in eval/mlx_stage2d_train.py's docstring) |
β | β |
bridges/gemma-4-12b-4bit-mlx-2d-dpot/config.json |
written from its bridges.npz.meta in the schema below |
β | β |
physics/dpot_tiny_fisher2d_finetuned.safetensors |
results/hf_export/physics/dpot_tiny_fisher2d_finetuned.safetensors (= results/stage2d/dpot_ft.pt, bare DPOT-Tiny state-dict keys; verified identical to the .pt in the smoke below) |
30,144,524 B | 88472c199fed489c05ac5ceaf9113c607dd28d95e45385f62e52fac6494b15d8 |
physics/model_Ti.pth |
results/stage2d/model_Ti.pth -- the upstream DPOT-Tiny base checkpoint (hzk17/DPOT, Apache-2.0). Ship it, or rely on the download: psilm_infer.py --task 2d looks for it at --dpot-base (default physics/model_Ti.pth) and, when absent, downloads model_Ti.pth from the Hugging Face repo hzk17/DPOT (the repo psilm/physics/dpot_wrapper.py names; the file is listed there, download verified 2026-09-06) into the HF cache. DPOTPhysics loads the base first and the fine-tuned safetensors then replaces every one of its 67 tensors (strict=True), so the base only satisfies the wrapper's constructor. |
90,475,962 B | 074c337f9b3a3c70253f8022ce6be7e7dfb809a91a7b00e46fbfedf9611d767f |
Then fill the two in progress rows of README.md ("Bridges in this repository") from their
final_eval.json, and add einops>=0.8 to requirements.txt (the vendored DPOT definition
imports it; only the 2D task needs it).
The 2D task needs a clone. psilm/physics/dpot_wrapper.py imports dpot_model from
<repo>/vendor/, which the pip package ([tool.setuptools.packages.find] include = ["psilm*"])
does not ship. psilm_infer.py adds $PSILM_REPO/vendor to sys.path when PSILM_REPO
points at a clone (even with the package installed) and exits with a message naming this
otherwise; the README's usage section says so. Packaging vendor/dpot_model.py inside psilm
would lift the requirement.
config.json schema (multimode and 2d)
psilm_infer.py requires every key below for --task multimode / --task 2d and exits naming
the missing one (e.g. config.json: missing key(s) ['coupling.l_rev', 'physics']). The 1D
directory keeps its existing, more lenient config (defaults inferred from the tensors). task
is also what the script auto-detects when --bridges is given without --task (falling back to
the directory name: multimode, 2d/dpot).
{
"task": "multimode", // "multimode" | "2d" (required)
"backbone": "mlx-community/gemma-4-12B-it-4bit", // informational
"hf_tokenizer": "mlx-community/gemma-4-12B-it-4bit", // used for the chat template (else --backbone)
"bridges_class": "psilm.mlx.multimode.make_bridges_multi (PsiBridgesMLX, n_params=6)",
// 2d: "psilm.mlx.bridges2d.PsiBridges2DMLX"
"construct": { // required, all five keys; passed verbatim to the
"d_model": 3840, // constructor the trainer used:
"channel": "value", // make_bridges_multi(**construct) (eval/mlx_stage2b_train.py)
"inj_cap": 0.2, // PsiBridges2DMLX(**construct) (eval/mlx_stage2d_train.py)
"gate_bias": 0.0, // = meta["args"]{channel, inj_cap, gate_bias, readout_norm}
"readout_norm": "dim"
},
"coupling": {"l_fwd": 20, "l_rev": 30, "n_layers": 48}, // required; meta["l_fwd"], meta["l_rev"]; n_layers is checked
"physics": { // required; "file" is relative to the repo root and is the
"file": "physics/fno_burgers_multimode.safetensors", // default for --physics
"dpot_base": "physics/model_Ti.pth" // 2d only, informational (the CLI flag --dpot-base decides)
},
"training": {"...": "free-form record, as in the 1D config"},
"license": "apache-2.0"
}
(JSON has no comments; the file itself carries none.) Values must match how the checkpoint was
trained: the script constructs the bridges from construct, then checks every tensor shape in
bridges.safetensors against the module and refuses on a mismatch or an unknown tensor; missing
tensors are allowed (strict=False) and reported as unused (the multimode export may drop the
retired learned pointer fwd.x0_query, fwd.x0_key.*, as the 1D export did; the 2D bridges
have no such tensors). fwd.dim_mu / fwd.dim_sigma (the readout_norm: "dim" calibration)
are ordinary tensors of the checkpoint and must be included.
Export recipe (maintainer, from the checkout root)
import json, mlx.core as mx
from pathlib import Path
task, src, dst = "multimode", Path("results/stage2b_gemma12b_2b"), Path("release/gemma-4-12b-psilm/bridges/gemma-4-12b-4bit-mlx-multimode")
# task, src, dst = "2d", Path("results/stage2d_gemma12b_2d"), Path("release/gemma-4-12b-psilm/bridges/gemma-4-12b-4bit-mlx-2d-dpot")
meta = json.loads((src / "bridges.npz.meta").read_text()); a = meta["args"]
w = {k: v for k, v in mx.load(str(src / "bridges.npz")).items()
if not k.startswith(("fwd.x0_query", "fwd.x0_key."))} # unused learned pointer (multimode only)
dst.mkdir(parents=True, exist_ok=True)
mx.save_safetensors(str(dst / "bridges.safetensors"), w)
cfg = {"task": task, "backbone": meta["model"], "hf_tokenizer": a["hf_tokenizer"],
"bridges_class": {"multimode": "psilm.mlx.multimode.make_bridges_multi (PsiBridgesMLX, n_params=6)",
"2d": "psilm.mlx.bridges2d.PsiBridges2DMLX"}[task],
"construct": {"d_model": 3840, "channel": a["channel"], "inj_cap": a["inj_cap"],
"gate_bias": a["gate_bias"], "readout_norm": a["readout_norm"]},
"coupling": {"l_fwd": meta["l_fwd"], "l_rev": meta["l_rev"], "n_layers": 48},
"physics": {"multimode": {"file": "physics/fno_burgers_multimode.safetensors"},
"2d": {"file": "physics/dpot_tiny_fisher2d_finetuned.safetensors", "dpot_base": "physics/model_Ti.pth"}}[task],
"training": {"step": meta["step"], "args": a}, "license": "apache-2.0"}
(dst / "config.json").write_text(json.dumps(cfg, indent=1))
Then python psilm_infer.py --task multimode / --task 2d from release/gemma-4-12b-psilm
must print the three sections with a PsiLM match verdict on the defaults before upload.
Smoke record (2026-09-06, mechanics only)
Run with randomly initialised bridges of the right shapes for mlx-community/Qwen2.5-0.5B-Instruct-4bit
(d_model 896, 24 layers, coupling 10/15), built with the trainers' own constructors
(make_bridges_multi(896, gate_bias=0.0, inj_cap=0.2, channel="value", readout_norm="dim"),
PsiBridges2DMLX(d_model=896, ...) with the same arguments), saved as bridges.safetensors +
config.json in the schema above, with the physics files from results/hf_export/physics/:
--task multimode(auto-detected from the directory name in one run), single-mode default and the two-mode combination, with and without the baseline arm: three sections printed; the[3] physics model (FNO)value agreed with an independent torch computation (psilm.stage2.bridges.build_ic_multi+psilm.physics.fno.FNO1dloaded fromresults/stage2b/fno.pt+fourier_interp) to 5e-8 (single) and 4e-7 (combo).--task 2don MPS with--dpot-base results/stage2d/model_Ti.pth, and on CPU with the base absent (downloaded fromhzk17/DPOT): three sections printed;[3] physics model (DPOT)agreed with the torch stage-2d path (DPOTPhysicsfrommodel_Ti.pth+results/stage2d/dpot_ft.pt,psilm.stage2d.bridges2d.build_ic_2d,features_and_field,fisher2d.bilinear_periodic, CPU) to 7e-7 (MPS) and 0.0 (CPU).- Error paths: a config missing
coupling.l_revandphysicsexits naming both keys;--task 2don a multimode directory exits on thetaskmismatch; malformed--modesexits. - The coupled answers were garbage, as expected from random bridges (the backbone's own reply
template, no
equals), which the script reports as "reply left the trained template".
Upload (maintainer runs this)
From the GitHub checkout root, with HF_TOKEN set (or huggingface-cli login done):
cd /Users/rxiii/Documents/GitHub/PsiLM
HF_HUB_DISABLE_XET=1 .venv/bin/python - <<'EOF'
from huggingface_hub import HfApi
api = HfApi()
repo = "ryoji-info/Gemma-4-12B-PsiLM"
api.create_repo(repo, repo_type="model", private=True, exist_ok=True)
api.upload_folder(
folder_path="release/gemma-4-12b-psilm",
repo_id=repo,
repo_type="model",
commit_message="Gemma-4-12B-PsiLM: bridges, Burgers FNO, one-command CLI, model card",
ignore_patterns=["__pycache__/*", "*.pyc", ".DS_Store"],
)
print("UPLOAD DONE")
EOF
HF_HUB_DISABLE_XET=1 keeps the upload on the classic LFS path (the Xet backend has
stalled on this machine's earlier uploads). Make the repo public afterwards with
api.update_repo_settings(repo, private=False) or from the repo's settings page, together
with ryoji-info/PsiLM-bridges and ryoji-info/PsiLM-physics, which the card links to.
After upload: the one-command check
huggingface-cli download ryoji-info/Gemma-4-12B-PsiLM --local-dir /tmp/g4psilm && cd /tmp/g4psilm
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python psilm_infer.py
Note for the pip install line: the psilm @ git+... requirement needs the GitHub
pyproject.toml to use package discovery ([tool.setuptools.packages.find] include = ["psilm*"],
changed on 2026-09-06 in the working tree from packages = ["psilm"], which shipped only the
top-level package without psilm.mlx, psilm.stage2, psilm.physics). That change must be
pushed before the requirement installs a usable package; until then the script says so, and the
PSILM_REPO=/path/to/clone fallback works regardless.