ffh92r32rm0 commited on
Commit
faf271b
·
verified ·
1 Parent(s): 17ab360

Delete text2roi_colab_demo.ipynb

Browse files
Files changed (1) hide show
  1. text2roi_colab_demo.ipynb +0 -301
text2roi_colab_demo.ipynb DELETED
@@ -1,301 +0,0 @@
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 via the **GitHub Colab link** on the model card (recommended).\n",
12
- "\n",
13
- "Weights download from the public HF repo `ffh92r32rm0/Amphora_NeuroText` — no login required.\n",
14
- "\n",
15
- "Pipeline:\n",
16
- "```\n",
17
- "text → Qwen3-Embedding-4B → Text2ROI MLP (3M params) → 56 ROI scores → HCP-MMP parcels → fsaverage5 surface\n",
18
- "```\n",
19
- "\n",
20
- "Brain plotting uses **MNE + Nilearn only** (BSD/MIT-friendly) — no tribev2 import (CC BY-NC).\n",
21
- "\n",
22
- "**Setup:** Runtime → Change runtime type → **GPU** (T4 is enough), then run all cells.\n",
23
- "\n",
24
- "Model: [ffh92r32rm0/Amphora_NeuroText](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText) · MIT license\n",
25
- "\n",
26
- "> ⚠️ Predictions are **model estimates** from group fMRI training — not measurements of anyone's private thoughts."
27
- ]
28
- },
29
- {
30
- "cell_type": "code",
31
- "metadata": {},
32
- "source": [
33
- "# Install dependencies (first run ~5–8 min)\n",
34
- "# Commercial-friendly: MNE + Nilearn for brain viz — no tribev2 (CC BY-NC).\n",
35
- "import sys\n",
36
- "\n",
37
- "!{sys.executable} -m pip install -q --upgrade pip\n",
38
- "!{sys.executable} -m pip install -q \"torch>=2.3\" \"transformers>=4.44\" huggingface_hub ipywidgets\n",
39
- "!{sys.executable} -m pip install -q nilearn mne nibabel scipy matplotlib numpy\n",
40
- "\n",
41
- "print(\"Deps installed (MNE + Nilearn for fsaverage5 brain maps).\")"
42
- ],
43
- "execution_count": null,
44
- "outputs": []
45
- },
46
- {
47
- "cell_type": "code",
48
- "metadata": {},
49
- "source": [
50
- "import json\n",
51
- "from pathlib import Path\n",
52
- "\n",
53
- "import matplotlib.pyplot as plt\n",
54
- "import numpy as np\n",
55
- "import torch\n",
56
- "import torch.nn as nn\n",
57
- "import torch.nn.functional as F\n",
58
- "from huggingface_hub import hf_hub_download\n",
59
- "from IPython.display import display, clear_output\n",
60
- "import ipywidgets as widgets\n",
61
- "\n",
62
- "HF_REPO = \"ffh92r32rm0/Amphora_NeuroText\"\n",
63
- "\n",
64
- "DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
65
- "print(f\"Device: {DEVICE}\")\n",
66
- "\n",
67
- "CKPT_PATH = hf_hub_download(HF_REPO, \"text2roi_projector.pt\")\n",
68
- "print(f\"Checkpoint: {CKPT_PATH}\")"
69
- ],
70
- "execution_count": null,
71
- "outputs": []
72
- },
73
- {
74
- "cell_type": "code",
75
- "metadata": {},
76
- "source": [
77
- "ROI_NAMES_56 = [\n",
78
- " \"V1\", \"V2\", \"V3\", \"V4\", \"V3A\", \"V3B\", \"LO1\", \"LO2\",\n",
79
- " \"MT\", \"MST\", \"V7\", \"IPS1\",\n",
80
- " \"FFA-1\", \"FFA-2\", \"PPA\", \"RSC\", \"OFA\", \"EBA\",\n",
81
- " \"IPS2\", \"IPS3\", \"IPS4\", \"IPS5\", \"SPL1\", \"hIP1\", \"hIP2\", \"hIP3\",\n",
82
- " \"dlPFC\", \"vlPFC\", \"OFC\", \"ACC\", \"mPFC\", \"FP1\", \"FP2\",\n",
83
- " \"IFG\", \"IFGorb\", \"STG\", \"STS\", \"MTG\", \"AG\",\n",
84
- " \"PCC\", \"mPFC_dmn\", \"LP_L\", \"LP_R\", \"HPC_L\", \"HPC_R\",\n",
85
- " \"AI\", \"dACC\", \"sgACC\", \"vmPFC\",\n",
86
- " \"Amygdala_L\", \"Amygdala_R\", \"Caudate_L\", \"Caudate_R\",\n",
87
- " \"Putamen_L\", \"Putamen_R\", \"Thalamus\",\n",
88
- "]\n",
89
- "\n",
90
- "class Text2ROI(nn.Module):\n",
91
- " def __init__(self, in_dim=2560, hidden=1024, out_dim=56, dropout=0.1):\n",
92
- " super().__init__()\n",
93
- " self.net = nn.Sequential(\n",
94
- " nn.Linear(in_dim, hidden), nn.GELU(), nn.Dropout(dropout), nn.LayerNorm(hidden),\n",
95
- " nn.Linear(hidden, hidden // 2), nn.GELU(), nn.Dropout(dropout),\n",
96
- " nn.Linear(hidden // 2, out_dim),\n",
97
- " )\n",
98
- " def forward(self, x):\n",
99
- " return self.net(x)\n",
100
- "\n",
101
- "def load_projector(path):\n",
102
- " ckpt = torch.load(path, map_location=\"cpu\", weights_only=False)\n",
103
- " model = Text2ROI(int(ckpt[\"in_dim\"]), int(ckpt[\"hidden\"]), int(ckpt[\"n_roi\"]))\n",
104
- " model.load_state_dict(ckpt[\"state_dict\"])\n",
105
- " model.to(DEVICE).eval()\n",
106
- " names = [str(x) for x in ckpt.get(\"roi_names\", ROI_NAMES_56)]\n",
107
- " return model, names, ckpt\n",
108
- "\n",
109
- "PROJECTOR, ROI_NAMES, CKPT_META = load_projector(CKPT_PATH)\n",
110
- "print(f\"Loaded Text2ROI v1 — val R={CKPT_META.get('best_val_r', 0):+.3f}, {len(ROI_NAMES)} ROIs\")"
111
- ],
112
- "execution_count": null,
113
- "outputs": []
114
- },
115
- {
116
- "cell_type": "code",
117
- "metadata": {},
118
- "source": [
119
- "QWEN_ID = \"Qwen/Qwen3-Embedding-4B\"\n",
120
- "from transformers import AutoModel, AutoTokenizer\n",
121
- "\n",
122
- "print(\"Loading Qwen3 embedder (first run downloads ~8 GB)...\")\n",
123
- "_tok = AutoTokenizer.from_pretrained(QWEN_ID, padding_side=\"left\")\n",
124
- "_qwen = AutoModel.from_pretrained(QWEN_ID, dtype=torch.bfloat16).to(DEVICE).eval()\n",
125
- "print(\"Qwen3 ready.\")\n",
126
- "\n",
127
- "@torch.no_grad()\n",
128
- "def embed_text(text: str) -> np.ndarray:\n",
129
- " tok = _tok([text], return_tensors=\"pt\", padding=True, truncation=True, max_length=512).to(DEVICE)\n",
130
- " out = _qwen(**tok)\n",
131
- " emb = out.last_hidden_state[:, -1].float()\n",
132
- " emb = F.normalize(emb, p=2, dim=1).cpu().numpy().astype(np.float32)\n",
133
- " return emb\n",
134
- "\n",
135
- "@torch.no_grad()\n",
136
- "def predict_rois(text: str) -> dict:\n",
137
- " x = torch.from_numpy(embed_text(text)).to(DEVICE)\n",
138
- " pred = PROJECTOR(x).cpu().numpy().reshape(-1)\n",
139
- " return {name: float(pred[i]) for i, name in enumerate(ROI_NAMES)}"
140
- ],
141
- "execution_count": null,
142
- "outputs": []
143
- },
144
- {
145
- "cell_type": "code",
146
- "metadata": {},
147
- "source": [
148
- "# Map 56 ROI values → fsaverage5 vertices (MNE + Nilearn — no tribev2)\n",
149
- "import sys\n",
150
- "import urllib.request\n",
151
- "from pathlib import Path\n",
152
- "\n",
153
- "_helper = Path(\"text2roi_to_fsaverage.py\")\n",
154
- "if not _helper.exists():\n",
155
- " try:\n",
156
- " from huggingface_hub import hf_hub_download\n",
157
- " _helper = Path(hf_hub_download(HF_REPO, \"text2roi_to_fsaverage.py\"))\n",
158
- " except Exception:\n",
159
- " urllib.request.urlretrieve(\n",
160
- " \"https://raw.githubusercontent.com/hamcoderfran/neuroevolution/main/huggingface/text2roi/text2roi_to_fsaverage.py\",\n",
161
- " _helper,\n",
162
- " )\n",
163
- "sys.path.insert(0, str(_helper.parent))\n",
164
- "from text2roi_to_fsaverage import roi_dict_to_fsaverage5, plot_fsaverage5_brain\n",
165
- "\n",
166
- "print(\"fsaverage5 plotting helpers ready (MNE + Nilearn).\")"
167
- ],
168
- "execution_count": null,
169
- "outputs": []
170
- },
171
- {
172
- "cell_type": "code",
173
- "metadata": {},
174
- "source": [
175
- "def plot_results(text: str, roi_values: dict):\n",
176
- " vertex_map, skipped = roi_dict_to_fsaverage5(roi_values)\n",
177
- "\n",
178
- " # --- ROI bar chart ---\n",
179
- " top = sorted(roi_values.items(), key=lambda kv: abs(kv[1]), reverse=True)[:16]\n",
180
- " names = [t[0] for t in top]\n",
181
- " vals = [t[1] for t in top]\n",
182
- " colors = [\"#c44e52\" if v < 0 else \"#4c72b0\" for v in vals]\n",
183
- "\n",
184
- " fig, ax = plt.subplots(figsize=(7, 5))\n",
185
- " ax.barh(names[::-1], vals[::-1], color=colors[::-1])\n",
186
- " ax.axvline(0, color=\"#333\", lw=0.8)\n",
187
- " ax.set_title(\"Top ROI predictions\")\n",
188
- " ax.set_xlabel(\"Predicted activation\")\n",
189
- " plt.tight_layout()\n",
190
- " plt.show()\n",
191
- "\n",
192
- " # --- fsaverage5 brain maps (Nilearn) ---\n",
193
- " skip_note = f\" — subcortical skipped: {len(skipped)}\" if skipped else \"\"\n",
194
- " plot_fsaverage5_brain(\n",
195
- " vertex_map,\n",
196
- " views=[\"left\", \"right\", \"dorsal\"],\n",
197
- " cmap=\"RdBu_r\",\n",
198
- " threshold=0.02,\n",
199
- " title=f\"fsaverage5 cortical map (HCP-MMP ROIs){skip_note}\",\n",
200
- " )\n",
201
- " plt.show()\n",
202
- "\n",
203
- " print(\"\\nTop ROIs:\")\n",
204
- " for n, v in top[:10]:\n",
205
- " print(f\" {n:<16} {v:+.4f}\")\n",
206
- " if skipped:\n",
207
- " print(f\"\\n(Subcortical / unmapped ROIs not painted on cortex: {', '.join(skipped[:8])}{'…' if len(skipped)>8 else ''})\")"
208
- ],
209
- "execution_count": null,
210
- "outputs": []
211
- },
212
- {
213
- "cell_type": "markdown",
214
- "metadata": {},
215
- "source": [
216
- "## Try it — enter text and click **Predict**\n",
217
- "\n",
218
- "Or use a preset example below."
219
- ]
220
- },
221
- {
222
- "cell_type": "code",
223
- "metadata": {},
224
- "source": [
225
- "text_in = widgets.Textarea(\n",
226
- " value=\"a dog running through a sunny park\",\n",
227
- " description=\"Text:\",\n",
228
- " layout=widgets.Layout(width=\"90%\", height=\"80px\"),\n",
229
- ")\n",
230
- "btn = widgets.Button(description=\"Predict brain map\", button_style=\"primary\", icon=\"play\")\n",
231
- "out = widgets.Output()\n",
232
- "\n",
233
- "PRESETS = {\n",
234
- " \"Sunny park\": \"a dog running through a sunny park\",\n",
235
- " \"Scary scene\": \"a terrifying monster jumps out in a dark alley\",\n",
236
- " \"Romantic\": \"two people sharing a quiet candlelit dinner\",\n",
237
- " \"Math puzzle\": \"solving a difficult calculus proof step by step\",\n",
238
- "}\n",
239
- "preset_btns = [widgets.Button(description=k, layout=widgets.Layout(width=\"140px\")) for k in PRESETS]\n",
240
- "\n",
241
- "def _on_preset(btn):\n",
242
- " text_in.value = PRESETS[btn.description]\n",
243
- "\n",
244
- "for b in preset_btns:\n",
245
- " b.on_click(_on_preset)\n",
246
- "\n",
247
- "def _on_predict(_):\n",
248
- " with out:\n",
249
- " clear_output(wait=True)\n",
250
- " text = text_in.value.strip()\n",
251
- " if not text:\n",
252
- " print(\"Enter some text first.\")\n",
253
- " return\n",
254
- " print(f\"Predicting for: {text!r} …\")\n",
255
- " rois = predict_rois(text)\n",
256
- " plot_results(text, rois)\n",
257
- "\n",
258
- "btn.on_click(_on_predict)\n",
259
- "\n",
260
- "display(widgets.VBox([\n",
261
- " text_in,\n",
262
- " widgets.HBox([btn] + preset_btns),\n",
263
- " out,\n",
264
- "]))"
265
- ],
266
- "execution_count": null,
267
- "outputs": []
268
- },
269
- {
270
- "cell_type": "markdown",
271
- "metadata": {},
272
- "source": [
273
- "## What the output means\n",
274
- "\n",
275
- "| Output | Description |\n",
276
- "|--------|-------------|\n",
277
- "| **Bar chart** | Top 16 of 56 ROI activation scores (positive = predicted up-regulation) |\n",
278
- "| **Brain surface** | ROI values painted onto **fsaverage5** via HCP-MMP1 parcels (MNE + Nilearn) |\n",
279
- "| **Skipped ROIs** | Subcortical regions (amygdala, striatum, thalamus) are not on the cortical surface |\n",
280
- "\n",
281
- "**Links:** [Model on HF](https://huggingface.co/ffh92r32rm0/Amphora_NeuroText) · [Code](https://github.com/hamcoderfran/neuroevolution)"
282
- ]
283
- }
284
- ],
285
- "metadata": {
286
- "colab": {
287
- "provenance": [],
288
- "gpuType": "T4"
289
- },
290
- "kernelspec": {
291
- "display_name": "Python 3",
292
- "name": "python3"
293
- },
294
- "language_info": {
295
- "name": "python"
296
- },
297
- "accelerator": "GPU"
298
- },
299
- "nbformat": 4,
300
- "nbformat_minor": 5
301
- }