NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects.
The 8 matches
- [1] § Results › Quantitative Results ↔ matrices.ipynb, lines 338–404 · score 0.92 · EffNet, Inception v3, EfficientNet, SwAV distance, AlexNet, PixCorr
- [2] § Methods › Visual Reconstruction via Ridge-refined Embeddings and IP-Adapter-SDXL ↔ GOD_dataloader.ipynb, lines 128–182 · score 0.91 · classifier free guidance, Stable Diffusion XL, adapter_sdxl.bin, IP Adapter scale, inference, float16
- [3] § Methods › Visual Reconstruction via Ridge-refined Embeddings and IP-Adapter-SDXL ↔ cross_model_aligment.ipynb, lines 382–399 · score 0.81 · Stable Diffusion XL, adapter_sdxl.bin, IP Adapter scale, float16, h94, refined
- [4] § Results ↔ cross_model_aligment.ipynb, lines 181–301 · score 0.79 · AdamW, weight decay, Lightning, temperature, validation, GELU
- [5] § Methods › Overview ↔ GOD_dataloader.ipynb, lines 128–182 · score 0.75 · stable diffusion XL, sdxl bin, sdxl models, IP Adapter, h94, image embedding
- [6] § Methods › Overview ↔ cross_model_aligment.ipynb, lines 382–399 · score 0.74 · stable diffusion XL, sdxl bin, sdxl models, IP Adapter, h94, weights
- [7] § Methods › Cross-subject and Cross-dataset Neural Vision Alignment ↔ cross_model_aligment.ipynb, lines 181–301 · score 0.71 · cross entropy, contrastive loss, temperature, optimization, module, batch
- [8] § Results › Quantitative Results ↔ matrices.ipynb, lines 338–404 · score 0.58 · AlexNet, PixCorr, Inception, SSIM, efficiency, metrics
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 399 lines · 15 KB · no license · 4 matches
- # %% [markdown]
- # ## Loading Libraries and data
- # %%
- import torch
- import numpy as np
- from torch.utils.data import DataLoader, TensorDataset
- import warnings
- warnings.filterwarnings('ignore')
- device = torch.device("cuda:2" if torch.cuda.is_available() else "cpu")
- # %%
- ## Loading BOLD5000 data
- BOLD_brain_signals_train = torch.load("/BOLD5000/data_augmentation/train_25percent_noise_75.pt", map_location=device)
- # BOLD_brain_signals_train = torch.load("/BOLD5000_V2/brain_signals_train.pt", map_location=device)
- BOLD_brain_signals_test = torch.load("/BOLD5000_V2/brain_signals_test.pt", map_location=device)
- # BOLD_brain_signals_train = torch.from_numpy(BOLD_brain_signals_train).to(device)
- BOLD_brain_signals_test = torch.from_numpy(BOLD_brain_signals_test).to(device)
- # Normalizing the BOLD signals
- mean = BOLD_brain_signals_train.mean(0)
- std = BOLD_brain_signals_train.std(0)
- BOLD_brain_signals_train = (BOLD_brain_signals_train - mean) / std
- BOLD_brain_signals_test = (BOLD_brain_signals_test - mean) / std
- BOLD_brain_signals_train = torch.nan_to_num(BOLD_brain_signals_train)
- BOLD_brain_signals_test = torch.nan_to_num(BOLD_brain_signals_test)
- BOLD_stimulus_embeddings_train = torch.load( "/BOLD5000/data_augmentation/train_embds_25percent.pt", map_location=device)
- # BOLD_stimulus_embeddings_train = torch.load( "/BOLD5000_V2/image_embeddings_train.pt", map_location=device)
- BOLD_stimulus_embeddings_test = torch.load("/BOLD5000_V2/image_embeddings_test.pt", map_location=device)
- BOLD_subject_ids_train = torch.load("/BOLD5000/data_augmentation/train_ids_25percent.pt", map_location=device)
- # BOLD_subject_ids_train = torch.load("/BOLD5000_V2/subject_ids_train.pt", map_location=device)
- BOLD_subject_ids_train = torch.tensor(BOLD_subject_ids_train).to(device)
- BOLD_subject_ids_test = torch.load("/BOLD5000_V2/subject_ids_test.pt", map_location=device)
- # Convert BOLD5000 brain signals to tensor
- BOLD_brain_signals_train = torch.tensor(BOLD_brain_signals_train).float()
- BOLD_brain_signals_test = torch.tensor(BOLD_brain_signals_test).float()
- # Extract CLIP embeddings from BOLD5000
- BOLD_stimulus_embeddings_train = BOLD_stimulus_embeddings_train[:, 1, 0].float()
- BOLD_stimulus_embeddings_test = BOLD_stimulus_embeddings_test[:, 1, 0].float()
- # %%
- BOLD_brain_signals_train.shape, BOLD_stimulus_embeddings_train.shape, BOLD_subject_ids_train.shape, BOLD_brain_signals_test.shape, BOLD_stimulus_embeddings_test.shape, BOLD_subject_ids_test.shape
- # %%
- #Loading NSD dataset
- NSD_train_data = torch.load("/decoding_NSD/data_augmentation/train_25percent_noise_50.pt").to(device).float()
- NSD_test_data = np.load("/decoding_NSD/data_fmri_nsd/test_data.npy")
- NSD_test_data = torch.from_numpy(NSD_test_data).to(device).float()
- mean = NSD_train_data.mean(0)
- std = NSD_train_data.std(0)
- NSD_train_data = (NSD_train_data - mean) / std
- NSD_test_data = (NSD_test_data - mean) / std
- NSD_train_data = torch.nan_to_num(NSD_train_data)
- NSD_test_data = torch.nan_to_num(NSD_test_data)
- NSD_train_img_embeds = torch.load("/decoding_NSD/data_augmentation/train_embds_25percent.pt", map_location=device)
- NSD_test_img_embeds = torch.load("/decoding_NSD/data_fmri_nsd/test_clip_img_embeds.pt", map_location=device)
- NSD_train_img_embeds = NSD_train_img_embeds[:, 1, 0].float()
- NSD_test_img_embeds = NSD_test_img_embeds[:, 1, 0].float()
- NSD_subject_train_ids = torch.load("/decoding_NSD/data_augmentation/train_ids_25percent.pt")
- NSD_subject_test_ids = np.load("/decoding_NSD/data_fmri_nsd/subject_test_ids.npy")
- # NSD_subject_train_ids=[int(i[-1]) for i in NSD_subject_train_ids]
- NSD_subject_test_ids=[int(i[-1]) for i in NSD_subject_test_ids]
- NSD_subject_train_ids = torch.from_numpy(np.array(NSD_subject_train_ids)).to(device)
- NSD_subject_test_ids = torch.from_numpy(np.array(NSD_subject_test_ids)).to(device)
- # %%
- #Loading GOD dataset
- GOD_train_brain_signals = torch.load('/GOD/train_brain_signals.pt').to(device)
- GOD_test_brain_signals = torch.load('/GOD/test_brain_signals.pt').to(device)
- mean = GOD_train_brain_signals.mean(0)
- std = GOD_train_brain_signals.std(0)
- GOD_train_brain_signals = (GOD_train_brain_signals - mean) / std
- GOD_test_brain_signals = (GOD_test_brain_signals - mean) / std
- GOD_train_brain_signals = torch.nan_to_num(GOD_train_brain_signals).float()
- GOD_test_brain_signals = torch.nan_to_num(GOD_test_brain_signals).float()
- GOD_train_image_embds = torch.load('/GOD/train_image_embeddings.pt', map_location=device)
- GOD_test_image_embds = torch.load('/GOD/test_image_embeddings.pt', map_location=device)
- GOD_train_image_embds = GOD_train_image_embds[:, 1, 0].float()
- GOD_test_image_embds = GOD_test_image_embds[:, 1, 0].float()
- GOD_train_subject_ids = torch.load('/GOD/train_subject_ids.pt', map_location=device)
- # GOD_train_subject_ids = torch.tensor(GOD_train_subject_ids).to(device)
- GOD_test_subject_ids = torch.load('/GOD/test_subject_ids.pt', map_location=device)
- GOD_train_brain_signals.shape, GOD_train_image_embds.shape, GOD_train_subject_ids.shape, GOD_test_brain_signals.shape, GOD_test_image_embds.shape, GOD_test_subject_ids.shape
- # %%
- # Concatenate datasets
- cross_train_data = torch.cat([NSD_train_data, BOLD_brain_signals_train, GOD_train_brain_signals], dim=0)
- cross_test_data = torch.cat([NSD_test_data, BOLD_brain_signals_test, GOD_test_brain_signals], dim=0)
- cross_train_embeds = torch.cat([NSD_train_img_embeds, BOLD_stimulus_embeddings_train, GOD_train_image_embds], dim=0)
- cross_test_embeds = torch.cat([NSD_test_img_embeds, BOLD_stimulus_embeddings_test, GOD_test_image_embds], dim=0)
- cross_train_subjects = torch.cat([torch.tensor(NSD_subject_train_ids, device=device), torch.tensor(BOLD_subject_ids_train, device=device), torch.tensor(GOD_train_subject_ids, device=device)], dim=0)
- cross_test_subjects = torch.cat([torch.tensor(NSD_subject_test_ids, device=device), torch.tensor(BOLD_subject_ids_test, device=device), torch.tensor(GOD_test_subject_ids, device=device)], dim=0)
- # %% [markdown]
- # ## Defining model
- # %%
- import torch
- import torch.nn as nn
- import pytorch_lightning as pl
- class Encoder(nn.Module):
- def __init__(self, input_dim, hidden_dims, output_dim, act_fn=nn.ReLU, alignment_layers_keys=[12, 13, 14, 15, 16], common_dim=1024): #, 1, 2, 5, 7, 8, 9, 10, 11
- super(Encoder, self).__init__()
- self.common_dim = common_dim
- self.alignment_layers = nn.ModuleDict({str(k): nn.Linear(input_dim, common_dim) for k in alignment_layers_keys})
- self.dropout = nn.Dropout(p=0.3)
- # Transformer Encoder
- self.transformer = nn.TransformerEncoder(
- nn.TransformerEncoderLayer(d_model=common_dim, nhead=8, dim_feedforward=2048, activation='gelu'),
- num_layers=4
- )
- layers = [nn.LayerNorm(common_dim)]
- prev_dim = common_dim
- for hidden_dim in hidden_dims:
- layers.append(nn.Linear(prev_dim, hidden_dim))
- layers.append(nn.LayerNorm(hidden_dim))
- layers.append(act_fn())
- layers.append(nn.Linear(hidden_dim, prev_dim)) #Residual Connections
- prev_dim = hidden_dim
- layers.append(nn.Linear(prev_dim, output_dim))
- layers.append(nn.LayerNorm(output_dim))
- self.net = nn.Sequential(*layers)
- # Alignment layer
- self.alignment_layer = nn.Linear(output_dim, output_dim)
- def forward(self, x, k=None):
- if k is None:
- k = torch.ones(len(x), dtype=torch.long)
- result = torch.zeros(len(x), self.common_dim, device=x.device)
- for key in k.unique():
- mask = (k == key)
- result[mask] = self.alignment_layers[str(key.item())](x[mask])
- # result[mask] = self.dropout(result[mask]) #add dropoutout
- # # Add Transformer encoding here
- result = result.unsqueeze(1) # Add sequence dimension for Transformer (batch, seq_len, features)
- result = self.transformer(result)
- result = result.squeeze(1) # Remove sequence dimension
- #Alignment layer
- aligned_result = self.net(result)
- aligned_result = self.alignment_layer(aligned_result)
- return aligned_result #self.net(result)
- class ContrastiveModel(pl.LightningModule):
- def __init__(self, num_input_channels, base_channel_size, latent_dim, temperature=0.1, act_fn=nn.GELU, loss_type="contrastive"):
- super().__init__()
- self.temperature = temperature
- self.model = Encoder(num_input_channels, base_channel_size, latent_dim, act_fn)
- self.loss_type = loss_type
- if loss_type == "contrastive":
- self.loss_fn = self.contrastive_loss
- elif loss_type == "mean_contrastive":
- self.loss_fn = self.mean_contrastive
- elif loss_type == "mse":
- self.loss_fn = torch.nn.functional.mse_loss
- elif loss_type == "cosine":
- self.loss_fn = self.cosine_loss
- self.train_losses = []
- self.train_mse = []
- self.train_cosine = []
- self.val_losses = []
- self.val_mse = []
- self.val_cosine = []
- self.train_history = {
- "train_loss": [],
- "train_mse": [],
- "train_cosine": []
- }
- self.val_history = {
- "val_loss": [],
- "val_mse": [],
- "val_cosine": []
- }
- def forward(self, x, **kwargs):
- return self.model(x, **kwargs)
- def contrastive_loss(self, z_i, z_j):
- z_i = nn.functional.normalize(z_i, dim=1)
- z_j = nn.functional.normalize(z_j, dim=1)
- logits = (z_i @ z_j.T) / self.temperature
- targets = torch.arange(logits.shape[0]).long().to(logits.device)
- # Original cross-entropy loss
- loss1 = torch.nn.functional.cross_entropy(logits, targets)
- # Transposed cross-entropy loss
- loss2 = torch.nn.functional.cross_entropy(logits.T, targets)
- # Combined loss
- loss = 0.5 * loss1 + 0.5 * loss2
- return loss
- def mean_contrastive(self, z_i, z_j, temperature=1.0):
- return nn.functional.mse_loss(z_i, z_j) + self.contrastive_loss(z_i, z_j, temperature=temperature) / 8
- def cosine_loss(self, z_i, z_j, temperature=1.0):
- cosine_similarity = torch.nn.functional.cosine_similarity(z_i, z_j).mean()
- return 1 - cosine_similarity
- def training_step(self, batch, batch_idx):
- x, y, idx = batch #add noise inX
- noise = 0.15 * torch.randn_like(x)
- x = x + noise
- y_hat = self(x, k=idx)
- loss = self.loss_fn(y_hat, y)
- self.log('train_loss', loss, on_epoch=True, prog_bar=True)
- self.train_losses.append(loss.item())
- mse_loss = torch.nn.functional.mse_loss(y_hat, y)
- cosine_similarity = torch.nn.functional.cosine_similarity(y_hat, y).mean()
- self.train_mse.append(mse_loss.item())
- self.train_cosine.append(cosine_similarity.item())
- return loss
- def validation_step(self, batch, batch_idx):
- x, y, idx = batch
- y_hat = self(x, k=idx)
- loss = self.loss_fn(y_hat, y)
- self.log('val_loss', loss, on_epoch=True, prog_bar=True)
- mse_loss = torch.nn.functional.mse_loss(y_hat, y)
- self.log('val_mse_loss', mse_loss, on_epoch=True, prog_bar=True)
- cosine_similarity = torch.nn.functional.cosine_similarity(y_hat, y).mean()
- self.log('val_cosine_similarity', cosine_similarity, on_epoch=True, prog_bar=True)
- self.val_losses.append(loss.item())
- self.val_mse.append(mse_loss.item())
- self.val_cosine.append(cosine_similarity.item())
- return mse_loss
- def on_train_epoch_end(self):
- self.train_history["train_loss"].append(np.mean(self.train_losses))
- self.train_history["train_mse"].append(np.mean(self.train_mse))
- self.train_history["train_cosine"].append(np.mean(self.train_cosine))
- self.train_losses = []
- self.train_mse = []
- self.train_cosine = []
- super().on_train_epoch_end()
- def on_validation_epoch_end(self):
- self.val_history["val_loss"].append(np.mean(self.val_losses))
- self.val_history["val_mse"].append(np.mean(self.val_mse))
- self.val_history["val_cosine"].append(np.mean(self.val_cosine))
- self.val_losses = []
- self.val_mse = []
- self.val_cosine = []
- super().on_validation_epoch_end()
- def configure_optimizers(self):
- optimizer = torch.optim.AdamW(self.parameters(), lr=1e-4, weight_decay=1e-3)
- scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=50, verbose=True)
- return {"optimizer": optimizer, "lr_scheduler": scheduler, "monitor": "val_loss"}
- # %%
- BS = 256
- # Create the final dataset
- train_dataset = TensorDataset(cross_train_data, cross_train_embeds, cross_train_subjects)
- test_dataset = TensorDataset(cross_train_data, cross_test_embeds, cross_test_subjects)
- # Create DataLoaders
- train_dataloader = DataLoader(train_dataset, batch_size=BS, shuffle=True)
- test_dataloader = DataLoader(test_dataset, batch_size=BS, shuffle=False)
- # %%
- brain_model = ContrastiveModel(num_input_channels=cross_train_data.shape[-1], base_channel_size=[1024], latent_dim=1280, act_fn=nn.GELU, loss_type="contrastive")
- trainer = pl.Trainer(max_epochs=10, devices=[2])
- # Train the model
- trainer.fit(brain_model, train_dataloader, test_dataloader)
- # %%
- #RIDGE REGRESION
- from sklearn.linear_model import Ridge
- train_pred_embeddings = []
- train_gt_embeddings = []
- brain_model.eval()
- with torch.no_grad():
- for x, y, k in train_dataloader:
- x = x.to("cpu")
- y = y.to("cpu")
- k = k.to("cpu")
- y_hat = brain_model(x, k=k)
- train_pred_embeddings.append(y_hat.cpu().numpy())
- train_gt_embeddings.append(y.cpu().numpy())
- train_pred_embeddings = np.vstack(train_pred_embeddings)
- train_gt_embeddings = np.vstack(train_gt_embeddings)
- # Train Ridge regression model
- ridge_reg = Ridge(alpha=50000.0)
- ridge_reg.fit(train_pred_embeddings, train_gt_embeddings)
- # Predict embeddings for the test set
- test_pred_embeddings = []
- with torch.no_grad():
- for x, y, k in test_dataloader:
- x = x.to("cpu")
- y = y.to("cpu")
- k = k.to("cpu")
- y_hat = brain_model(x, k=k)
- test_pred_embeddings.append(y_hat.cpu().numpy())
- test_pred_embeddings = np.vstack(test_pred_embeddings)
- # Apply Ridge regression on the test set embeddings
- refined_test_embeddings = ridge_reg.predict(test_pred_embeddings)
- # Convert refined embeddings to tensor
- refined_test_embeddings = torch.tensor(refined_test_embeddings).float()
- # %%
- BOLD_stimulus_embeddings_test = BOLD_stimulus_embeddings_test.to("cpu")
- BOLD_pred_IP = refined_test_embeddings.to("cpu")
- # %%
- NSD_stimulus_embeddings_test = NSD_test_img_embeds.to("cpu")
- NSD_pred_IP = refined_test_embeddings.to("cpu")
- # %%
- GOD_stimulus_embeddings_test = GOD_test_image_embds.to("cpu")
- GOD_pred_IP = refined_test_embeddings.to("cpu")
- # %%
- from diffusers import AutoPipelineForText2Image
- from diffusers.utils import load_image
- import torch
- pipeline = AutoPipelineForText2Image.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16).to("cuda:2")
- pipeline.load_ip_adapter("h94/IP-Adapter", subfolder="sdxl_models", weight_name="ip-adapter_sdxl.bin")
- pipeline.set_ip_adapter_scale(1.0)
- #RESHAPING THE EMBEDDINGS
- y_pred_IP = torch.zeros((2, refined_test_embeddings.shape[0], 1, refined_test_embeddings.shape[-1]), dtype=torch.float16)
- y_pred_IP[1] = refined_test_embeddings.unsqueeze(1)
- y_pred_IP[0] = torch.zeros_like(refined_test_embeddings.unsqueeze(1))
- y_pred_IP = y_pred_IP.transpose(0,1)
- y_pred_IP.shape
- torch.save(y_pred_IP, "New_results/BOLD_predicted_embeddings_08042025.pt")
cross_model_aligment.ipynb at commit a011911, no license · at the source
Overview
- Department of Biomedicine and Prevention, University of Rome Tor Vergata,Rome, Italy
- Martinos Center for Biomedical Imaging, MGH and Harvard Medical School,Boston, MA USA
Abstract
Recent advancements in neural decoding have shown promising results in reconstructing visual experiences from brain activity. However, existing approaches focus primarily on decoding within a single dataset or subject, which limits generalization across various sources of neuroimaging. In this work, we propose a novel framework for the decoding of visual stimuli between subjects and between data sets, integrating neural recordings from multiple publicly available fMRI datasets. To address inherent intersubject and interdataset variability, we introduce a contrastive learning-based alignment strategy using image embeddings from a pre-trained IP-Adapter model. Our approach learns a shared latent space by aligning subject-specific neural representations with image features, enabling generalized decoding across both subjects and datasets. In addition, we propose a simple yet effective data augmentation method using ridge regression. This method synthesizes realistic fMRI-like signals from novel images by predicting voxel activity and injecting learned noise distributions, thus enhancing training diversity and model robustness. To the best of our knowledge, while several recent studies have explored cross-subject decoding, we extend recent cross-subject decoding efforts by training a single unified framework jointly across multiple public fMRI datasets and subjects, enabling cross-dataset transfer in addition to cross-subject generalization. We distinguish this multi-dataset unified training setting, where each dataset contributes training data, from a stricter leave-one-dataset-out transfer setting in which the target dataset is excluded from source pretraining and used only for lightweight alignment-layer adaptation. Empirically, our unified model achieves strong semantic reconstruction across datasets (e.g., up to 94.8% CLIP similarity on NSD (AUG) and 0.403 SSIM on BOLD5000 after lightweight finetuning), demonstrating robust cross-subject and cross-dataset transfer.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 8 matches between paragraphs and lines of code.
r8832711/Cross-subject-and-cross-dataset-brain-decoding
a01191158a14df08c24d5309953614d1fc9ab025, 15 May 2025Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
10 files
- BOLD5000_data_augmentati
on.ipynb , Jupyter, 265 lines - GOD_SemanticDecoding.ipy
nb , Jupyter, 126 lines - GOD_data_augmentation.ip
ynb , Jupyter, 254 lines - GOD_dataloader.ipynb, Jupyter, 205 lines, 2 matches
- GOD_decoding_utils.py, Python, 333 lines
- NSD_data_augmentation.ip
ynb , Jupyter, 224 lines - NSD_dataloader_utils.ipy
nb , Jupyter, 232 lines - cross_model_aligment.ipy
nb , Jupyter, 399 lines, 4 matches - matrices.ipynb, Jupyter, 498 lines, 2 matches
- README.md, Text, 56 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 9 scripts, each with its path and the digest of its content;
- 8 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- bold5000-dataset.github.
io/ , at bold5000-dataset.github.io; found in “Data Availability”website - openneuro:ds001246, at OpenNeuro; found in “Information Sharing Statement”
Data Availability
The NSD (Natural Scenes Dataset) version 1.0 used in this study is publicly available at https://
The BOLD5000 dataset used in this study is publicly available at https://
The GOD (Generic Object Decoding) dataset version 1.2.1 used in this study is available from OpenNeuro at https://
The code used in this study has been anonymously uploaded to GitHub and is available at: https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 2, 28 September 2026
- Publisher: n/a → Springer Science+Business Media
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 3 authors, 8 keywords, 9 MeSH terms, 1 funder, 33 references.
Cite
This paper
Kashif, M., Ferrante, M., & Toschi, N. (2026). NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects. Neuroinformatics, 24(3), 45. https://
BibTeX
@article{kashif2026neuro
author = {Kashif, Muhammad and Ferrante, Matteo and Toschi, Nicola},
title = {{NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects}},
journal = {Neuroinformatics},
year = {2026},
month = jul,
volume = {24},
number = {3},
pages = {45},
publisher = {Springer Science+Business Media},
issn = {1539-2791},
doi = {10.1007/
url = {https://
pmid = {42469516},
pmcid = {PMC13379418}
}
RIS
TY - JOUR
AU - Kashif, Muhammad
AU - Ferrante, Matteo
AU - Toschi, Nicola
TI - NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects
T2 - Neuroinformatics
J2 - Neuroinformatics
PY - 2026
DA - 2026/
VL - 24
IS - 3
SP - 45
SN - 1539-2791
PB - Springer Science+Business Media
DO - 10.1007/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1007/
"type": "article-journal",
"title": "NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects",
"container-title": "Neuroinformatics",
"author": [
{
"family": "Kashif",
"given": "Muhammad"
},
{
"family": "Ferrante",
"given": "Matteo"
},
{
"family": "Toschi",
"given": "Nicola"
}
],
"container-title-short":
"volume": "24",
"issue": "3",
"page": "45",
"DOI": "10.1007/
"PMID": "42469516",
"PMCID": "PMC13379418",
"ISSN": "1539-2791",
"publisher": "Springer Science+Business Media",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
18
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1162/imag.a.1299 [code]
- A modular semantic-structural pipeline for visual decoding from primate spiking data via selective temporal integration.Journal: Imaging neuroscience (Cambridge, Mass.)In common: PyTorch Lightning, scikit-image, h5py, 7 other tools, methods / tools, 8 references
- [2] doi:10.7554/elife.107933 [code]
- Modality-agnostic decoding of vision and language from fMRI.Journal: eLifeIn common: Nilearn, scikit-image, h5py, 8 other tools, fMRI, 7 references
- [3] doi:10.1371/journal.pcbi.1014263 [code]
- MIRAGE: Robust multi-modal architectures translate fMRI-to-image models from vision to mental imagery.Journal: PLoS computational biologyIn common: PyTorch Lightning, scikit-image, h5py, 8 other tools, fMRI, 6 references
- [4] doi:10.1038/s41597-026-06869-1 [code]
- Individual Brain Charting: fifth release of high-resolution fMRI data for cognitive mapping.Journal: Scientific dataIn common: Nilearn, scikit-image, Pillow, 6 other tools, fMRI, methods / tools, 4 references
- [5] doi:10.1038/s41597-026-07248-6 [code]
- A large-scale fMRI dataset for vision-language semantic association.Journal: Scientific dataIn common: Nilearn, scikit-image, h5py, 8 other tools, fMRI, methods / tools, 2 references
- [6] doi:10.1038/s41597-025-05174-7 [code]
- A large-scale MEG and EEG dataset for object recognition in naturalistic scenesJournal: n/aIn common: MNE-BIDS, MNE-Python, h5py, 8 other tools, fMRI, methods / tools, 1 reference
- [7] doi:10.1016/j.isci.2026.117180 [code]
- Developmental changes in similarity between neural representations of mental arithmetic and artificial neural networks.Journal: iScienceIn common: Nilearn, h5py, NiBabel, 6 other tools, fMRI, 3 references
- [8] doi:10.1523/jneurosci.0038-26.2026 [code]
- Multidimensional Feature Tuning in Category Selective Areas of Human Visual Cortex.Journal: The Journal of neuroscience : the official journal of the Society for NeuroscienceIn common: h5py, Pillow, NiBabel, 6 other tools, fMRI, 3 references
- [9] doi:10.1162/imag.a.1286 [code]
- Behavioral imitation with artificial neural networks leads to personalized models of brain dynamics during videogame play.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Nilearn, h5py, Pillow, 7 other tools, fMRI, 2 references
- [10] doi:10.1162/nol.a.271 [code]
- Compositional Complexity in Text and Images.Journal: Neurobiology of language (Cambridge, Mass.)In common: Nilearn, Pillow, NiBabel, 6 other tools, fMRI, 3 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 9 scripts, and 8 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:26853eaa181d8a0e…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
