Tutorial 3: Generative Text-to-Brain#

This tutorial demonstrates how to generate brain activation maps from text descriptions using NeuroVLM’s generative approach.

Pipeline: Text → SPECTER2 → Projection Head (MSE) → Autoencoder Decoder → Brain Activation Map

You’ll learn:

  1. Basic text-to-brain generation

  2. Generating maps for different cognitive concepts

  3. Batch generation for multiple queries

  4. Saving and exporting generated maps

  5. Comparing generated vs. retrieved maps

import os

os.environ["USE_TF"] = "0"
os.environ["USE_FLAX"] = "0"
os.environ["TOKENIZERS_PARALLELISM"] = "false"

from neurovlm import NeuroVLM
import numpy as np

# Initialize model
nvlm = NeuroVLM()

1. Basic Text-to-Brain Generation#

The generative approach uses the MSE projection head to map text embeddings directly into the brain latent space, then decodes them into full brain activation maps.

# Generate a brain map from a simple text query
result = nvlm.text("vision").to_brain(head="mse")

# Plot the generated activation map
result.plot(threshold=0.25);
There are adapters available but none are activated for the forward pass.
../_images/44797c0e99b428707934cf7c4d2359610914353cd6c3ac87c01830708dc4fdb3.png

Access the NIfTI image#

# Get the NIfTI image
nifti_img = result.to_nifti()[0]
print(f"Image shape: {nifti_img.shape}")
print(f"Image affine:\n{nifti_img.affine}")
Image shape: (46, 55, 46, 1)
Image affine:
[[   4.    0.    0.  -90.]
 [   0.    4.    0. -126.]
 [   0.    0.    4.  -72.]
 [   0.    0.    0.    1.]]

2. Generate Maps for Different Cognitive Concepts#

Visual Processing#

result = nvlm.text("visual object recognition").to_brain(head="mse")
result.plot(threshold=0.2, title="Visual Object Recognition");
../_images/819b8f86f556e11c3a83726fa1e438d6b12d0ee3d7860142ab14fe5bf4d976db.png

Motor Control#

result = nvlm.text("motor execution").to_brain(head="mse")
result.plot(threshold=0.2, title="Motor Execution");
../_images/666d2150729318acd13e4e5fba8952a5606f6b516d4131c9161e9257acb2e75b.png

Language Processing#

result = nvlm.text("language comprehension").to_brain(head="mse")
result.plot(threshold=0.2, title="Language Comprehension");
../_images/bb422c11c355a502c60b9cb08c0ba7c85d51a9cf30d26c18ad92b503753555b3.png

Default Mode Network#

result = nvlm.text("default mode network").to_brain(head="mse")
result.plot(threshold=0.15, title="Default Mode Network");
../_images/9b41974639d081e13f731417488894ae6c01893ed1b33ae629d5ba5a7171cdcb.png

Working Memory#

result = nvlm.text("working memory").to_brain(head="mse")
result.plot(threshold=0.2, title="Working Memory");
../_images/176726d814f45787f7a0bd25f2ea7b52ead1a8d7b6828f9cdf99bda320c0597a.png

Emotion Processing#

result = nvlm.text("emotion regulation").to_brain(head="mse")
result.plot(threshold=0.15, title="Emotion Regulation");
../_images/18c917ef08d96473c3c09989b43bceb98ec1616aba99f6f9778fc2ec06a2464d.png

3. Batch Generation#

Generate multiple brain maps at once for efficiency.

# Generate maps for multiple cognitive functions
queries = [
    "visual attention",
    "auditory processing"
]

result = nvlm.text(queries).to_brain(head="mse")

# Get all NIfTI images
images = result.to_nifti()
print(f"Generated {len(images)} brain maps")
Generated 2 brain maps
# Plot each generated map
for i, query in enumerate(queries):
    result.plot(index=i, threshold=0.2, title=query);
../_images/556bf0cd1fc68e50b191a572bf5580854d162da70cfea2deb0b61e65af0785d1.png ../_images/2b03ff7d3fd179b50d06421ada343b6608af67c44d93fc5adbb6f9948dc184db.png

4. Using Scientific Abstracts#

You can generate brain maps from longer, more detailed text like scientific abstracts.

from neurovlm.data import load_dataset

# Load the PubMed dataset and pick a test-set example
pubmed = load_dataset("pubmed_text")
test_df = pubmed[pubmed["test"] == True].dropna(subset=["name", "description"])
row = test_df.iloc[20]

abstract = row["description"]
title = row["name"]
print(f"PMID: {row['pmid']}")
print(f"Title: {title}\n")
print(f"Abstract:\n{abstract}")

result = nvlm.text(abstract).to_brain(head="mse")
result.plot(threshold=0.1, title=title);
PMID: 21784106
Title: Age differences in spatial working memory contributions to visuomotor adaptation  and transfer.

Abstract:
Throughout our life span we encounter challenges that require us to adapt to the demands of our changing environment; this entails learning new skills. Two primary components of motor skill learning are motor acquisition, the initial process of learning the skill, and motor transfer, when learning a new skill is benefitted by the overlap with a previously learned one. Older adults typically exhibit declines in motor acquisition compared to young adults, but remarkably, do not demonstrate deficits in motor transfer [10]. Our recent work demonstrates that a failure to engage spatial working memory (SWM) is associated with skill learning deficits in older adults [16]. Here, we investigate the role that SWM plays in both motor learning and transfer in young and older adults. Both age groups exhibited performance savings, or positive transfer, at transfer of learning for some performance variables. Measures of spatial working memory performance and reaction time correlated with both motor learning and transfer for young adults. Young adults recruited overlapping brain regions in prefrontal, premotor, parietal and occipital cortex for performance of a SWM and a visuomotor adaptation task, most notably during motor learning, replicating our prior findings [12]. Neural overlap between the SWM task and visuomotor adaptation for the older adults was limited to parietal cortex, with minimal changes from motor learning to transfer. Combined, these results suggest that age differences in engagement of cognitive strategies have a differential impact on motor learning and transfer.
../_images/5a2f5705d416d6bafc143987b27e1a59e9d79b721c0c4903252759fe62ea99a0.png

5. Saving Generated Maps#

Export generated brain maps as NIfTI files for further analysis.

import nibabel as nib
from pathlib import Path

# Generate a brain map
result = nvlm.text("attention network").to_brain(head="mse")
nifti_img = result.to_nifti(index=0)

# Save to file
output_dir = Path("generated_maps")
output_dir.mkdir(exist_ok=True)
nib.save(nifti_img, output_dir / "attention_network.nii.gz")
print(f"Saved to {output_dir / 'attention_network.nii.gz'}")
Saved to generated_maps/attention_network.nii.gz

Batch save multiple maps#

# Generate multiple maps
cognitive_functions = [
    "sensorimotor processing",
    "cognitive control",
    "memory encoding",
    "reward processing"
]

result = nvlm.text(cognitive_functions).to_brain(head="mse")
images = result.to_nifti()

# Save each map
for i, (query, img) in enumerate(zip(cognitive_functions, images)):
    filename = query.replace(" ", "_") + ".nii.gz"
    nib.save(img, output_dir / filename)
    print(f"Saved: {filename}")
Saved: sensorimotor_processing.nii.gz
Saved: cognitive_control.nii.gz
Saved: memory_encoding.nii.gz
Saved: reward_processing.nii.gz

6. Comparing Generative vs. Retrieval#

Let’s compare brain maps generated from text vs. maps retrieved from datasets.

query = "motor cortex"

# Generate a brain map
generated = nvlm.text(query).to_brain(head="mse")

# Retrieve similar maps
retrieved = nvlm.text(query).to_brain(head="infonce", dataset="networks")

print("=== Generated Map ===")
generated.plot(threshold=0.25, title=f"Generated: {query}");

print("\n=== Retrieved Map ===")
top = retrieved.top_k(1)
print(top)
top.plot_row(0, threshold=0.1, title="Retrieved: Most similar network");
=== Generated Map ===

=== Retrieved Map ===
    dataset  dataset_index  title    description  cosine_similarity
0  networks            130  WashU  Effector-hand           0.460576
../_images/d0ca2a3a929077d33a8336893ff8a1b99a73483630bed228659daaebc0dc6ce9.png ../_images/5d4264b87543cc6d019dc415215eb314a96af4aa4ad7fdfa4e98b3b15cce7cd4.png

7. Advanced: Using Different Display Modes#

from nilearn import plotting

result = nvlm.text("auditory cortex").to_brain(head="mse")
img = result.to_nifti(index=0)

# Ortho view (default)
plotting.plot_stat_map(
    img, threshold=0.2, display_mode="ortho",
    title="Auditory Cortex - Ortho View", cmap="hot"
);
../_images/a33eeb5bae2607642c26ab0f7d58c51bdda07e95bb17bde2a25f15cc671a01d9.png
# Z slices
plotting.plot_stat_map(
    img, threshold=0.2, display_mode="z",
    cut_coords=5, title="Auditory Cortex - Axial Slices", cmap="hot"
);
../_images/300d5d3d4c33a14dd431e2b67586e4d05b46707c860ce4a6e291b2637e0b3c17.png
# Glass brain
plotting.plot_glass_brain(
    img, threshold=0.2, display_mode="lyrz",
    title="Auditory Cortex - Glass Brain", cmap="hot"
);
../_images/de7445e7cde9734c7612e9c8fea8699a851f0a1676e22331e3b46718d34bcc98.png

8. Exploring Specific Regions#

result.generated_flatmaps[0].quantile(0.95)
tensor(0.1665)
# Generate maps for specific brain regions
regions = [
    "prefrontal cortex",
    "hippocampus",
    "amygdala",
    "cerebellum"
]

for region in regions:
    result = nvlm.text(region).to_brain(head="mse")
    threshold = float(result.generated_flatmaps[0].quantile(0.90))
    result.plot(threshold=threshold, title=region.title());
../_images/31c5fc3d6ca2f9c4cefeabdc369c5861932151c40378ac788fea68e45d917e5b.png ../_images/4fb350c5d3413bdf5b4a0c752ed79b600ba15a91e2cc6e5efbbe1e41f0263f0b.png ../_images/9a9db1d4653a6de6441b3991b8c4480a0ae8b97b110906412499f5f8f20ab246.png ../_images/214a66c0828f2dfcb03bd21d1f8649b674a5af6efba81182ab3c093630b432d9.png

9. Clinical Applications#

Generate activation patterns related to clinical conditions.

# Example: Disorders or symptoms
clinical_queries = [
    "anxiety processing",
    "addiction",
    "Parkinsons disease",
    "chronic pain"
]

for query in clinical_queries:
    result = nvlm.text(query).to_brain(head="mse")
    threshold = float(result.generated_flatmaps[0].quantile(0.95))
    result.plot(threshold=threshold, title=query.title());
../_images/c3cc8c375b90269c100487772f7ec9276157b574b9423ec3925b9d9acfc6c9db.png ../_images/e448418d0301ed084e018ae581789aa498feb94abb066d6e80468c3927ca5c09.png ../_images/d05c9411f4f17eb5c07f96e3db456cdd42bec70459dd352c9d38a2d104f54b0b.png ../_images/507e825556d5719b2d4b764bdc43b102968da1fc2e42e88b9bfc153260a07c74.png

10. Summary#

In this tutorial, you learned:

  1. Basic text-to-brain generation using head="mse"

  2. Generating maps for various cognitive concepts:

    • Vision, motor, language, memory, emotion

  3. Batch generation for multiple queries

  4. Using scientific abstracts as input

  5. Saving generated maps as NIfTI files

  6. Comparing generative vs. retrieval approaches

  7. Visualization options (ortho, slices, glass brain)

  8. Clinical applications

Key Differences:

  • Generative (MSE): Creates new brain maps from text, useful for hypothesis generation

  • Retrieval (InfoNCE): Finds existing maps from datasets, useful for finding real examples

Next: In Tutorial 4, you’ll learn how to generate text descriptions from brain activation maps using language models.