神经科学 AI 这两年确实被很多科研团队盯上了,但真正劝退的往往不是算法,而是 fMRI 数据从“原始扫描”到“可训练张量”这条链路上的各种坑。这次我们直接拆一个比较完整的落地路径:脑影像数据怎么做预处理、怎么进入深度学习模型、怎么在单卡 GPU 上完成小规模实验、以及后续如何封装成批量处理和 API 服务。本文不会只停留在“深度学习很强”的概念层面,而是把数据、环境、代码、验证和排错放在一起,给出一套可以照着跑的方案。
为什么要单独提 fMRI?因为功能性磁共振成像并不是一张普通图片,它本质上是“体素(voxel)× 时间点”的四维数据,单被试扫描动辄几个 GB,多被试实验跑下来就是几十 TB。传统统计分析需要做运动校正、时间层校正、配准、平滑,而深度学习介入后,这些预处理步骤的结果会直接影响模型能学到什么。所以,做神经影像深度学习的第一步不是急着调网络结构,而是先把数据管线和计算环境稳住。
这篇文章适合三类读者:正在做神经影像分析但想引入深度学习的研究生;准备在企业里做脑电、功能影像相关 AI 产品但需要理清技术边界的技术人员;以及单纯想了解医学深度学习为什么在脑科学赛道里被看好、想知道从哪开始学的入门者。
1. 神经科学 AI 核心能力速览
| 能力项 | 说明 |
|---|---|
| 数据类型 | 功能磁共振成像(fMRI)、T1 结构像、任务态与静息态数据 |
| 核心任务 | 疾病分类、认知状态解码、脑区定位、功能连接分析、脑龄预测、跨模态融合 |
| 常见框架 | PyTorch、MONAI、NiBabel、nilearn、fMRIPrep 等 |
| 推荐硬件 | NVIDIA 单卡 GPU(显存 8GB 起步更稳妥;显存占用需按实际模型和数据量测试) |
| 启动方式 | Jupyter Notebook 交互式分析 / Python 脚本执行 / Flask API 服务 |
| 是否支持批量任务 | 可以,fMRI 建模天然适合按被试批量处理,但要设计队列与失败重试 |
| 是否支持 API | 可以,训练后的模型可以封装为推理接口 |
| 适合场景 | 科研分析、临床辅助诊断研究、认知解码实验、多模态特征融合 |
需要先说明一点:fMRI 深度学习并没有“一个包解决所有问题”的万能工具,真正成熟的流程是把几个开源工具串起来,比如dcm2niix做格式转换、fMRIPrep做预处理、nilearn做特征提取、PyTorch做模型训练。下面所有步骤都会按照这个链路线性展开。
2. 医学深度学习在神经影像中的真正价值
很多人把深度学习想象成“输入脑图,输出诊断”的黑盒,但神经影像 AI 的价值远不止分类准确率。从公开文献和实际科研项目来看,fMRI 深度学习的核心能力集中在以下几个方向。
2.1 从体素级探索到全脑连接建模
传统 fMRI 分析通常先定义感兴趣区域(ROI),然后看这些区域在不同条件下的激活差异。深度学习则可以直接在体素级别输入全脑数据,让模型自己发现哪些空间模式和时间模式存在判别信息,尤其对静息态功能连接(RSFC)的建模很有效。常见做法是把每个被试的功能连接矩阵当作图像输入,用一个 2D CNN 或图神经网络完成分类或回归任务。
2.2 任务态解码与认知状态识别
任务态 fMRI 设计下,模型可以学习“某类刺激出现时全脑体素模式”到“认知标签”之间的映射,比如识别被试看到的是人脸、场景还是文字。这类实验通常被称为脑解码(brain decoding)。这类任务的优势在于样本量不需要像疾病诊断那么大,因为标签是被试内重复的试次,而不是一个疾病类别。
2.3 疾病辅助诊断与影像标记物发现
在阿尔茨海默病、精神分裂症、抑郁症等疾病研究中,深度学习经常被用来提取多模态影像特征,再结合临床量表做辅助诊断。由于医学数据获取成本高、标注要求严格,当前主流研究都在强调“可解释性”,也就是不只看模型判得准不准,还要看模型关注了哪些脑区,结果是否和已知病理机制一致。
2.4 建立因果推断与跨模态关联
fMRI 的时间分辨率不如 EEG,但空间分辨率明显更高,因此很多工作会做 fMRI 与 EEG/NIRS 的跨模态融合。深度学习在这里的角色不是替代某个模态,而是把不同时间-空间尺度整合到一个表征空间里,为后续假设检验提供更稳定特征。
2.5 使用边界必须提前划定
医学数据和普通图像生成、语音合成完全不同。只要涉及真实被试影像,就必须走伦理审查、知情同意、数据去标识化流程;公开数据集(如 ADHD-200、ABIDE、HCP)都有各自的数据使用协议,商用前要逐条核对。模型训练过程中如果出现被试身份信息可被重建的风险,需要用脱敏和噪声扰动处理。下面所有实验代码默认使用公开数据集或脱敏数据,不涉及真实临床数据上传。
3. 神经影像深度学习环境准备
神经影像深度学习的环境比普通 CV 要复杂一点,因为除了 Python 深度学习库,还需要安装神经影像专用的 I/O 和可视化工具。这里给出一套可以复用的通用准备清单。
3.1 操作系统与硬件建议
建议系统为 Ubuntu 20.04 以上或 Windows 11 + WSL2。如果只有 CPU,也可以跑通小型模型和静态连接性分析,但 3D 卷积模型会很慢;有 NVIDIA 显卡时建议使用 CUDA 11.8 或 CUDA 12.x 对应版本的 PyTorch。磁盘空间至少预留 100GB,因为公开 fMRI 数据集解压后单被试就是 1~3GB,预处理中间文件还会增加 2~4 倍。
3.2 创建 Python 虚拟环境
conda create -n neuroai python=3.10 -y conda activate neuroai不要直接把 numpy、scipy、torch 装进 base 环境,否则后面换版本很痛苦。
3.3 安装深度学习库与神经影像库
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install nibabel nilearn nipype pip install monai pip install matplotlib pandas scikit-learn pip install jupyternibabel负责读取 NIfTI 格式(.nii / .nii.gz),nilearn提供可视化、ROI 提取和连接性计算,nipype用于搭建预处理工作流,MONAI提供医学影像专用的 3D 模型和训练工具。如果网络环境下载慢,可以先下载 whl 包再本地安装,不要中途中断。
3.4 预处理工具安装与验证
预处理是 fMRI 深度学习最容易踩坑的位置,建议使用成熟工具而不是手写每个模块。
pip install fmriprepfMRIPrep 启动时会对 BIDS 数据目录做校验,所以输入数据必须符合 BIDS 命名规范。如果机器性能有限,可以先跑单被试、低分辨率测试。
4. 神经影像数据准备与 BIDS 整理
4.1 原始格式转换
医院或者扫描仪导出的数据通常是 DICOM 格式,需要先转换为 NIfTI。常用工具是dcm2niix:
dcm2niix -z y -o ./output_dir ./input_dicom_dir转换后你会得到 .nii.gz 文件、对应的 .json 元数据和可能的 .bvec / .bval 文件。这一步没有做好,后面的预处理和模型输入都会出错,所以转换后建议用nibabel看一眼 shape:
import nibabel as nib img = nib.load("./sub-01/func/sub-01_task-rest_bold.nii.gz") data = img.get_fdata() print(data.shape) # 通常是 (x, y, z, timepoints)4.2 BIDS 目录结构最小实例
project_root/ ├── dataset/ │ ├── sub-01/ │ │ ├── anat/ │ │ │ └── sub-01_T1w.nii.gz │ │ └── func/ │ │ └── sub-01_task-rest_bold.nii.gz │ ├── sub-02/ │ │ └── ... │ └── dataset_description.json ├── preprocessing/ ├── features/ ├── models/ └── results/dataset_description.json是 BIDS 格式必填文件,fMRIPrep 会检查它的存在。可以用任意编辑器创建:
{ "Name": "My fMRI Study", "BIDSVersion": "1.8.0", "DatasetType": "raw", "Authors": ["Your Name"] }4.3 运行 fMRIPrep 预处理
fmriprep dataset preprocessing \ --participant-label sub-01 \ --fs-license-file /path/to/license.txt \ --output-spaces MNI152NLin6Asym \ --nthreads 4 \ --mem_mb 8192 \ --stop-on-first-crash需要提前准备 FreeSurfer license,可以从 FreeSurfer 官网申请。--output-spaces指定空间标准化目标,MNI152 是神经元影像领域最常用的模板。
预处理跑完之后,重点检查preprocessing/sub-01/func/下是否生成了*_space-MNI152NLin6Asym_desc-preproc_bold.nii.gz文件。这个文件才是后续深度学习真正要用的张量来源。
5. 功能测试与效果验证
下面按“从基线到复杂”的顺序,设计一套可以直接执行的验证流程。所有结果判断都以输出目录是否有有效文件、指标是否符合常识为准。如果环境不同,时间会有所差异,不要去强行对齐别人测出的秒数或者显存数值,要记录自己机器上的实际值。
5.1 数据读取与可视化测试
测试目的:确认数据管线能正确读入 NIfTI,并确认体素尺寸和时间点数没有异常。
import nibabel as nib import matplotlib.pyplot as plt img = nib.load("./preprocessing/sub-01/func/sub-01_task-rest_bold_space-MNI152NLin6Asym_desc-preproc_bold.nii.gz") data = img.get_fdata() print("data shape:", data.shape) print("voxel size:", img.header.get_zooms()) middle_slice = data[:, :, data.shape[2] // 2, 0] plt.imshow(middle_slice.T, cmap="gray", origin="lower") plt.axis("off") plt.savefig("./results/sub01_slice_check.png", dpi=150)成功标准:打印出的 shape 是四维,脑影像切片看起来是左右翻转正常的轴向视图。
5.2 全脑功能连接矩阵计算
测试目的:验证能否从预处理后的 BOLD 时间序列中提取有意义的脑区连接矩阵。这一步是很多下游分类任务的标配特征。
from nilearn import datasets, image, connectome from nilearn.maskers import NiftiLabelsMasker atlas = datasets.fetch_atlas_schaefer_2018(n_rois=400) masker = NiftiLabelsMasker(atlas.maps, standardize=True, memory="nilearn_cache") bold_path = "./preprocessing/sub-01/func/sub-01_task-rest_bold_space-MNI152NLin6Asym_desc-preproc_bold.nii.gz" timeseries = masker.fit_transform(bold_path) correlation = connectome.ConnectivityMeasure(kind="correlation").fit_transform([timeseries])[0] print("connectivity matrix shape:", correlation.shape)成功标准:得到 400×400 的矩阵,数值范围大体在 -1 到 1 之间。如果矩阵中大量数值为 0,说明掩膜与数据空间没有对齐,需要检查--output-spaces的设置。
5.3 小规模疾病分类基线实验
测试目的:打通“特征→模型→评估”这条最简流程。这里使用公开数据集的连接矩阵做分类,避免直接从原始体素训练导致显存不够。
import numpy as np from sklearn.model_selection import cross_val_score from sklearn.svm import SVC from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler # X: (n_subjects, n_rois * (n_rois - 1) / 2) 连接特征 # y: (n_subjects,) 标签 X = np.load("./features/connectivity_features.npy") y = np.load("./features/labels.npy") # 取矩阵上三角作为特征 n_rois = 400 indices = np.triu_indices(n_rois, k=1) X_vec = np.array([mat[indices] for mat in X]) clf = make_pipeline(StandardScaler(), SVC(kernel="linear", class_weight="balanced")) scores = cross_val_score(clf, X_vec, y, cv=5, scoring="accuracy") print("CV accuracy: {:.3f} ± {:.3f}".format(scores.mean(), scores.std()))成功标准:五折交叉验证能跑通并输出均值和标准差。如果模型仅比随机略好,不代表流程错误,可能与样本量和类别平衡有关。
5.4 体素级 3D CNN 训练实验
当连接矩阵不能满足需求时,可以直接把预处理后的 BOLD 数据裁剪成 3D 体素块,训练 3D CNN。这一步才是真正体现“医学深度学习”的地方,因为模型要同时学习空间局部模式和时间激活模式。
import torch from torch import nn class SmallVoxelCNN3D(nn.Module): def __init__(self, in_channels=1, num_classes=2): super().__init__() self.features = nn.Sequential( nn.Conv3d(in_channels, 16, kernel_size=3, padding=1), nn.ReLU(), nn.MaxPool3d(2), nn.Conv3d(16, 32, kernel_size=3, padding=1), nn.ReLU(), nn.MaxPool3d(2), ) self.classifier = nn.Sequential( nn.AdaptiveAvgPool3d(1), nn.Flatten(), nn.Linear(32, num_classes), ) def forward(self, x): return self.classifier(self.features(x))注意,这里没有写死输入图像尺寸,因为AdaptiveAvgPool3d(1)可以适应任意输入分辨率。实际训练时要把单个被试的 3D 数据(比如 96×96×96)作为输入,batch size 可以先设为 2 或 4,再逐步增加。
在实际训练前,先确认设备是 GPU 还是 CPU:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print("using device:", device)5.5 显存占用与稳定性观察
使用nvidia-smi监控显存占用,建议开两个终端,一个跑训练,另一个执行:
watch -n 2 nvidia-smi更稳妥的做法是在训练脚本里打印 PyTorch 分配到的显存:
if torch.cuda.is_available(): print("allocated MB:", torch.cuda.memory_allocated() / 1024 / 1024) print("reserved MB:", torch.cuda.memory_reserved() / 1024 / 1024)如果显存不足,优先降低 batch size,然后降低体素块裁剪的分辨率,最后才考虑换更小的模型。直接换显卡不是第一选择,因为神经影像数据处理经常是在已有的共享服务器上完成。
6. 接口 API 与批量任务设计
fMRI 深度学习模型研究完成后,如果要把能力开放给团队内部或其他平台调用,最简单的做法是使用 FastAPI 或 Flask 封装一个推理接口。训练好的模型可以保存为model.pt,然后通过接口接收 NIfTI 文件路径或上传的影像文件,返回预测概率和解释性特征。
6.1 保存与加载模型
训练结束后,至少保存两份内容:模型权重和预处理器参数。只保存权重文件会让后续推理非常痛苦,因为你会忘记输入应该怎么归一化。
torch.save(model.state_dict(), "./models/voxel_cnn.pt") import joblib joblib.dump(scaler, "./models/scaler.pkl")6.2 最小可用的推理 API 示例
下面用 Flask 做一个最小示例,这个文件可以直接保存为api_server.py:
from flask import Flask, request, jsonify import nibabel as nib import numpy as np import torch app = Flask(__name__) model = SmallVoxelCNN3D() model.load_state_dict(torch.load("./models/voxel_cnn.pt", map_location="cpu")) model.eval() @app.route("/predict", methods=["POST"]) def predict(): if "file" not in request.files: return jsonify({"error": "no file uploaded"}), 400 f = request.files["file"] tmp_path = "./tmp_upload.nii.gz" f.save(tmp_path) img = nib.load(tmp_path) data = img.get_fdata() # 这里需要替换成你训练时实际使用的预处理逻辑 data = np.expand_dims(data[:, :, :, 0], axis=(0, 1)) tensor = torch.from_numpy(data).float() with torch.no_grad(): logits = model(tensor) probs = torch.softmax(logits, dim=1).numpy() return jsonify({"probabilities": probs.tolist()}) if __name__ == "__main__": app.run(host="127.0.0.1", port=8080)启动命令:
python api_server.py调用测试:
curl -X POST -F "file=@./test_bold.nii.gz" http://127.0.0.1:8080/predict这个接口只是一个结构模板,真正接到研究流程里时,必须替换成你训练时的预处理和归一化参数。
6.3 批量任务队列建议
fMRI 典型的批量任务就是“一次性训练/推理 50~100 个被试”。不建议直接写一个 for 循环把所有数据喂进去,因为任何一个被试的数据损坏都会让整个任务中断。推荐一个简单的设计:
queue.csv:记录被试 ID、输入路径、输出路径、状态。- 脚本每次从 CSV 里读取一个未处理的行。
- 处理成功就在 CSV 里标记 success,失败标记 fail,并记录日志。
- 断线后重新启动脚本时跳过 success。
import csv def load_queue(csv_path): with open(csv_path, newline="") as f: return list(csv.DictReader(f)) def mark_done(csv_path, subject_id, status): rows = [] with open(csv_path, newline="") as f: for row in csv.DictReader(f): if row["subject_id"] == subject_id: row["status"] = status rows.append(row) with open(csv_path, "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=rows[0].keys()) writer.writeheader() writer.writerows(rows)这样即使在第 47 个被试出错,只需修复数据后重新运行脚本,前面的成功结果不会重复计算。
7. 资源占用与性能观察方法
神经影像深度学习的资源占用有两个来源:数据读取和前向计算。很多人只关注显卡显存,实际上 fMRI 数据从硬盘读入内存再搬进显存的过程更加耗时。下面给出一套观察和优化思路。
7.1 显存与内存观察
训练时观察指标建议记录四个:
- GPU 利用率
- 显存占用
- 内存占用
- 磁盘 I/O
其中磁盘 I/O 被忽略的频率最高。如果用机械硬盘读取多个 GB 的 NIfTI 文件,GPU 即使被喂饱也会出现严重等待。优先选择 NVMe SSD。更稳妥的判断是所有观察指标都以实际机器为基准,跑一次完整训练脚本,把nvidia-smi的输出保存成日志,对比不同 batch size 的差异:
nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csv -l 2 > gpu_log.csv7.2 不同输入策略的显存差异
体素级 3D 卷积最耗显存,因为输入是高维体积。建议优先把数据裁剪到固定大小,比如只取大脑中心区域;其次使用连接矩阵做特征,这种策略几乎不占显存,甚至 CPU 就能完成。到底选择哪种策略,取决于实验目的:建模整体空间模式用体素级,建模网络连接用连接矩阵,建模任务态动态变化用时间序列模型。
7.3 减少占用稳定的手段
减小 batch size 是最直接的方法。如果 batch size 为 4 时显存溢出,改成 2 通常能解决问题。如果仍然溢出,使用梯度累积:
optimizer.zero_grad() loss.backward() loss = loss * (1.0 / accumulation_steps) if (step + 1) % accumulation_steps == 0: optimizer.step()不过要注意,梯度累积并不减少显存中的激活值占用,它只是把“大步长”拆成“小步长”,本质收益有限,更有效的方法是降低输入分辨率或使用混合精度。
from torch.cuda.amp import autocast, GradScaler scaler = GradScaler() with autocast(): outputs = model(inputs) loss = criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()混合精度需要 GPU 支持,一般较新的 NVIDIA 显卡都能跑通;在训练初期观察 loss 是否正常下降再继续执行。
7.4 端口和服务进程管理
如果 API 服务反复调试,容易出现端口被残留进程占用。先看端口再杀进程:
lsof -i :8080或者:
netstat -tunlp | grep 8080确认 PID 后结束进程:
kill -9 PID启动 API 服务时,建议先在本机127.0.0.1上调试,不要直接暴露到公网。如果确实需要局域网访问,再绑定对应 IP,并做访问控制,不要裸奔。
8. 神经影像深度学习常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| fMRIPrep 报错 BIDS 校验失败 | 目录结构或 dataset_description.json 不符合规范 | 重新检查目录树和 JSON 格式 | 严格按 BIDS 命名规范修改文件 |
| 加载 NIfTI 后 shape 不是四维 | DICOM 转换时漏了时间维度配置 | 查看 json 元数据中的 RepetitionTime | 重新用 dcm2niix 转换 |
| 训练 loss 一直不下降 | 输入未归一化 / 标签错位 / 模型没有读取到关键脑区 | 检查数据均值与方差、抽查输入样本 | 加入标准化预处理,必要时做数据可视化 |
| 显存溢出 | 体素块太大 / batch size 过高 / 网络层数过多 | 看 nvidia-smi 的 memory 上限 | 减少 batch size、裁剪尺寸、用混合精度 |
| 预处理输出只有几个被试 | 个别被试原始数据损坏或头动太大 | 查看 fMRIPrep 日志中的 crash file | 修复数据后单独重跑该被试 |
| curl 调用 API 返回 400 | 文件字段名与请求不对应 | 检查请求中的参数名 | 改成-F "file=@..."或修改服务端字段名 |
| 批量队列跑到一半卡住 | 某个数据读取阻塞或显存被占满 | 加日志输出当前正在处理的被试 | 在循环中打印 subject_id,失败时跳过并重试 |
| 模型结果在三个数据集差异巨大 | 扫描仪参数、头动水平、预处理版本不一致 | 对比各数据集的元信息 | 统一预处理参数,做站点校正或分层验证 |
| 连接矩阵大量为 0 | 掩膜没有被正确配准到数据空间 | 可视化掩膜与数据的叠加 | 重新检查 fMRIPrep 的输出空间 |
实际排查顺序建议是:先看日志,再查数据 shape,再确认设备,最后怀疑模型。不要一上来就调网络结构,fMRI 领域大量训练异常都来自于数据管线和预处理参数。
9. 医学深度学习完整学习路径与最佳实践
9.1 从零开始的 12 周学习路径
如果之前没有接触过神经影像,按下面这条路径会少走很多弯路。
前四周打数据基础:学习 DICOM/NIfTI 格式,理解体素、TR、TE 的含义;用 nilearn 完成一次静息态功能连接分析,尝试画出全脑连接矩阵。不要急着训练模型,先理解你后面要喂给模型的数据是怎么来的。
五六周打 Python 建模基础:熟练使用 numpy、pandas、scikit-learn,完成一次基于连接矩阵的分类实验。这次实验核心是体会“特征从哪里来、标签是否干净”,不需要上深度学习。
七八周进入 3D 深度学习:用 MONAI 跑通一个 3D 医学影像分类示例,理解卷积核在体积数据上的移动方式,会写 DataLoader,学会保存和加载模型权重。
九十周做小项目:找一个小规模的公开 fMRI 数据集,完成“预处理→特征提取→模型训练→结果可视化”的完整闭环,并记录显存、内存、耗时三类指标。
最后两周做接口交付:用 Flask 封装已经训练好的模型,设计批量推理 CSV 队列,写一份 README 说明调用方法和参数含义。
9.2 数据管理与复现性
建议给每个研究项目建立固定目录模板,并把预处理参数写入配置文件:
dataset: raw_dir: ./dataset/ bids_version: "1.8.0" preprocessing: fmriprep_version: "23.2.1" output_spaces: "MNI152NLin6Asym" training: batch_size: 4 epochs: 50 lr: 0.0001 seed: 42训练前设置随机种子,确保同一环境两次运行结果一致:
import random import numpy as np import torch random.seed(42) np.random.seed(42) torch.manual_seed(42) if torch.cuda.is_available(): torch.cuda.manual_seed_all(42)9.3 合规与伦理最佳实践
处理 fMRI 数据前,先问三个问题:这个数据集的授权协议能不能支持我的用途?被试影像是否做过去标识化?我的实验是否通过了所在机构的伦理审查?任何涉及临床数据的实验,都不应该把原始影像直接发送到不受控的外部服务;本地部署自己的模型比公网 API 更可控。如果字段包含人脸重建信息或脑结构个体特征,还要考虑脱敏处理。研究成果发布时,应按照数据集使用协议明确致谢,不把被禁止再分发的数据二次传出。
9.4 模型效果复核建议
神经网络在神经影像项目里很容易“看起来有效、实际不可复现”,所以建议训练完成后做三件事:
- 多次重复训练,观察稳定性和方差。
- 用留出集或至少五折交叉验证汇报结果。
- 可视化模型关注区域,看是否落在已知任务相关脑区。
如果模型关注的区域和已有文献完全相反,优先怀疑数据泄露,比如预处理时把标签信息写入了文件名并被模型读取;其次是样本量不足导致过拟合。
10. 总结与下一步
神经科学 AI 看起来是个很宽的赛道,但真正核心的落地点是“能否在合理成本下把 fMRI 数据变成有用特征”。连接矩阵方案可以在单卡 GPU 甚至 CPU 上完成,体素级 3D 卷积需要更大的显存和更长的训练时间,API 和批量队列则决定了研究成果能不能被别人调用。这项技术最值得先验证的点不是模型花哨程度,而是数据预处理能否稳定复现,以及第一次分类实验的交叉验证是否能跑通。最容易踩的坑则是:跳过 BIDS 规范直接训练、不检查输入数据的 shape、批处理不记录日志、显存不够时盲目堆模型。
下一步建议先复制第四节的数据目录模板,用公开数据集跑一次 fMRIPrep,确认预处理输出正常,再用第五节的功能连接代码生成矩阵。这条路径跑通之后,再进入 3D 深度学习实验和 API 封装。整套流程建议收藏备用,侧重点不是看概念多深,而是今天能不能在自己机器上把数据管线捋顺。