ffh92r32rm0 commited on
Commit
6a926ef
·
verified ·
1 Parent(s): faf271b

Upload 3 files

Browse files
Files changed (3) hide show
  1. LICENSE.txt +21 -0
  2. README.md +213 -0
  3. text2roi_colab_demo.ipynb +293 -0
LICENSE.txt ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Amphora NeuroText contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language:
4
+ - en
5
+ tags:
6
+ - neuroscience
7
+ - fmri
8
+ - brain-encoding
9
+ - text-embeddings
10
+ - roi-prediction
11
+ - pytorch
12
+ library_name: pytorch
13
+ pipeline_tag: feature-extraction
14
+ ---
15
+
16
+ # Amphora NeuroText — Text to Brain ROI Activations
17
+
18
+ **Hugging Face model:** [`ffh92r32rm0/Amphora_NeuroText`](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText)
19
+
20
+ Lightweight MLP that maps **text** → **56 cortical/subcortical ROI activation scores**.
21
+
22
+ ```
23
+ text → Qwen3-Embedding-4B (2560d) → Text2ROI MLP (3.2M params) → 56 ROI values
24
+ ```
25
+
26
+ This is a fast, text-native brain encoding model. It does **not** require the full V5 joint fMRI encoder or multimodal feature extraction — only Qwen3 text embeddings plus this 13 MB projector.
27
+
28
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText/colab)
29
+
30
+ **Try it now:** [Open the Colab demo](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText/colab) (GPU runtime → type text → click **Predict** → ROI bar chart + fsaverage5 brain maps).
31
+
32
+ Weights (`text2roi_projector.pt`) download automatically from this public HF repo — no token needed.
33
+
34
+ **Model page:** https://huggingface.co/ffh92r32rm0/Amphora_NeuroText
35
+
36
+ ## Model details
37
+
38
+ | | |
39
+ |---|---|
40
+ | **Input** | Any English text string |
41
+ | **Text encoder** | [`Qwen/Qwen3-Embedding-4B`](https://huggingface.co/Qwen/Qwen3-Embedding-4B) (2560d, L2-normalized last token) |
42
+ | **Projector** | 3-layer MLP: 2560 → 1024 → 512 → 56 |
43
+ | **Output** | 56 ROI activation scores (universal schema, same order as NeuroDiffusion V5) |
44
+ | **Parameters** | 3,178,040 (projector only) |
45
+ | **Checkpoint size** | ~13 MB |
46
+ | **Val mean Pearson R** | **0.170** (held-out text–fMRI pairs) |
47
+ | **Training data** | ~300k text–ROI pairs from naturalistic fMRI corpora |
48
+ | **License** | MIT (this repo). Qwen3-Embedding-4B has its own [license](https://huggingface.co/Qwen/Qwen3-Embedding-4B). |
49
+
50
+ ### ROI outputs (56 regions)
51
+
52
+ Visual (`V1`–`EBA`), parietal (`IPS2`–`hIP3`), frontal executive (`dlPFC`–`FP2`), language (`IFG`–`AG`), default mode (`PCC`, `mPFC_dmn`, `LP_L/R`), salience/affect (`AI`, `dACC`, `vmPFC`, hippocampus), subcortical (`Amygdala`, `Caudate`, `Putamen`, `Thalamus`). See `config.json` for full list.
53
+
54
+ ## Intended use
55
+
56
+ - Research prototyping: estimate population-level brain ROI responses to text stimuli
57
+ - Creative tools: text-driven neuroemotion / brain-state visualization pipelines
58
+ - Fast baseline before running the full multimodal V5 encoder
59
+
60
+ ## Limitations
61
+
62
+ - **Not mind reading.** Outputs are model predictions trained on group fMRI, not measurements of any individual person's thoughts or emotions.
63
+ - **Modest accuracy.** Val mean R ≈ 0.17 — useful for relative comparisons across texts, not clinical or diagnostic use.
64
+ - **Text only.** No image, audio, or video input. Multimodal (image/audio/video) encoding is out of scope for this model.
65
+ - **English-biased.** Trained primarily on English naturalistic narratives; other languages are untested.
66
+ - **Depends on Qwen3.** First run downloads ~8 GB of embedding weights from Hugging Face.
67
+
68
+ ## Quick start
69
+
70
+ ### Colab demo (recommended — no install)
71
+
72
+ 1. Open the [**Colab demo**](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText/colab) (or model page → **Use this model** → **Google Colab**)
73
+ 2. Runtime → **Change runtime type** → **GPU** (T4)
74
+ 3. Run all cells, type any sentence, click **Predict brain map**
75
+
76
+ Everything loads from this HF repo (`ffh92r32rm0/Amphora_NeuroText`) — notebook, weights, and helper scripts.
77
+
78
+ **Commercial-friendly brain viz:** The Colab demo uses **MNE + Nilearn** for fsaverage5 / HCP-MMP plotting (`text2roi_to_fsaverage.py`). It does **not** import tribev2 (CC BY-NC). See `requirements-colab.txt`.
79
+
80
+ ### Local install
81
+
82
+ **1. Install**
83
+
84
+ ```bash
85
+ pip install torch numpy transformers huggingface_hub
86
+ # or
87
+ pip install -r requirements.txt
88
+ ```
89
+
90
+ **2. Download this model**
91
+
92
+ ```bash
93
+ huggingface-cli download ffh92r32rm0/Amphora_NeuroText text2roi_projector.pt predict.py config.json
94
+ ```
95
+
96
+ Or in Python:
97
+
98
+ ```python
99
+ from huggingface_hub import hf_hub_download
100
+
101
+ ckpt = hf_hub_download("ffh92r32rm0/Amphora_NeuroText", "text2roi_projector.pt")
102
+ ```
103
+
104
+ **3. Run inference**
105
+
106
+ CLI:
107
+
108
+ ```bash
109
+ python predict.py --text "a dog running through a sunny park" --device cuda
110
+ ```
111
+
112
+ Python API:
113
+
114
+ ```python
115
+ from predict import predict_text
116
+ from huggingface_hub import hf_hub_download
117
+
118
+ ckpt = hf_hub_download("ffh92r32rm0/Amphora_NeuroText", "text2roi_projector.pt")
119
+ result = predict_text("a terrifying monster in a dark alley", checkpoint_path=ckpt, device="cuda")
120
+
121
+ for roi, score in sorted(result["roi_predictions"].items(), key=lambda x: abs(x[1]), reverse=True)[:8]:
122
+ print(f"{roi:16s} {score:+.4f}")
123
+ ```
124
+
125
+ **Example output:**
126
+
127
+ ```
128
+ LO2 +0.4797
129
+ FFA-2 +0.4387
130
+ V3A +0.4014
131
+ mPFC_dmn +0.3215
132
+ V2 +0.3037
133
+ IPS2 +0.2845
134
+ HPC_L -0.2610
135
+ MST +0.2586
136
+ ```
137
+
138
+ **4. Load projector weights manually**
139
+
140
+ ```python
141
+ import torch
142
+ from predict import Text2ROI
143
+
144
+ ckpt = torch.load("text2roi_projector.pt", map_location="cpu", weights_only=False)
145
+ model = Text2ROI(in_dim=ckpt["in_dim"], hidden=ckpt["hidden"], out_dim=ckpt["n_roi"])
146
+ model.load_state_dict(ckpt["state_dict"])
147
+ model.eval()
148
+
149
+ # embed: (1, 2560) float32 from Qwen3-Embedding-4B
150
+ with torch.no_grad():
151
+ rois = model(torch.from_numpy(embed)).numpy() # (1, 56)
152
+ ```
153
+
154
+ ## Training
155
+
156
+ Trained with Pearson-R correlation loss + 0.1× MSE on ~300k (text embedding, ROI target) pairs:
157
+
158
+ ```bash
159
+ python train_text2roi.py \
160
+ --data /path/to/neurotext_pairs.npz \
161
+ --out text2roi_projector.pt \
162
+ --epochs 80 --batch 2048 --lr 3e-4
163
+ ```
164
+
165
+ Train your own projector with Pearson-R loss + 0.1× MSE on `(text embedding, ROI target)` pairs in `.npz` format.
166
+
167
+ ## Evaluation
168
+
169
+ | Metric | Value |
170
+ |--------|-------|
171
+ | Val mean Pearson R (56 ROIs) | 0.170 |
172
+ | Projector params | 3.18M |
173
+ | Training time | ~5 min (RTX 5080) |
174
+
175
+ Reproduce on your val split:
176
+
177
+ ```bash
178
+ python infer_text2roi.py --checkpoint text2roi_projector.pt --data neurotext_pairs.npz
179
+ ```
180
+
181
+ ## Files in this repo
182
+
183
+ | File | Description |
184
+ |------|-------------|
185
+ | `text2roi_projector.pt` | Trained MLP weights + metadata |
186
+ | `notebook.ipynb` | **Interactive Colab demo** (opened via `/colab` on the model page) |
187
+ | `text2roi_colab_demo.ipynb` | Same Colab demo (alternate filename) |
188
+ | `text2roi_to_fsaverage.py` | ROI → fsaverage5 mapping + Nilearn plotting (no tribev2) |
189
+ | `predict.py` | Standalone inference script |
190
+ | `config.json` | Model hyperparameters and eval summary |
191
+ | `requirements.txt` | Local Python dependencies |
192
+ | `requirements-colab.txt` | Colab deps (MNE + Nilearn, no tribev2) |
193
+ | `LICENSE` | MIT |
194
+
195
+ ## Citation
196
+
197
+ ```bibtex
198
+ @misc{amphora_neurotext2026,
199
+ author = {ffh92r32rm0},
200
+ title = {Amphora NeuroText: Text-to-Brain ROI Activation Projector},
201
+ year = {2026},
202
+ publisher = {Hugging Face},
203
+ howpublished = {\url{https://huggingface.co/ffh92r32rm0/Amphora_NeuroText}},
204
+ license = {MIT}
205
+ }
206
+ ```
207
+
208
+ ## Links
209
+
210
+ - **Model:** https://huggingface.co/ffh92r32rm0/Amphora_NeuroText
211
+ - **Colab demo:** https://huggingface.co/ffh92r32rm0/Amphora_NeuroText/colab
212
+ - **Text encoder:** https://huggingface.co/Qwen/Qwen3-Embedding-4B
213
+ - **Brain visualization:** MNE + Nilearn (fsaverage5 / HCP-MMP1, commercial-friendly)
text2roi_colab_demo.ipynb ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Amphora NeuroText — Colab Demo\n",
8
+ "\n",
9
+ "**Type text → predict 56 brain ROI activations → visualize on fsaverage5 cortical maps (MNE + Nilearn).**\n",
10
+ "\n",
11
+ "Open this notebook from the [Hugging Face model page](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText) → **Use this model** → **Google Colab**, or go directly to:\n",
12
+ "\n",
13
+ "**https://huggingface.co/ffh92r32rm0/Amphora_NeuroText/colab**\n",
14
+ "\n",
15
+ "All assets (weights, helper scripts) download from `ffh92r32rm0/Amphora_NeuroText` — no GitHub, no login required.\n",
16
+ "\n",
17
+ "Pipeline:\n",
18
+ "```\n",
19
+ "text → Qwen3-Embedding-4B → Text2ROI MLP (3M params) → 56 ROI scores → HCP-MMP parcels → fsaverage5 surface\n",
20
+ "```\n",
21
+ "\n",
22
+ "Brain plotting uses **MNE + Nilearn only** (BSD/MIT-friendly) — no tribev2 import (CC BY-NC).\n",
23
+ "\n",
24
+ "**Setup:** Runtime → Change runtime type → **GPU** (T4 is enough), then run all cells.\n",
25
+ "\n",
26
+ "Model: [ffh92r32rm0/Amphora_NeuroText](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText) · MIT license\n",
27
+ "\n",
28
+ "> ⚠️ Predictions are **model estimates** from group fMRI training — not measurements of anyone's private thoughts."
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "code",
33
+ "metadata": {},
34
+ "source": [
35
+ "# Install dependencies (first run ~5–8 min)\n",
36
+ "# Commercial-friendly: MNE + Nilearn for brain viz — no tribev2 (CC BY-NC).\n",
37
+ "import sys\n",
38
+ "\n",
39
+ "!{sys.executable} -m pip install -q --upgrade pip\n",
40
+ "!{sys.executable} -m pip install -q \"torch>=2.3\" \"transformers>=4.44\" huggingface_hub ipywidgets\n",
41
+ "!{sys.executable} -m pip install -q nilearn mne nibabel scipy matplotlib numpy\n",
42
+ "\n",
43
+ "print(\"Deps installed (MNE + Nilearn for fsaverage5 brain maps).\")"
44
+ ],
45
+ "execution_count": null,
46
+ "outputs": []
47
+ },
48
+ {
49
+ "cell_type": "code",
50
+ "metadata": {},
51
+ "source": [
52
+ "import json\n",
53
+ "from pathlib import Path\n",
54
+ "\n",
55
+ "import matplotlib.pyplot as plt\n",
56
+ "import numpy as np\n",
57
+ "import torch\n",
58
+ "import torch.nn as nn\n",
59
+ "import torch.nn.functional as F\n",
60
+ "from huggingface_hub import hf_hub_download\n",
61
+ "from IPython.display import display, clear_output\n",
62
+ "import ipywidgets as widgets\n",
63
+ "\n",
64
+ "HF_REPO = \"ffh92r32rm0/Amphora_NeuroText\"\n",
65
+ "\n",
66
+ "DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
67
+ "print(f\"Device: {DEVICE}\")\n",
68
+ "\n",
69
+ "CKPT_PATH = hf_hub_download(HF_REPO, \"text2roi_projector.pt\")\n",
70
+ "print(f\"Checkpoint: {CKPT_PATH}\")"
71
+ ],
72
+ "execution_count": null,
73
+ "outputs": []
74
+ },
75
+ {
76
+ "cell_type": "code",
77
+ "metadata": {},
78
+ "source": [
79
+ "ROI_NAMES_56 = [\n",
80
+ " \"V1\", \"V2\", \"V3\", \"V4\", \"V3A\", \"V3B\", \"LO1\", \"LO2\",\n",
81
+ " \"MT\", \"MST\", \"V7\", \"IPS1\",\n",
82
+ " \"FFA-1\", \"FFA-2\", \"PPA\", \"RSC\", \"OFA\", \"EBA\",\n",
83
+ " \"IPS2\", \"IPS3\", \"IPS4\", \"IPS5\", \"SPL1\", \"hIP1\", \"hIP2\", \"hIP3\",\n",
84
+ " \"dlPFC\", \"vlPFC\", \"OFC\", \"ACC\", \"mPFC\", \"FP1\", \"FP2\",\n",
85
+ " \"IFG\", \"IFGorb\", \"STG\", \"STS\", \"MTG\", \"AG\",\n",
86
+ " \"PCC\", \"mPFC_dmn\", \"LP_L\", \"LP_R\", \"HPC_L\", \"HPC_R\",\n",
87
+ " \"AI\", \"dACC\", \"sgACC\", \"vmPFC\",\n",
88
+ " \"Amygdala_L\", \"Amygdala_R\", \"Caudate_L\", \"Caudate_R\",\n",
89
+ " \"Putamen_L\", \"Putamen_R\", \"Thalamus\",\n",
90
+ "]\n",
91
+ "\n",
92
+ "class Text2ROI(nn.Module):\n",
93
+ " def __init__(self, in_dim=2560, hidden=1024, out_dim=56, dropout=0.1):\n",
94
+ " super().__init__()\n",
95
+ " self.net = nn.Sequential(\n",
96
+ " nn.Linear(in_dim, hidden), nn.GELU(), nn.Dropout(dropout), nn.LayerNorm(hidden),\n",
97
+ " nn.Linear(hidden, hidden // 2), nn.GELU(), nn.Dropout(dropout),\n",
98
+ " nn.Linear(hidden // 2, out_dim),\n",
99
+ " )\n",
100
+ " def forward(self, x):\n",
101
+ " return self.net(x)\n",
102
+ "\n",
103
+ "def load_projector(path):\n",
104
+ " ckpt = torch.load(path, map_location=\"cpu\", weights_only=False)\n",
105
+ " model = Text2ROI(int(ckpt[\"in_dim\"]), int(ckpt[\"hidden\"]), int(ckpt[\"n_roi\"]))\n",
106
+ " model.load_state_dict(ckpt[\"state_dict\"])\n",
107
+ " model.to(DEVICE).eval()\n",
108
+ " names = [str(x) for x in ckpt.get(\"roi_names\", ROI_NAMES_56)]\n",
109
+ " return model, names, ckpt\n",
110
+ "\n",
111
+ "PROJECTOR, ROI_NAMES, CKPT_META = load_projector(CKPT_PATH)\n",
112
+ "print(f\"Loaded Text2ROI v1 — val R={CKPT_META.get('best_val_r', 0):+.3f}, {len(ROI_NAMES)} ROIs\")"
113
+ ],
114
+ "execution_count": null,
115
+ "outputs": []
116
+ },
117
+ {
118
+ "cell_type": "code",
119
+ "metadata": {},
120
+ "source": [
121
+ "QWEN_ID = \"Qwen/Qwen3-Embedding-4B\"\n",
122
+ "from transformers import AutoModel, AutoTokenizer\n",
123
+ "\n",
124
+ "print(\"Loading Qwen3 embedder (first run downloads ~8 GB)...\")\n",
125
+ "_tok = AutoTokenizer.from_pretrained(QWEN_ID, padding_side=\"left\")\n",
126
+ "_qwen = AutoModel.from_pretrained(QWEN_ID, dtype=torch.bfloat16).to(DEVICE).eval()\n",
127
+ "print(\"Qwen3 ready.\")\n",
128
+ "\n",
129
+ "@torch.no_grad()\n",
130
+ "def embed_text(text: str) -> np.ndarray:\n",
131
+ " tok = _tok([text], return_tensors=\"pt\", padding=True, truncation=True, max_length=512).to(DEVICE)\n",
132
+ " out = _qwen(**tok)\n",
133
+ " emb = out.last_hidden_state[:, -1].float()\n",
134
+ " emb = F.normalize(emb, p=2, dim=1).cpu().numpy().astype(np.float32)\n",
135
+ " return emb\n",
136
+ "\n",
137
+ "@torch.no_grad()\n",
138
+ "def predict_rois(text: str) -> dict:\n",
139
+ " x = torch.from_numpy(embed_text(text)).to(DEVICE)\n",
140
+ " pred = PROJECTOR(x).cpu().numpy().reshape(-1)\n",
141
+ " return {name: float(pred[i]) for i, name in enumerate(ROI_NAMES)}"
142
+ ],
143
+ "execution_count": null,
144
+ "outputs": []
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "metadata": {},
149
+ "source": [
150
+ "# Map 56 ROI values → fsaverage5 vertices (MNE + Nilearn — no tribev2)\n",
151
+ "import sys\n",
152
+ "from pathlib import Path\n",
153
+ "\n",
154
+ "_helper = Path(hf_hub_download(HF_REPO, \"text2roi_to_fsaverage.py\"))\n",
155
+ "sys.path.insert(0, str(_helper.parent))\n",
156
+ "from text2roi_to_fsaverage import roi_dict_to_fsaverage5, plot_fsaverage5_brain\n",
157
+ "\n",
158
+ "print(\"fsaverage5 plotting helpers ready (MNE + Nilearn).\")"
159
+ ],
160
+ "execution_count": null,
161
+ "outputs": []
162
+ },
163
+ {
164
+ "cell_type": "code",
165
+ "metadata": {},
166
+ "source": [
167
+ "def plot_results(text: str, roi_values: dict):\n",
168
+ " vertex_map, skipped = roi_dict_to_fsaverage5(roi_values)\n",
169
+ "\n",
170
+ " # --- ROI bar chart ---\n",
171
+ " top = sorted(roi_values.items(), key=lambda kv: abs(kv[1]), reverse=True)[:16]\n",
172
+ " names = [t[0] for t in top]\n",
173
+ " vals = [t[1] for t in top]\n",
174
+ " colors = [\"#c44e52\" if v < 0 else \"#4c72b0\" for v in vals]\n",
175
+ "\n",
176
+ " fig, ax = plt.subplots(figsize=(7, 5))\n",
177
+ " ax.barh(names[::-1], vals[::-1], color=colors[::-1])\n",
178
+ " ax.axvline(0, color=\"#333\", lw=0.8)\n",
179
+ " ax.set_title(\"Top ROI predictions\")\n",
180
+ " ax.set_xlabel(\"Predicted activation\")\n",
181
+ " plt.tight_layout()\n",
182
+ " plt.show()\n",
183
+ "\n",
184
+ " # --- fsaverage5 brain maps (Nilearn) ---\n",
185
+ " skip_note = f\" — subcortical skipped: {len(skipped)}\" if skipped else \"\"\n",
186
+ " plot_fsaverage5_brain(\n",
187
+ " vertex_map,\n",
188
+ " views=[\"left\", \"right\", \"dorsal\"],\n",
189
+ " cmap=\"RdBu_r\",\n",
190
+ " threshold=0.02,\n",
191
+ " title=f\"fsaverage5 cortical map (HCP-MMP ROIs){skip_note}\",\n",
192
+ " )\n",
193
+ " plt.show()\n",
194
+ "\n",
195
+ " print(\"\\nTop ROIs:\")\n",
196
+ " for n, v in top[:10]:\n",
197
+ " print(f\" {n:<16} {v:+.4f}\")\n",
198
+ " if skipped:\n",
199
+ " print(f\"\\n(Subcortical / unmapped ROIs not painted on cortex: {', '.join(skipped[:8])}{'…' if len(skipped)>8 else ''})\")"
200
+ ],
201
+ "execution_count": null,
202
+ "outputs": []
203
+ },
204
+ {
205
+ "cell_type": "markdown",
206
+ "metadata": {},
207
+ "source": [
208
+ "## Try it — enter text and click **Predict**\n",
209
+ "\n",
210
+ "Or use a preset example below."
211
+ ]
212
+ },
213
+ {
214
+ "cell_type": "code",
215
+ "metadata": {},
216
+ "source": [
217
+ "text_in = widgets.Textarea(\n",
218
+ " value=\"a dog running through a sunny park\",\n",
219
+ " description=\"Text:\",\n",
220
+ " layout=widgets.Layout(width=\"90%\", height=\"80px\"),\n",
221
+ ")\n",
222
+ "btn = widgets.Button(description=\"Predict brain map\", button_style=\"primary\", icon=\"play\")\n",
223
+ "out = widgets.Output()\n",
224
+ "\n",
225
+ "PRESETS = {\n",
226
+ " \"Sunny park\": \"a dog running through a sunny park\",\n",
227
+ " \"Scary scene\": \"a terrifying monster jumps out in a dark alley\",\n",
228
+ " \"Romantic\": \"two people sharing a quiet candlelit dinner\",\n",
229
+ " \"Math puzzle\": \"solving a difficult calculus proof step by step\",\n",
230
+ "}\n",
231
+ "preset_btns = [widgets.Button(description=k, layout=widgets.Layout(width=\"140px\")) for k in PRESETS]\n",
232
+ "\n",
233
+ "def _on_preset(btn):\n",
234
+ " text_in.value = PRESETS[btn.description]\n",
235
+ "\n",
236
+ "for b in preset_btns:\n",
237
+ " b.on_click(_on_preset)\n",
238
+ "\n",
239
+ "def _on_predict(_):\n",
240
+ " with out:\n",
241
+ " clear_output(wait=True)\n",
242
+ " text = text_in.value.strip()\n",
243
+ " if not text:\n",
244
+ " print(\"Enter some text first.\")\n",
245
+ " return\n",
246
+ " print(f\"Predicting for: {text!r} …\")\n",
247
+ " rois = predict_rois(text)\n",
248
+ " plot_results(text, rois)\n",
249
+ "\n",
250
+ "btn.on_click(_on_predict)\n",
251
+ "\n",
252
+ "display(widgets.VBox([\n",
253
+ " text_in,\n",
254
+ " widgets.HBox([btn] + preset_btns),\n",
255
+ " out,\n",
256
+ "]))"
257
+ ],
258
+ "execution_count": null,
259
+ "outputs": []
260
+ },
261
+ {
262
+ "cell_type": "markdown",
263
+ "metadata": {},
264
+ "source": [
265
+ "## What the output means\n",
266
+ "\n",
267
+ "| Output | Description |\n",
268
+ "|--------|-------------|\n",
269
+ "| **Bar chart** | Top 16 of 56 ROI activation scores (positive = predicted up-regulation) |\n",
270
+ "| **Brain surface** | ROI values painted onto **fsaverage5** via HCP-MMP1 parcels (MNE + Nilearn) |\n",
271
+ "| **Skipped ROIs** | Subcortical regions (amygdala, striatum, thalamus) are not on the cortical surface |\n",
272
+ "\n",
273
+ "**Model:** [ffh92r32rm0/Amphora_NeuroText](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText)"
274
+ ]
275
+ }
276
+ ],
277
+ "metadata": {
278
+ "colab": {
279
+ "provenance": [],
280
+ "gpuType": "T4"
281
+ },
282
+ "kernelspec": {
283
+ "display_name": "Python 3",
284
+ "name": "python3"
285
+ },
286
+ "language_info": {
287
+ "name": "python"
288
+ },
289
+ "accelerator": "GPU"
290
+ },
291
+ "nbformat": 4,
292
+ "nbformat_minor": 5
293
+ }