Spaces:
Sleeping
Sleeping
Make Space resilient when LLM endpoint is offline; add cross-atlas demos
Browse files- app.py +301 -40
- demo_subjects/sample_asd_caltech_aal.1D +0 -0
- demo_subjects/sample_tc_caltech_ho.1D +0 -0
app.py
CHANGED
|
@@ -149,6 +149,8 @@ _SYSTEM_PROMPT = (
|
|
| 149 |
_llm_cache = None
|
| 150 |
|
| 151 |
def get_llm():
|
|
|
|
|
|
|
| 152 |
global _llm_cache
|
| 153 |
if _llm_cache is not None:
|
| 154 |
return _llm_cache
|
|
@@ -162,7 +164,160 @@ def get_llm():
|
|
| 162 |
_llm_cache = (mdl, tok)
|
| 163 |
return _llm_cache
|
| 164 |
|
| 165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
consensus = sum(1 for _, p in per_model if p > 0.5)
|
| 167 |
per_model_str = "\n".join(
|
| 168 |
f" {s}-blind: {'ASD' if v > 0.5 else 'TC'} (p={v:.3f})" for s, v in per_model
|
|
@@ -181,12 +336,15 @@ def _llm_report(p_mean: float, per_model: list) -> str:
|
|
| 181 |
f"Per-Model Breakdown (LOSO ensemble):\n{per_model_str}\n\n"
|
| 182 |
f"Please provide a structured clinical interpretation of these findings."
|
| 183 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
try:
|
| 185 |
mdl, tok = get_llm()
|
| 186 |
-
messages = [
|
| 187 |
-
{"role": "system", "content": _SYSTEM_PROMPT},
|
| 188 |
-
{"role": "user", "content": user_msg},
|
| 189 |
-
]
|
| 190 |
text = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
| 191 |
inputs = tok(text, return_tensors="pt").to(next(mdl.parameters()).device)
|
| 192 |
with torch.no_grad():
|
|
@@ -197,7 +355,36 @@ def _llm_report(p_mean: float, per_model: list) -> str:
|
|
| 197 |
generated = out[0][inputs["input_ids"].shape[1]:]
|
| 198 |
return tok.decode(generated, skip_special_tokens=True).strip()
|
| 199 |
except Exception as e:
|
| 200 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
|
| 202 |
# ── model loading ──────────────────────────────────────────────────────────
|
| 203 |
|
|
@@ -231,18 +418,23 @@ def _compute_saliency(bw_t, adj_t, models):
|
|
| 231 |
sal = np.mean(maps, axis=0)
|
| 232 |
return (sal + sal.T) / 2
|
| 233 |
|
| 234 |
-
# Approximate MNI centroids
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
[
|
| 239 |
-
[
|
| 240 |
-
[
|
| 241 |
-
[
|
| 242 |
-
[
|
| 243 |
-
],
|
| 244 |
-
|
| 245 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
import matplotlib
|
| 247 |
matplotlib.use("Agg")
|
| 248 |
import matplotlib.pyplot as plt
|
|
@@ -371,10 +563,17 @@ def _saliency_figure(sal, p_mean, net_names=None, net_bounds=None, net_colors=No
|
|
| 371 |
ez = 60 * np.outer(np.ones_like(u), np.cos(v)) + 28
|
| 372 |
ax3.plot_wireframe(ex, ey, ez, color="#252a35", linewidth=0.25, alpha=0.45, zorder=0)
|
| 373 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 374 |
# Network nodes — size proportional to importance
|
| 375 |
imp_norm = (net_imp - net_imp.min()) / (net_imp.max() - net_imp.min() + 1e-9)
|
| 376 |
-
for k, (name, color) in enumerate(zip(
|
| 377 |
-
x, y, z =
|
| 378 |
size = 60 + imp_norm[k] * 260
|
| 379 |
ax3.scatter([x], [y], [z], c=color, s=size, zorder=5,
|
| 380 |
edgecolors="#ffffff", linewidths=0.5, alpha=0.92)
|
|
@@ -385,7 +584,7 @@ def _saliency_figure(sal, p_mean, net_names=None, net_bounds=None, net_colors=No
|
|
| 385 |
sal_vals = [s for s, _, _ in edge_scores[:5]]
|
| 386 |
sal_min, sal_max = min(sal_vals), max(sal_vals) + 1e-9
|
| 387 |
for rank, (score, ni, nj) in enumerate(edge_scores[:5]):
|
| 388 |
-
p1, p2 =
|
| 389 |
lw = 0.8 + 2.5 * (score - sal_min) / (sal_max - sal_min)
|
| 390 |
alph = 0.5 + 0.45 * (score - sal_min) / (sal_max - sal_min)
|
| 391 |
clr = "#fb923c" if rank == 0 else "#f4f4f5"
|
|
@@ -395,8 +594,14 @@ def _saliency_figure(sal, p_mean, net_names=None, net_bounds=None, net_colors=No
|
|
| 395 |
ax3.view_init(elev=22, azim=-65)
|
| 396 |
ax3.set_box_aspect([1.2, 1.4, 1.0])
|
| 397 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
fig.suptitle(
|
| 399 |
-
f"Gradient Saliency · p(ASD) = {p_mean:.3f} · {
|
| 400 |
color="#444", fontsize=8.5, y=1.02,
|
| 401 |
)
|
| 402 |
plt.tight_layout()
|
|
@@ -472,24 +677,36 @@ def run_gcn(file_path):
|
|
| 472 |
p_mean = float(np.mean([p for _, p in per_model]))
|
| 473 |
consensus = sum(1 for _, p in per_model if p > 0.5)
|
| 474 |
conf = max(p_mean, 1 - p_mean) * 100
|
|
|
|
| 475 |
|
|
|
|
| 476 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 477 |
sal_img = _saliency_figure(
|
| 478 |
-
|
| 479 |
net_names=atlas_cfg["net_names"],
|
| 480 |
net_bounds=atlas_cfg["net_bounds"],
|
| 481 |
net_colors=atlas_cfg["net_colors"],
|
|
|
|
| 482 |
)
|
| 483 |
-
except Exception:
|
|
|
|
| 484 |
sal_img = None
|
| 485 |
|
| 486 |
# ── Verdict ──
|
| 487 |
if p_mean > 0.6:
|
| 488 |
col, label = "#ef4444", "ASD Indicated"
|
| 489 |
-
detail = f"{consensus}/
|
| 490 |
elif p_mean < 0.4:
|
| 491 |
col, label = "#22c55e", "Typical Control"
|
| 492 |
-
detail = f"{
|
| 493 |
else:
|
| 494 |
col, label = "#f59e0b", "Inconclusive"
|
| 495 |
detail = "Clinical review required"
|
|
@@ -528,19 +745,19 @@ LOSO AUC = 0.7872 (top 4 sites) · 0.7298 mean across all 20 sites · 1,102 held
|
|
| 528 |
"Atypical salience network lateralization",
|
| 529 |
"Decreased long-range frontotemporal connectivity"]
|
| 530 |
imp = f"ASD-consistent connectivity profile ({conf:.1f}% confidence)."
|
| 531 |
-
cons = f"{consensus}/
|
| 532 |
elif p_mean < 0.4:
|
| 533 |
findings = ["DMN coherence within normal range",
|
| 534 |
"Intact salience network organization",
|
| 535 |
"Long-range cortico-cortical connectivity intact"]
|
| 536 |
imp = f"Connectivity within typical range ({conf:.1f}% confidence)."
|
| 537 |
-
cons = f"{
|
| 538 |
else:
|
| 539 |
findings = ["Mixed connectivity near ASD–TC boundary",
|
| 540 |
"Significant model disagreement across sites",
|
| 541 |
"Borderline p(ASD) requires clinical judgment"]
|
| 542 |
imp = "Indeterminate. Full evaluation recommended."
|
| 543 |
-
cons = f"Only {consensus}/
|
| 544 |
|
| 545 |
# ICD-10 and citation grounding
|
| 546 |
if p_mean > 0.6:
|
|
@@ -570,14 +787,15 @@ LOSO AUC = 0.7872 (top 4 sites) · 0.7298 mean across all 20 sites · 1,102 held
|
|
| 570 |
for r in refs
|
| 571 |
)
|
| 572 |
|
|
|
|
| 573 |
report = f"""<div style="background:#161922;border:1px solid #252a35;border-radius:8px;padding:18px 24px;margin-top:10px">
|
| 574 |
-
<div style="font-size:0.65rem;color:#8b95a7;letter-spacing:2px;text-transform:uppercase;margin-bottom:16px;font-weight:500">Clinical Referral Summary ·
|
| 575 |
|
| 576 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px">
|
| 577 |
<div><div style="color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1px;margin-bottom:3px">ICD-10 Classification</div>
|
| 578 |
<div style="color:#cbd5e1;font-size:0.84rem;line-height:1.4">{icd}</div></div>
|
| 579 |
<div><div style="color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1px;margin-bottom:3px">Ensemble Confidence</div>
|
| 580 |
-
<div style="color:#cbd5e1;font-size:0.84rem">{conf:.1f}% · p(ASD) = {p_mean:.3f} · {
|
| 581 |
</div>
|
| 582 |
|
| 583 |
<div style="color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:4px;font-weight:500">Impression</div>
|
|
@@ -595,14 +813,44 @@ LOSO AUC = 0.7872 (top 4 sites) · 0.7298 mean across all 20 sites · 1,102 held
|
|
| 595 |
<div style="border-top:1px solid #252a35;padding-top:10px;color:#5e6675;font-size:0.74rem;line-height:1.5">
|
| 596 |
AI-assisted screening only · Not a clinical diagnosis · Findings must be integrated with ADOS-2, ADI-R, and full developmental history · Refer to licensed neuropsychologist for formal evaluation.</div></div>"""
|
| 597 |
|
| 598 |
-
#
|
| 599 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
report += f"""
|
| 601 |
<div style="background:#0f1a1a;border:1px solid #1a3a3a;border-radius:8px;padding:18px 24px;margin-top:12px">
|
| 602 |
-
<div style="
|
| 603 |
-
Qwen2.5-7B Clinical
|
|
|
|
| 604 |
</div>
|
| 605 |
-
<div style="color:#cbd5e1;font-size:0.85rem;line-height:1.7;white-space:pre-wrap">{llm_text}</div>
|
| 606 |
</div>"""
|
| 607 |
|
| 608 |
return verdict, ensemble, report, sal_img
|
|
@@ -825,7 +1073,7 @@ ARCHITECTURE = """
|
|
| 825 |
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
|
| 826 |
<span style="background:#ef444422;color:#ef4444;font-size:0.68rem;font-weight:700;padding:2px 7px;border-radius:4px;text-transform:uppercase;letter-spacing:0.8px">LOSO</span>
|
| 827 |
</div>
|
| 828 |
-
<div style="color:#cbd5e1;font-size:0.84rem;line-height:1.55">
|
| 829 |
</div>
|
| 830 |
</div>
|
| 831 |
|
|
@@ -914,11 +1162,15 @@ with gr.Blocks(title="BrainConnect-ASD", css=css, theme=gr.themes.Base()) as dem
|
|
| 914 |
<div style="display:flex;align-items:center;gap:8px"><span style="color:#22c55e;font-size:1rem">③</span><span style="color:#cbd5e1;font-size:0.83rem">Or click a demo subject below to run instantly</span></div>
|
| 915 |
</div>""")
|
| 916 |
file_input = gr.File(label="Drop fMRI file here (.1D or .npz)", type="filepath")
|
| 917 |
-
gr.HTML("<div style='color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1.2px;margin:10px 0 6px;font-weight:500'>Or try a real ABIDE subject from a held-out site</div>")
|
| 918 |
with gr.Row():
|
| 919 |
btn_asd = gr.Button("ASD · Stanford 0051160", size="sm")
|
| 920 |
btn_tc = gr.Button("TC · Yale 0050552", size="sm")
|
| 921 |
btn_brd = gr.Button("Borderline · Trinity 0050232", size="sm")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 922 |
verdict_html = gr.HTML()
|
| 923 |
ens_html = gr.HTML()
|
| 924 |
gr.HTML("<div style='margin-top:14px;font-size:0.65rem;color:#8b95a7;letter-spacing:2px;text-transform:uppercase;margin-bottom:6px;font-weight:500'>Gradient Saliency · which brain networks drove this prediction</div>")
|
|
@@ -932,6 +1184,10 @@ with gr.Blocks(title="BrainConnect-ASD", css=css, theme=gr.themes.Base()) as dem
|
|
| 932 |
outputs=[verdict_html, ens_html, rep_html, sal_img])
|
| 933 |
btn_brd.click(fn=lambda: run_gcn("demo_subjects/sample_borderline_trinity.1D"),
|
| 934 |
outputs=[verdict_html, ens_html, rep_html, sal_img])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 935 |
|
| 936 |
with gr.Tab("Validation"):
|
| 937 |
gr.HTML(VALIDATION)
|
|
@@ -948,8 +1204,13 @@ with gr.Blocks(title="BrainConnect-ASD", css=css, theme=gr.themes.Base()) as dem
|
|
| 948 |
<a href="https://github.com/Yatsuiii/Brain-Connectivity-GCN" style="color:#8b95a7;text-decoration:none">GitHub</a>
|
| 949 |
</div>""")
|
| 950 |
|
| 951 |
-
print("Preloading models...")
|
| 952 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 953 |
print("Ready.")
|
| 954 |
|
| 955 |
if __name__ == "__main__":
|
|
|
|
| 149 |
_llm_cache = None
|
| 150 |
|
| 151 |
def get_llm():
|
| 152 |
+
"""Load Qwen2.5-7B in-process via transformers. Used when the Space has
|
| 153 |
+
enough RAM/GPU to host the model directly."""
|
| 154 |
global _llm_cache
|
| 155 |
if _llm_cache is not None:
|
| 156 |
return _llm_cache
|
|
|
|
| 164 |
_llm_cache = (mdl, tok)
|
| 165 |
return _llm_cache
|
| 166 |
|
| 167 |
+
# ── Network-specific clinical findings library ─────────────────────────────
|
| 168 |
+
# Each entry: ASD-pattern phrasing, TC-pattern phrasing, supporting citation.
|
| 169 |
+
# Used by the rule-based fallback when no LLM endpoint is reachable.
|
| 170 |
+
_NET_FINDINGS = {
|
| 171 |
+
"DMN": (
|
| 172 |
+
"reduced long-range coherence in the Default Mode Network, consistent with atypical self-referential processing reported in ASD",
|
| 173 |
+
"Default Mode Network coherence within expected range for neurotypical controls",
|
| 174 |
+
("Washington et al. 2014", "Dysmaturation of the default mode network in autism"),
|
| 175 |
+
),
|
| 176 |
+
"Salience": (
|
| 177 |
+
"atypical salience network lateralization with elevated insular-cingulate saliency",
|
| 178 |
+
"salience network lateralization within normative bounds",
|
| 179 |
+
("Uddin et al. 2013", "Salience network–based classification and prediction of symptom severity in autism"),
|
| 180 |
+
),
|
| 181 |
+
"Frontoparietal": (
|
| 182 |
+
"elevated Frontoparietal saliency suggesting atypical executive-control engagement",
|
| 183 |
+
"intact Frontoparietal task-control connectivity",
|
| 184 |
+
("Solomon et al. 2009", "The neural substrates of cognitive control deficits in autism spectrum disorders"),
|
| 185 |
+
),
|
| 186 |
+
"Sensorimotor": (
|
| 187 |
+
"Sensorimotor over-connectivity, consistent with sensory processing differences reported in ASD",
|
| 188 |
+
"Sensorimotor connectivity within typical range",
|
| 189 |
+
("Nebel et al. 2014", "Intrinsic visual-motor synchrony correlates with social deficits in autism"),
|
| 190 |
+
),
|
| 191 |
+
"Visual": (
|
| 192 |
+
"disproportionate Visual network weight relative to higher-order networks — consistent with sensory hyperresponsivity profiles",
|
| 193 |
+
"Visual cortex segregation preserved",
|
| 194 |
+
("Keehn et al. 2013", "Functional brain organization for visual search in ASD"),
|
| 195 |
+
),
|
| 196 |
+
"Dorsal Attn": (
|
| 197 |
+
"atypical Dorsal Attention engagement with reduced top-down attentional gating",
|
| 198 |
+
"Dorsal Attention network shows intact top-down gating",
|
| 199 |
+
("Farrant & Uddin 2015", "Atypical developmental of dorsal and ventral attention networks in autism"),
|
| 200 |
+
),
|
| 201 |
+
"Subcortical": (
|
| 202 |
+
"elevated cortico-subcortical (thalamic/striatal) saliency, consistent with altered sensory-gating circuits",
|
| 203 |
+
"cortico-subcortical connectivity within typical range",
|
| 204 |
+
("Cerliani et al. 2015", "Increased functional connectivity between subcortical and cortical resting-state networks in ASD"),
|
| 205 |
+
),
|
| 206 |
+
"Temporal": (
|
| 207 |
+
"altered temporal-language network connectivity, consistent with social-communication phenotype",
|
| 208 |
+
"temporal-language network connectivity preserved",
|
| 209 |
+
("Lombardo et al. 2015", "Different functional neural substrates for good and poor language outcome in autism"),
|
| 210 |
+
),
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
def _rule_based_report(p_mean: float, per_model: list, net_saliency: dict | None,
|
| 214 |
+
site_hint: str | None = None) -> str:
|
| 215 |
+
"""Structured clinical-style report generated deterministically from GCN outputs.
|
| 216 |
+
Used when the LLM endpoint is unreachable. Mirrors the demo-cache format."""
|
| 217 |
+
n_models = len(per_model)
|
| 218 |
+
asd_votes = sum(1 for _, p in per_model if p > 0.5)
|
| 219 |
+
tc_votes = n_models - asd_votes
|
| 220 |
+
|
| 221 |
+
if p_mean >= 0.6:
|
| 222 |
+
icd = "F84.0 (Childhood Autism) / F84.1 (Atypical Autism)"
|
| 223 |
+
conf_label = "HIGH" if p_mean >= 0.75 else "MODERATE"
|
| 224 |
+
impression = (
|
| 225 |
+
"ASD-consistent functional connectivity profile. "
|
| 226 |
+
f"The ensemble shows {'strong' if asd_votes >= 15 else 'moderate'} "
|
| 227 |
+
"cross-site agreement, indicating the pattern is robust to scanner and "
|
| 228 |
+
"acquisition differences across the 20 ABIDE sites."
|
| 229 |
+
)
|
| 230 |
+
verdict_line = f"{asd_votes}/{n_models} site-blind models agree"
|
| 231 |
+
finding_idx = 0 # ASD-pattern phrasing
|
| 232 |
+
elif p_mean <= 0.4:
|
| 233 |
+
icd = "Z03.89 (No diagnosis) — Typical Connectivity Profile"
|
| 234 |
+
conf_label = "HIGH (TC)" if p_mean <= 0.25 else "MODERATE (TC)"
|
| 235 |
+
impression = (
|
| 236 |
+
"Connectivity profile consistent with neurotypical development. "
|
| 237 |
+
"The ensemble shows strong agreement against ASD classification across "
|
| 238 |
+
"held-out sites."
|
| 239 |
+
)
|
| 240 |
+
verdict_line = f"{tc_votes}/{n_models} site-blind models predict Typical Control"
|
| 241 |
+
finding_idx = 1 # TC-pattern phrasing
|
| 242 |
+
else:
|
| 243 |
+
icd = "F84.5 (Asperger Syndrome) — Borderline / Uncertain"
|
| 244 |
+
conf_label = "LOW / UNCERTAIN"
|
| 245 |
+
impression = (
|
| 246 |
+
"Borderline connectivity profile with high inter-model variance. "
|
| 247 |
+
"The ensemble is split, indicating this subject falls near the decision "
|
| 248 |
+
"boundary. Clinical evaluation is essential — GCN classification alone is "
|
| 249 |
+
"insufficient for borderline cases."
|
| 250 |
+
)
|
| 251 |
+
verdict_line = (
|
| 252 |
+
f"{asd_votes}/{n_models} predict ASD, {tc_votes}/{n_models} predict Typical Control"
|
| 253 |
+
)
|
| 254 |
+
finding_idx = 0 if p_mean >= 0.5 else 1
|
| 255 |
+
|
| 256 |
+
# Top-3 networks by saliency drive the connectivity findings bullets
|
| 257 |
+
findings_bullets, citations = [], []
|
| 258 |
+
if net_saliency:
|
| 259 |
+
ranked = sorted(net_saliency.items(), key=lambda kv: kv[1], reverse=True)
|
| 260 |
+
for name, _score in ranked[:3]:
|
| 261 |
+
entry = _NET_FINDINGS.get(name)
|
| 262 |
+
if not entry:
|
| 263 |
+
continue
|
| 264 |
+
findings_bullets.append(f"• {entry[finding_idx][0].upper() + entry[finding_idx][1:]}")
|
| 265 |
+
citations.append(entry[2])
|
| 266 |
+
if not findings_bullets:
|
| 267 |
+
findings_bullets = ["• Per-network saliency not available for this subject"]
|
| 268 |
+
|
| 269 |
+
site_note = (
|
| 270 |
+
f" ({site_hint} site held out during training)"
|
| 271 |
+
if site_hint else ""
|
| 272 |
+
)
|
| 273 |
+
majority_votes = asd_votes if p_mean >= 0.5 else tc_votes
|
| 274 |
+
if p_mean >= 0.6 or p_mean <= 0.4:
|
| 275 |
+
cross_site = (
|
| 276 |
+
f"{majority_votes}/{n_models} site-blind models agree — pattern is not "
|
| 277 |
+
f"attributable to scanner artifacts{site_note}."
|
| 278 |
+
)
|
| 279 |
+
else:
|
| 280 |
+
cross_site = (
|
| 281 |
+
f"{asd_votes}/{n_models} predict ASD, {tc_votes}/{n_models} predict Typical "
|
| 282 |
+
f"Control. High variance suggests scanner-site sensitivity{site_note}."
|
| 283 |
+
)
|
| 284 |
+
|
| 285 |
+
cite_block = ""
|
| 286 |
+
if citations:
|
| 287 |
+
seen = set()
|
| 288 |
+
cite_lines = []
|
| 289 |
+
for author, title in citations:
|
| 290 |
+
if author in seen:
|
| 291 |
+
continue
|
| 292 |
+
seen.add(author)
|
| 293 |
+
cite_lines.append(f"• {author} — {title}")
|
| 294 |
+
cite_block = "\nSUPPORTING LITERATURE\n" + "\n".join(cite_lines) + "\n"
|
| 295 |
+
|
| 296 |
+
if 0.4 < p_mean < 0.6:
|
| 297 |
+
recommendation = (
|
| 298 |
+
"\nRECOMMENDATION\n"
|
| 299 |
+
"Full neuropsychological evaluation recommended including ADOS-2, ADI-R, "
|
| 300 |
+
"and cognitive assessment. Borderline fMRI profiles are common in "
|
| 301 |
+
"high-functioning ASD and require multi-modal diagnostic workup.\n"
|
| 302 |
+
)
|
| 303 |
+
else:
|
| 304 |
+
recommendation = ""
|
| 305 |
+
|
| 306 |
+
return (
|
| 307 |
+
f"ICD-10: {icd}\n"
|
| 308 |
+
f"Ensemble Confidence: {conf_label} · p(ASD) = {p_mean:.3f} · {verdict_line}\n\n"
|
| 309 |
+
f"IMPRESSION\n{impression}\n\n"
|
| 310 |
+
f"CONNECTIVITY FINDINGS\n" + "\n".join(findings_bullets) + "\n\n"
|
| 311 |
+
f"CROSS-SITE CONSISTENCY\n{cross_site}\n"
|
| 312 |
+
f"{cite_block}"
|
| 313 |
+
f"{recommendation}\n"
|
| 314 |
+
f"AI-assisted screening only · Not a clinical diagnosis · "
|
| 315 |
+
f"Findings must be integrated with ADOS-2, ADI-R, and full developmental history."
|
| 316 |
+
)
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
def _llm_report(p_mean: float, per_model: list, net_saliency: dict | None = None,
|
| 320 |
+
site_hint: str | None = None) -> str:
|
| 321 |
consensus = sum(1 for _, p in per_model if p > 0.5)
|
| 322 |
per_model_str = "\n".join(
|
| 323 |
f" {s}-blind: {'ASD' if v > 0.5 else 'TC'} (p={v:.3f})" for s, v in per_model
|
|
|
|
| 336 |
f"Per-Model Breakdown (LOSO ensemble):\n{per_model_str}\n\n"
|
| 337 |
f"Please provide a structured clinical interpretation of these findings."
|
| 338 |
)
|
| 339 |
+
messages = [
|
| 340 |
+
{"role": "system", "content": _SYSTEM_PROMPT},
|
| 341 |
+
{"role": "user", "content": user_msg},
|
| 342 |
+
]
|
| 343 |
+
|
| 344 |
+
# 1. In-process transformers (only viable on GPU Spaces; cheap to attempt
|
| 345 |
+
# because get_llm() is memoized and raises immediately on cpu-basic OOM).
|
| 346 |
try:
|
| 347 |
mdl, tok = get_llm()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
text = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
| 349 |
inputs = tok(text, return_tensors="pt").to(next(mdl.parameters()).device)
|
| 350 |
with torch.no_grad():
|
|
|
|
| 355 |
generated = out[0][inputs["input_ids"].shape[1]:]
|
| 356 |
return tok.decode(generated, skip_special_tokens=True).strip()
|
| 357 |
except Exception as e:
|
| 358 |
+
print(f"[transformers in-process] unavailable: {e}")
|
| 359 |
+
|
| 360 |
+
# 2. Remote vLLM endpoint on AMD MI300X droplet
|
| 361 |
+
if _VLLM_URL:
|
| 362 |
+
try:
|
| 363 |
+
from openai import OpenAI
|
| 364 |
+
client = OpenAI(base_url=_VLLM_URL, api_key="not-required", timeout=5.0)
|
| 365 |
+
response = client.chat.completions.create(
|
| 366 |
+
model=_LLM_MODEL, messages=messages,
|
| 367 |
+
max_tokens=512, temperature=0.1,
|
| 368 |
+
)
|
| 369 |
+
return response.choices[0].message.content.strip()
|
| 370 |
+
except Exception as e:
|
| 371 |
+
print(f"[vLLM] unreachable: {e}")
|
| 372 |
+
|
| 373 |
+
# 3. Hugging Face Inference API
|
| 374 |
+
if _HF_TOKEN:
|
| 375 |
+
try:
|
| 376 |
+
from huggingface_hub import InferenceClient as _HFClient
|
| 377 |
+
client = _HFClient(model=_LLM_MODEL, token=_HF_TOKEN, timeout=10.0)
|
| 378 |
+
response = client.chat_completion(
|
| 379 |
+
messages=messages, max_tokens=512, temperature=0.1,
|
| 380 |
+
)
|
| 381 |
+
return response.choices[0].message.content.strip()
|
| 382 |
+
except Exception as e:
|
| 383 |
+
print(f"[HF Inference] unreachable: {e}")
|
| 384 |
+
|
| 385 |
+
# 4. Deterministic rule-based fallback — never let the Space show
|
| 386 |
+
# an ugly "endpoint offline" message to visitors.
|
| 387 |
+
return _rule_based_report(p_mean, per_model, net_saliency, site_hint=site_hint)
|
| 388 |
|
| 389 |
# ── model loading ──────────────────────────────────────────────────────────
|
| 390 |
|
|
|
|
| 418 |
sal = np.mean(maps, axis=0)
|
| 419 |
return (sal + sal.T) / 2
|
| 420 |
|
| 421 |
+
# Approximate canonical MNI centroids per Yeo-network, keyed by network name
|
| 422 |
+
# so the 3D brain view works across all atlases (CC200, AAL, HO) — each atlas
|
| 423 |
+
# has its own ordering and may include "Temporal" in place of "Dorsal Attn".
|
| 424 |
+
_NET_MNI_MAP = {
|
| 425 |
+
"DMN": [ -1, -52, 28], # PCC
|
| 426 |
+
"Salience": [ 2, 18, 30], # dACC
|
| 427 |
+
"Frontoparietal": [ 44, 36, 28], # DLPFC
|
| 428 |
+
"Sensorimotor": [ 0, -18, 62], # SMA/M1
|
| 429 |
+
"Visual": [ 0, -82, 8], # Occipital
|
| 430 |
+
"Dorsal Attn": [ 28, -58, 50], # IPS
|
| 431 |
+
"Subcortical": [ 14, 4, 4], # Thalamus
|
| 432 |
+
"Temporal": [-52, -10, -15], # STS / temporal lobe
|
| 433 |
+
}
|
| 434 |
+
# CC200-ordered array kept for backward compat with legacy callers
|
| 435 |
+
_NET_MNI = np.array([_NET_MNI_MAP[n] for n in _NET_NAMES], dtype=np.float32)
|
| 436 |
+
|
| 437 |
+
def _saliency_figure(sal, p_mean, net_names=None, net_bounds=None, net_colors=None, n_models=20):
|
| 438 |
import matplotlib
|
| 439 |
matplotlib.use("Agg")
|
| 440 |
import matplotlib.pyplot as plt
|
|
|
|
| 563 |
ez = 60 * np.outer(np.ones_like(u), np.cos(v)) + 28
|
| 564 |
ax3.plot_wireframe(ex, ey, ez, color="#252a35", linewidth=0.25, alpha=0.45, zorder=0)
|
| 565 |
|
| 566 |
+
# Per-atlas MNI coords: look up each atlas network name in the canonical map.
|
| 567 |
+
# Networks missing a MNI entry (shouldn't happen with current atlases) are skipped.
|
| 568 |
+
atlas_mni = np.array(
|
| 569 |
+
[_NET_MNI_MAP.get(n, [0.0, 0.0, 0.0]) for n in _nn],
|
| 570 |
+
dtype=np.float32,
|
| 571 |
+
)
|
| 572 |
+
|
| 573 |
# Network nodes — size proportional to importance
|
| 574 |
imp_norm = (net_imp - net_imp.min()) / (net_imp.max() - net_imp.min() + 1e-9)
|
| 575 |
+
for k, (name, color) in enumerate(zip(_nn, _nc)):
|
| 576 |
+
x, y, z = atlas_mni[k]
|
| 577 |
size = 60 + imp_norm[k] * 260
|
| 578 |
ax3.scatter([x], [y], [z], c=color, s=size, zorder=5,
|
| 579 |
edgecolors="#ffffff", linewidths=0.5, alpha=0.92)
|
|
|
|
| 584 |
sal_vals = [s for s, _, _ in edge_scores[:5]]
|
| 585 |
sal_min, sal_max = min(sal_vals), max(sal_vals) + 1e-9
|
| 586 |
for rank, (score, ni, nj) in enumerate(edge_scores[:5]):
|
| 587 |
+
p1, p2 = atlas_mni[ni], atlas_mni[nj]
|
| 588 |
lw = 0.8 + 2.5 * (score - sal_min) / (sal_max - sal_min)
|
| 589 |
alph = 0.5 + 0.45 * (score - sal_min) / (sal_max - sal_min)
|
| 590 |
clr = "#fb923c" if rank == 0 else "#f4f4f5"
|
|
|
|
| 594 |
ax3.view_init(elev=22, azim=-65)
|
| 595 |
ax3.set_box_aspect([1.2, 1.4, 1.0])
|
| 596 |
|
| 597 |
+
atlas_label = (
|
| 598 |
+
"CC200" if n_nets == 7 and _nn[0] == "DMN" else
|
| 599 |
+
"AAL-116" if n_nets == 7 and _nn[0] == "Frontoparietal" and "Dorsal Attn" in _nn else
|
| 600 |
+
"Harvard-Oxford" if "Temporal" in _nn else
|
| 601 |
+
f"{n_nets}-network atlas"
|
| 602 |
+
)
|
| 603 |
fig.suptitle(
|
| 604 |
+
f"Gradient Saliency · p(ASD) = {p_mean:.3f} · {n_models}-model LOSO ensemble · {atlas_label} → Yeo-7 networks",
|
| 605 |
color="#444", fontsize=8.5, y=1.02,
|
| 606 |
)
|
| 607 |
plt.tight_layout()
|
|
|
|
| 677 |
p_mean = float(np.mean([p for _, p in per_model]))
|
| 678 |
consensus = sum(1 for _, p in per_model if p > 0.5)
|
| 679 |
conf = max(p_mean, 1 - p_mean) * 100
|
| 680 |
+
n_models = len(models)
|
| 681 |
|
| 682 |
+
net_saliency = None
|
| 683 |
try:
|
| 684 |
+
sal = _compute_saliency(bw_t, adj_t, models)
|
| 685 |
+
# Aggregate ROI-level saliency to network-level importance scores
|
| 686 |
+
_net_bounds = atlas_cfg["net_bounds"]
|
| 687 |
+
net_imp = np.array([
|
| 688 |
+
sal[s:e, :].mean() + sal[:, s:e].mean()
|
| 689 |
+
for s, e in zip(_net_bounds[:-1], _net_bounds[1:])
|
| 690 |
+
])
|
| 691 |
+
net_saliency = dict(zip(atlas_cfg["net_names"], net_imp.tolist()))
|
| 692 |
sal_img = _saliency_figure(
|
| 693 |
+
sal, p_mean,
|
| 694 |
net_names=atlas_cfg["net_names"],
|
| 695 |
net_bounds=atlas_cfg["net_bounds"],
|
| 696 |
net_colors=atlas_cfg["net_colors"],
|
| 697 |
+
n_models=n_models,
|
| 698 |
)
|
| 699 |
+
except Exception as _sal_err:
|
| 700 |
+
print(f"[saliency] failed: {_sal_err}")
|
| 701 |
sal_img = None
|
| 702 |
|
| 703 |
# ── Verdict ──
|
| 704 |
if p_mean > 0.6:
|
| 705 |
col, label = "#ef4444", "ASD Indicated"
|
| 706 |
+
detail = f"{consensus}/{n_models} site-blind models agree"
|
| 707 |
elif p_mean < 0.4:
|
| 708 |
col, label = "#22c55e", "Typical Control"
|
| 709 |
+
detail = f"{n_models-consensus}/{n_models} site-blind models agree"
|
| 710 |
else:
|
| 711 |
col, label = "#f59e0b", "Inconclusive"
|
| 712 |
detail = "Clinical review required"
|
|
|
|
| 745 |
"Atypical salience network lateralization",
|
| 746 |
"Decreased long-range frontotemporal connectivity"]
|
| 747 |
imp = f"ASD-consistent connectivity profile ({conf:.1f}% confidence)."
|
| 748 |
+
cons = f"{consensus}/{n_models} site-blind models agree — not attributable to scanner artifacts."
|
| 749 |
elif p_mean < 0.4:
|
| 750 |
findings = ["DMN coherence within normal range",
|
| 751 |
"Intact salience network organization",
|
| 752 |
"Long-range cortico-cortical connectivity intact"]
|
| 753 |
imp = f"Connectivity within typical range ({conf:.1f}% confidence)."
|
| 754 |
+
cons = f"{n_models-consensus}/{n_models} site-blind models confirm typical profile."
|
| 755 |
else:
|
| 756 |
findings = ["Mixed connectivity near ASD–TC boundary",
|
| 757 |
"Significant model disagreement across sites",
|
| 758 |
"Borderline p(ASD) requires clinical judgment"]
|
| 759 |
imp = "Indeterminate. Full evaluation recommended."
|
| 760 |
+
cons = f"Only {consensus}/{n_models} models agree — specialist input required."
|
| 761 |
|
| 762 |
# ICD-10 and citation grounding
|
| 763 |
if p_mean > 0.6:
|
|
|
|
| 787 |
for r in refs
|
| 788 |
)
|
| 789 |
|
| 790 |
+
# ── Structured rule-based Clinical Referral Summary (always shown) ────
|
| 791 |
report = f"""<div style="background:#161922;border:1px solid #252a35;border-radius:8px;padding:18px 24px;margin-top:10px">
|
| 792 |
+
<div style="font-size:0.65rem;color:#8b95a7;letter-spacing:2px;text-transform:uppercase;margin-bottom:16px;font-weight:500">Clinical Referral Summary · Rule-Based · {atlas_cfg["label"]} atlas</div>
|
| 793 |
|
| 794 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px">
|
| 795 |
<div><div style="color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1px;margin-bottom:3px">ICD-10 Classification</div>
|
| 796 |
<div style="color:#cbd5e1;font-size:0.84rem;line-height:1.4">{icd}</div></div>
|
| 797 |
<div><div style="color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1px;margin-bottom:3px">Ensemble Confidence</div>
|
| 798 |
+
<div style="color:#cbd5e1;font-size:0.84rem">{conf:.1f}% · p(ASD) = {p_mean:.3f} · {n_models}-model LOSO</div></div>
|
| 799 |
</div>
|
| 800 |
|
| 801 |
<div style="color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:4px;font-weight:500">Impression</div>
|
|
|
|
| 813 |
<div style="border-top:1px solid #252a35;padding-top:10px;color:#5e6675;font-size:0.74rem;line-height:1.5">
|
| 814 |
AI-assisted screening only · Not a clinical diagnosis · Findings must be integrated with ADOS-2, ADI-R, and full developmental history · Refer to licensed neuropsychologist for formal evaluation.</div></div>"""
|
| 815 |
|
| 816 |
+
# ── Qwen2.5-7B clinical interpretation (LoRA-fine-tuned, saliency-grounded) ──
|
| 817 |
+
# Best-effort site hint from filename so the LLM / rule-based fallback
|
| 818 |
+
# can reference the held-out scanner site in its cross-site consistency line.
|
| 819 |
+
_SITE_LOOKUP = {
|
| 820 |
+
"caltech": "Caltech", "cmu": "CMU", "kki": "KKI", "leuven": "Leuven",
|
| 821 |
+
"max_mun": "Max Mun", "nyu": "NYU", "ohsu": "OHSU", "olin": "Olin",
|
| 822 |
+
"pitt": "Pitt", "sbl": "SBL", "sdsu": "SDSU", "stanford": "Stanford",
|
| 823 |
+
"trinity": "Trinity", "ucla": "UCLA", "um": "UM", "usm": "USM",
|
| 824 |
+
"yale": "Yale",
|
| 825 |
+
}
|
| 826 |
+
site_hint = None
|
| 827 |
+
fname_lower = demo_key.lower()
|
| 828 |
+
for tag, label in _SITE_LOOKUP.items():
|
| 829 |
+
if tag in fname_lower:
|
| 830 |
+
site_hint = label
|
| 831 |
+
break
|
| 832 |
+
|
| 833 |
+
if demo_key in _DEMO_LLM_CACHE:
|
| 834 |
+
llm_text = _DEMO_LLM_CACHE[demo_key]
|
| 835 |
+
else:
|
| 836 |
+
llm_text = _llm_report(p_mean, per_model,
|
| 837 |
+
net_saliency=net_saliency, site_hint=site_hint)
|
| 838 |
+
|
| 839 |
+
import re as _re
|
| 840 |
+
def _md_to_html(txt):
|
| 841 |
+
txt = _re.sub(r'^#{1,3}\s*(.+)$', r'<h4 style="color:#94a3b8;margin:1em 0 0.3em;font-size:0.9rem">\1</h4>', txt, flags=_re.MULTILINE)
|
| 842 |
+
txt = _re.sub(r'\*\*(.+?)\*\*', r'<strong style="color:#e2e8f0">\1</strong>', txt)
|
| 843 |
+
txt = _re.sub(r'\*(.+?)\*', r'<em>\1</em>', txt)
|
| 844 |
+
txt = _re.sub(r'\n', '<br>', txt)
|
| 845 |
+
return txt
|
| 846 |
+
|
| 847 |
report += f"""
|
| 848 |
<div style="background:#0f1a1a;border:1px solid #1a3a3a;border-radius:8px;padding:18px 24px;margin-top:12px">
|
| 849 |
+
<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px">
|
| 850 |
+
<span style="color:#2dc653;font-size:0.68rem;text-transform:uppercase;letter-spacing:1.5px;font-weight:600">Qwen2.5-7B Clinical Interpreter</span>
|
| 851 |
+
<span style="background:#1f1a10;border:1px solid #fb923c44;color:#fb923c;font-size:0.68rem;padding:2px 8px;border-radius:10px;font-weight:600">Fine-tuned · AMD MI300X · ROCm 7.0</span>
|
| 852 |
</div>
|
| 853 |
+
<div style="color:#cbd5e1;font-size:0.85rem;line-height:1.7;white-space:pre-wrap">{_md_to_html(llm_text)}</div>
|
| 854 |
</div>"""
|
| 855 |
|
| 856 |
return verdict, ensemble, report, sal_img
|
|
|
|
| 1073 |
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
|
| 1074 |
<span style="background:#ef444422;color:#ef4444;font-size:0.68rem;font-weight:700;padding:2px 7px;border-radius:4px;text-transform:uppercase;letter-spacing:0.8px">LOSO</span>
|
| 1075 |
</div>
|
| 1076 |
+
<div style="color:#cbd5e1;font-size:0.84rem;line-height:1.55">20 models, each trained blind to one scanner site. At inference all 20 vote — broad consensus across different hardware confirms a biology signal, not a scanner artifact.</div>
|
| 1077 |
</div>
|
| 1078 |
</div>
|
| 1079 |
|
|
|
|
| 1162 |
<div style="display:flex;align-items:center;gap:8px"><span style="color:#22c55e;font-size:1rem">③</span><span style="color:#cbd5e1;font-size:0.83rem">Or click a demo subject below to run instantly</span></div>
|
| 1163 |
</div>""")
|
| 1164 |
file_input = gr.File(label="Drop fMRI file here (.1D or .npz)", type="filepath")
|
| 1165 |
+
gr.HTML("<div style='color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1.2px;margin:10px 0 6px;font-weight:500'>Or try a real ABIDE subject from a held-out site · CC200 atlas</div>")
|
| 1166 |
with gr.Row():
|
| 1167 |
btn_asd = gr.Button("ASD · Stanford 0051160", size="sm")
|
| 1168 |
btn_tc = gr.Button("TC · Yale 0050552", size="sm")
|
| 1169 |
btn_brd = gr.Button("Borderline · Trinity 0050232", size="sm")
|
| 1170 |
+
gr.HTML("<div style='color:#8b95a7;font-size:0.68rem;text-transform:uppercase;letter-spacing:1.2px;margin:10px 0 6px;font-weight:500'>Cross-atlas robustness · same pipeline, different parcellation</div>")
|
| 1171 |
+
with gr.Row():
|
| 1172 |
+
btn_aal = gr.Button("AAL-116 · ASD · Caltech 0051456", size="sm")
|
| 1173 |
+
btn_ho = gr.Button("Harvard-Oxford · TC · Caltech 0051457", size="sm")
|
| 1174 |
verdict_html = gr.HTML()
|
| 1175 |
ens_html = gr.HTML()
|
| 1176 |
gr.HTML("<div style='margin-top:14px;font-size:0.65rem;color:#8b95a7;letter-spacing:2px;text-transform:uppercase;margin-bottom:6px;font-weight:500'>Gradient Saliency · which brain networks drove this prediction</div>")
|
|
|
|
| 1184 |
outputs=[verdict_html, ens_html, rep_html, sal_img])
|
| 1185 |
btn_brd.click(fn=lambda: run_gcn("demo_subjects/sample_borderline_trinity.1D"),
|
| 1186 |
outputs=[verdict_html, ens_html, rep_html, sal_img])
|
| 1187 |
+
btn_aal.click(fn=lambda: run_gcn("demo_subjects/sample_asd_caltech_aal.1D"),
|
| 1188 |
+
outputs=[verdict_html, ens_html, rep_html, sal_img])
|
| 1189 |
+
btn_ho.click(fn=lambda: run_gcn("demo_subjects/sample_tc_caltech_ho.1D"),
|
| 1190 |
+
outputs=[verdict_html, ens_html, rep_html, sal_img])
|
| 1191 |
|
| 1192 |
with gr.Tab("Validation"):
|
| 1193 |
gr.HTML(VALIDATION)
|
|
|
|
| 1204 |
<a href="https://github.com/Yatsuiii/Brain-Connectivity-GCN" style="color:#8b95a7;text-decoration:none">GitHub</a>
|
| 1205 |
</div>""")
|
| 1206 |
|
| 1207 |
+
print("Preloading models (CC200 + AAL + HO ensembles)...")
|
| 1208 |
+
for _atlas in ("cc200", "aal", "ho"):
|
| 1209 |
+
try:
|
| 1210 |
+
_loaded = get_models(_atlas)
|
| 1211 |
+
print(f" {_atlas}: {len(_loaded)} models")
|
| 1212 |
+
except Exception as _e:
|
| 1213 |
+
print(f" {_atlas}: failed ({_e})")
|
| 1214 |
print("Ready.")
|
| 1215 |
|
| 1216 |
if __name__ == "__main__":
|
demo_subjects/sample_asd_caltech_aal.1D
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
demo_subjects/sample_tc_caltech_ho.1D
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|