學(xué)深度學(xué)習(xí):從功能連接到疾病分類的完整實戰(zhàn)指南)
神經(jīng)影像與醫(yī)學(xué)深度學(xué)習(xí)的結(jié)合近幾年幾乎是計算機視覺和醫(yī)學(xué)圖像分析領(lǐng)域里最熱門的方向之一。無論是阿爾茨海默癥早期診斷、精神分裂癥生物標(biāo)志物挖掘還是腦機接口中的腦狀態(tài)解碼fMRI功能磁共振成像數(shù)據(jù)都扮演著核心角色。但很多剛接觸這個方向的同學(xué)會遇到同一個問題自然圖像那套深度學(xué)習(xí)流程遷移到腦影像上似乎沒那么好用了。數(shù)據(jù)維度不對、樣本量太小、預(yù)處理流程復(fù)雜、模型可解釋性要求高處處都是坎。這篇文章會圍繞醫(yī)學(xué)深度學(xué)習(xí)在神經(jīng)影像中的應(yīng)用展開重點針對 fMRI 數(shù)據(jù)講清楚核心概念、科研應(yīng)用場景、完整的工具鏈與學(xué)習(xí)路徑并提供一個可以照著跑的實戰(zhàn)案例幫助初學(xué)者少走彎路。文章適合以下幾類讀者醫(yī)學(xué)影像相關(guān)的碩士研究生、博士研究生尤其是剛接觸神經(jīng)影像分析的同學(xué)想從自然圖像 CV 轉(zhuǎn)向醫(yī)學(xué)圖像方向的算法工程師對腦科學(xué)、人工智能交叉方向感興趣但不知道從哪下手的初學(xué)者已經(jīng)在做結(jié)構(gòu)像 MRI 分析想擴展到 fMRI 功能像分析的研究者。讀完這篇文章你會掌握 fMRI 數(shù)據(jù)的基本結(jié)構(gòu)、主流分析流程、深度學(xué)習(xí)建模的常見思路以及一套從零開始的完整學(xué)習(xí)路線。1. 為什么神經(jīng)科學(xué) AI 被稱為黃金賽道1.1 從醫(yī)學(xué)深度學(xué)習(xí)說起醫(yī)學(xué)深度學(xué)習(xí)是深度學(xué)習(xí)技術(shù)在醫(yī)療健康領(lǐng)域的應(yīng)用總稱覆蓋醫(yī)學(xué)影像診斷、病理切片分析、電子病歷挖掘、藥物發(fā)現(xiàn)、基因組學(xué)等多個子方向。其中醫(yī)學(xué)影像因為數(shù)據(jù)形態(tài)相對規(guī)整、任務(wù)目標(biāo)明確成為落地最活躍的領(lǐng)域。常見的醫(yī)學(xué)影像模態(tài)包括CT計算機斷層掃描主要看解剖結(jié)構(gòu)MRI磁共振成像結(jié)構(gòu)像看解剖功能像看腦活動超聲實時性強常用于腹部和心血管檢查病理切片超高分辨率二維圖像需要特殊處理眼底照視網(wǎng)膜成像用于糖尿病視網(wǎng)膜病變篩查。在所有這些模態(tài)中fMRI 是比較特殊的一種。它并不是一張靜態(tài)圖片而是包含空間結(jié)構(gòu)和時間序列的四維數(shù)據(jù)。這意味著深度學(xué)習(xí)模型要同時捕捉空間模式和時間動態(tài)建模難度要比普通二維圖像高一個檔次。1.2 為什么神經(jīng)影像方向值得投入神經(jīng)影像 AI 之所以被很多人稱為“黃金賽道”主要是因為以下幾點第一臨床需求真實且迫切。神經(jīng)系統(tǒng)疾病包括阿爾茨海默癥、帕金森病、精神分裂癥、抑郁癥、自閉癥譜系障礙等往往缺乏客觀的生物學(xué)診斷指標(biāo)。醫(yī)生主要依賴量表評估和行為觀察主觀性較強。如果模型能從 fMRI 數(shù)據(jù)中找到穩(wěn)定的腦活動模式差異就有希望成為輔助診斷的生物標(biāo)志物。這種需求是剛性的。第二數(shù)據(jù)有獨特的學(xué)術(shù)價值。腦是人體最復(fù)雜的器官fMRI 數(shù)據(jù)記錄了大腦在任務(wù)刺激或靜息狀態(tài)下的血氧水平依賴信號BOLD 信號本質(zhì)上是一種高維時空數(shù)據(jù)。通過對 fMRI 的建模研究者不僅能做分類預(yù)測還能反過來探索“哪個腦區(qū)和哪個腦區(qū)之間的連接模式發(fā)生了改變”這種可解釋性分析對腦科學(xué)基礎(chǔ)研究非常有價值。第三交叉學(xué)科壁壘帶來的稀缺性。既懂深度學(xué)習(xí)又懂神經(jīng)影像的人目前仍然相對稀缺。純做算法的同學(xué)不熟悉腦結(jié)構(gòu)純做臨床的同學(xué)不熟悉深度學(xué)習(xí)。能夠把兩邊銜接起來的人在科研合作、項目落地、論文產(chǎn)出上都有明顯優(yōu)勢。1.3 常見應(yīng)用場景神經(jīng)影像 AI 的實際應(yīng)用場景非常豐富以下是幾個典型的任務(wù)疾病分類根據(jù) fMRI 數(shù)據(jù)判斷被試屬于患者組還是健康對照組例如精神分裂癥分類、阿爾茨海默癥識別。腦齡預(yù)測利用結(jié)構(gòu)像或功能像預(yù)測被試的“腦齡”腦齡與真實年齡的差距可以作為腦健康程度的指標(biāo)。認(rèn)知狀態(tài)解碼從任務(wù)態(tài) fMRI 中預(yù)測被試正在進(jìn)行的認(rèn)知活動例如看的是貓還是狗或者正在回憶什么內(nèi)容。功能連接分析不直接做分類而是通過功能連接矩陣比較兩組被試的腦網(wǎng)絡(luò)差異屬于更偏統(tǒng)計分析的方向。影像基因組學(xué)結(jié)合 fMRI 與基因數(shù)據(jù)分析腦活動模式與遺傳變異之間的關(guān)聯(lián)。這些場景中深度學(xué)習(xí)主要承擔(dān)兩種角色一種是端到端的預(yù)測模型直接吃原始 fMRI 或預(yù)處理后的數(shù)據(jù)做分類另一種是特征提取器將深度學(xué)習(xí)得到的表征與傳統(tǒng)的統(tǒng)計分析結(jié)合。2. fMRI 數(shù)據(jù)的核心概念在動手寫代碼之前先把 fMRI 數(shù)據(jù)本身搞清楚。很多人一開始就直接跑深度學(xué)習(xí)模型結(jié)果模型不收斂、效果差回頭才發(fā)現(xiàn)連數(shù)據(jù)長什么樣都沒弄明白。2.1 BOLD 信號與 fMRI 成像原理fMRI 的全稱是 functional Magnetic Resonance Imaging即功能磁共振成像。它測量的并不是神經(jīng)元放電本身而是血氧水平依賴信號也就是 BOLD 信號。其基本原理是當(dāng)某個腦區(qū)活躍時局部腦血流量增加含氧血紅蛋白與脫氧血紅蛋白的比例發(fā)生變化。脫氧血紅蛋白是順磁性的會擾動局部磁場從而影響 MRI 信號強度。通過對這種信號的連續(xù)采集可以間接反映神經(jīng)活動的時間變化。需要特別注意的是BOLD 信號是一種間接且滯后的測量信號時間分辨率有限通常每隔 1 到 3 秒采集一個全腦 volume。因此fMRI 并不是“實時記錄神經(jīng)元活動”而是通過血流動力學(xué)響應(yīng)間接推斷神經(jīng)活動。2.2 4D 數(shù)據(jù)空間維度和時間維度一次標(biāo)準(zhǔn)的 fMRI 掃描得到的數(shù)據(jù)通常是一個四維數(shù)組X冠狀位方向的空間維度Y矢狀位方向的空間維度Z軸位方向的空間維度T時間幀數(shù)。舉個例子一個常見的 fMRI 掃描參數(shù)可能是61 × 73 × 61的空間分辨率TR重復(fù)時間為 2 秒共掃描 120 個時間點。那么數(shù)據(jù)結(jié)構(gòu)就是61 × 73 × 61 × 120其中前三個維度構(gòu)成一個大腦的三維體積第四維是時間序列。理解這一點非常關(guān)鍵因為很多深度學(xué)習(xí)模型的設(shè)計都圍繞這四個維度展開如果忽略時間維度把每個 volume 當(dāng)作獨立樣本就退化為 3D CNN 分類問題如果保留時間維度可以用 4D CNN、CNN RNN 或 Transformer 處理如果先提取每個腦區(qū)的平均信號序列再算腦區(qū)之間的相關(guān)性就得到功能連接矩陣可以用 2D CNN 或圖神經(jīng)網(wǎng)絡(luò)。2.3 fMRI 與結(jié)構(gòu)像 MRI 的區(qū)別剛?cè)腴T的人容易把 fMRI 和結(jié)構(gòu)性 MRI 混在一起。實際上它們的區(qū)別非常明顯維度結(jié)構(gòu)像 MRI功能像 fMRI數(shù)據(jù)形態(tài)3D 單張圖像3D 時間的 4D 序列主要信息解剖結(jié)構(gòu)、組織類型血氧信號的時間變化空間分辨率較高可達(dá) 1mm 各向同性較低常見 2-3mm時間分辨率無較低TR 通常為 1-3 秒典型任務(wù)腫瘤分割、腦區(qū)分割功能連接分類、腦狀態(tài)解碼有些研究還會把結(jié)構(gòu)像和功能像一起作為多模態(tài)輸入比如 Alzheimer’s 分類中把 T1 結(jié)構(gòu)像和靜息態(tài) fMRI 結(jié)合。這樣能互補信息但多模態(tài)的數(shù)據(jù)預(yù)處理和模型融合復(fù)雜度也更高。2.4 靜息態(tài) fMRI 和任務(wù)態(tài) fMRIfMRI 數(shù)據(jù)根據(jù)采集時被試的狀態(tài)可以分成兩大類靜息態(tài) fMRIrs-fMRI被試不執(zhí)行任何任務(wù)閉眼放松休息大腦處于自發(fā)的低頻活動狀態(tài)。這種數(shù)據(jù)最常用于疾病分類研究因為它不需要復(fù)雜的任務(wù)設(shè)計臨床采集方便跨中心的標(biāo)準(zhǔn)化程度相對較高。任務(wù)態(tài) fMRItask-fMRI被試在掃描過程中執(zhí)行特定任務(wù)例如手指敲擊、圖片觀看、記憶編碼等。任務(wù)態(tài)數(shù)據(jù)更適合研究特定認(rèn)知功能對應(yīng)的腦區(qū)激活模式但不同實驗范式的設(shè)計差異很大跨研究比較困難。對于入門者通常建議從靜息態(tài) fMRI 開始因為它流程相對固定公開數(shù)據(jù)集也更多。3. 神經(jīng)影像 AI 的科研應(yīng)用全景這一部分把目前主流的研究方向梳理一遍。每個方向看似都是“分類”或“回歸”但實際技術(shù)方案差別很大。3.1 基于功能連接的疾病分類這是靜息態(tài) fMRI 中最主流的研究范式。思路分三步走將大腦按照標(biāo)準(zhǔn)圖譜劃分成若干個感興趣區(qū)ROI常用的圖譜包括 AAL、Desikan-Killiany、Gordon 等提取每個 ROI 的平均 BOLD 時間序列計算 ROI 兩兩之間的皮爾遜相關(guān)系數(shù)得到一個N × N的功能連接矩陣以功能連接矩陣作為特征訓(xùn)練分類器或者將矩陣當(dāng)作圖像輸入卷積網(wǎng)絡(luò)。這種做法的優(yōu)勢在于特征維度大幅降低從原始的百萬級體素降到幾百維或幾千維緩解了樣本量不足的問題。同時功能連接矩陣具有明確的神經(jīng)生物學(xué)意義實驗結(jié)果更容易解釋。3.2 基于體素/灰質(zhì)體積的淺層分類如果做結(jié)構(gòu)像分析可以計算每個體素或每個腦區(qū)的灰質(zhì)體積然后使用 SVM、邏輯回歸等傳統(tǒng)機器學(xué)習(xí)方法分類。這種方法在 Alzheimers 分類中非常經(jīng)典優(yōu)點是簡單、穩(wěn)健、可解釋性強。但要注意這種方法對圖像配準(zhǔn)的精度要求極高。不同被試的大腦形狀不同必須先把所有圖像配準(zhǔn)到同一個標(biāo)準(zhǔn)空間比如 MNI 空間才能保證同一個體素在不同被試之間對應(yīng)的是同一個解剖位置。3.3 端到端深度模型隨著深度學(xué)習(xí)的發(fā)展越來越多研究嘗試讓模型直接吃預(yù)處理后的 fMRI 數(shù)據(jù)跳過人工特征工程。典型方案3D CNN把每個時間點的 brain volume 當(dāng)作 3D 圖像輸入。4D CNN / RNN 組合先用 3D CNN 提取空間特征再用 RNN 或 LSTM 建模時間動態(tài)。Transformer把腦區(qū)時間序列當(dāng)作 token 序列用自注意力機制建模腦區(qū)間的長程依賴關(guān)系。圖神經(jīng)網(wǎng)絡(luò)GNN將大腦建模為圖節(jié)點是 ROI邊是功能連接強度或結(jié)構(gòu)連接在圖級別做分類。這些方法在論文里效果往往不錯但在實際應(yīng)用中需要面對樣本量小、過擬合嚴(yán)重、可解釋性差等問題。3.4 腦齡預(yù)測腦齡預(yù)測是另一個熱門的研究方向。研究者使用深度學(xué)習(xí)模型從 T1 結(jié)構(gòu)像或功能連接特征中預(yù)測被試的年齡然后計算“預(yù)測腦齡減去真實年齡”的差值即 PADPredicted Age Difference。如果某個人群的 PAD 顯著大于 0說明其大腦看起來比同齡人更老可能與神經(jīng)退行性疾病相關(guān)。腦齡預(yù)測已經(jīng)被應(yīng)用于輕度認(rèn)知障礙、精神分裂癥、艾滋病相關(guān)神經(jīng)認(rèn)知障礙等多種疾病研究。這個方向的技術(shù)核心不是分類精度而是回歸模型的準(zhǔn)確性和泛化能力。3.5 多中心數(shù)據(jù)的泛化問題在真實科研項目中很少只用單中心數(shù)據(jù)。比如 ABIDE 數(shù)據(jù)集就包含來自 17 個不同采集中心的數(shù)據(jù)不同中心的掃描儀型號、采集參數(shù)、被試群體都有差異。模型在一個中心上訓(xùn)練效果好到另一個中心上性能可能明顯下降。這就是所謂的“跨站點泛化問題”。目前在多中心 fMRI 研究中處理方式包括使用 ComBat 等工具進(jìn)行數(shù)據(jù)協(xié)調(diào)使用域適應(yīng)或域泛化方法把中心信息作為協(xié)變量加入模型采用更穩(wěn)健的預(yù)處理流程盡量減少采集參數(shù)對數(shù)據(jù)的影響。這一點需要從項目一開始就考慮等后面發(fā)現(xiàn)泛化不行再回頭處理會浪費大量時間和算力。4. 環(huán)境準(zhǔn)備與工具鏈4.1 操作系統(tǒng)與硬件神經(jīng)影像分析和深度學(xué)習(xí)訓(xùn)練通常在 Linux 環(huán)境下進(jìn)行推薦 Ubuntu 20.04 或 22.04。GPU 是必需的尤其是端到端深度學(xué)習(xí)模型顯存建議至少 8GB 以上如果做傳統(tǒng)機器學(xué)習(xí)或功能連接分類CPU 也可以應(yīng)付只是速度慢一些。Windows 也能跑大部分 Python 庫但在神經(jīng)影像工具鏈的兼容性上不如 Linux。這里還是最推薦 Linux。4.2 Python 環(huán)境建議使用conda管理 Python 環(huán)境Python 版本選擇 3.9 或 3.10 即可。這里給出一個示例建環(huán)境命令conda create -n neuroai python3.10 conda activate neuroai注意具體庫的兼容性會隨版本變化如果安裝過程遇到問題優(yōu)先查看對應(yīng)庫的官方文檔確認(rèn) Python 版本支持情況。4.3 核心 Python 庫神經(jīng)影像研究需要安裝以下幾類庫。醫(yī)學(xué)圖像讀取與處理# 讀取 nii.gz 格式的神經(jīng)影像數(shù)據(jù) import nibabel as nib img nib.load(sub-01_T1w.nii.gz) data img.get_fdata() print(data.shape)nibabel是幾乎所有神經(jīng)影像分析工作的基礎(chǔ)庫支持 NIfTI、GIFTI、CIFTI 等格式。拿到數(shù)據(jù)后第一件事通常是打印數(shù)據(jù)形狀確認(rèn)是 3D 還是 4D。影像預(yù)處理和可視化nilearn是專門為神經(jīng)影像機器學(xué)習(xí)設(shè)計的 Python 庫封裝了預(yù)處理、圖譜提取、功能連接計算、可視化等常用功能非常適合入門。from nilearn import plotting, datasets # 加載示例數(shù)據(jù) haxby_dataset datasets.fetch_haxby() # 顯示一個統(tǒng)計圖 plotting.plot_stat_map(example_stat.nii.gz)流程化預(yù)處理fMRIPrep是當(dāng)前 fMRI 預(yù)處理的主流工具自動完成頭動校正、時間層校正、配準(zhǔn)、歸一化等步驟。它運行在 Docker 或 Singularity 容器中輸出處理后的數(shù)據(jù)以及豐富的質(zhì)量報告。深度學(xué)習(xí)框架PyTorch 在醫(yī)學(xué)影像領(lǐng)域的使用率遠(yuǎn)高于其他框架主要原因是生態(tài)豐富、動態(tài)圖靈活、社區(qū)資料多。安裝命令pip install torch torchvision如果要用圖神經(jīng)網(wǎng)絡(luò)還需要安裝torch-geometric安裝方式與其支持的 CUDA 版本有關(guān)建議參考官網(wǎng)。4.4 常用公開數(shù)據(jù)集在科研中數(shù)據(jù)質(zhì)量直接決定實驗效果。以下是幾個常用的公開 fMRI 數(shù)據(jù)集ABIDE自閉癥譜系障礙靜息態(tài) fMRI 數(shù)據(jù)集包含 17 個中心的數(shù)據(jù)適合做跨中心分類實驗。HCP人類連接組計劃包含高質(zhì)量的任務(wù)態(tài)和靜息態(tài) fMRI數(shù)據(jù)量大、質(zhì)量高適合做認(rèn)知解碼和分析方法研究。ADNI阿爾茨海默癥神經(jīng)影像計劃包含 MRI、PET、臨床數(shù)據(jù)適合做疾病進(jìn)展預(yù)測和生物標(biāo)志物挖掘。UK Biobank大規(guī)模生物樣本庫包含數(shù)萬人的腦影像數(shù)據(jù)適合做腦齡預(yù)測和大規(guī)模統(tǒng)計分析。COBRE精神分裂癥 fMRI 數(shù)據(jù)集規(guī)模適中適合快速驗證模型。每個數(shù)據(jù)集都有自己的倫理授權(quán)協(xié)議和使用限制下載前務(wù)必查看對應(yīng)官網(wǎng)的 Terms of Use。4.5 目錄結(jié)構(gòu)規(guī)劃一個規(guī)范的 fMRI 深度學(xué)習(xí)項目目錄結(jié)構(gòu)可以參考下面neuro_project/ ├── data/ │ ├── raw/ # 原始 NIfTI 數(shù)據(jù) │ ├── processed/ # 預(yù)處理后數(shù)據(jù) │ └── derivatives/ # fMRIPrep 輸出 ├── src/ │ ├── preprocessing.py │ ├── build_connectome.py │ ├── dataset.py │ ├── model.py │ └── train.py ├── config/ │ └── config.yaml ├── results/ │ ├── models/ │ └── logs/ └── README.md從一開始就保持目錄清晰能避免后期寫論文時到處找數(shù)據(jù)文件的問題。5. 核心處理方法與代碼示例這一節(jié)列出 fMRI 分析中最常用的幾個環(huán)節(jié)每段代碼都可以直接參考使用。5.1 數(shù)據(jù)加載與基礎(chǔ)檢查拿到 fMRI 數(shù)據(jù)后第一步永遠(yuǎn)是檢查數(shù)據(jù)的基本屬性包括形狀、體素大小、TR 等。import nibabel as nib func_path path/to/sub-01_task-rest_bold.nii.gz func_img nib.load(func_path) # 4D 數(shù)據(jù)形狀: (x, y, z, time) data func_img.get_fdata() print(4D shape:, data.shape) # 獲取體素大小 zooms func_img.header.get_zooms() print(voxel sizes:, zooms) # 獲取 TR tr func_img.header[pixdim][4] print(TR:, tr)這里有一個新手常犯的錯誤直接用get_fdata()讀取 4D 數(shù)據(jù)并傳入 PyTorch卻忘了數(shù)據(jù)存儲的數(shù)據(jù)類型可能是float64顯存占用是float32的兩倍。建議讀取后轉(zhuǎn)換為float32data func_img.get_fdata(dtypefloat32)5.2 掩膜提取與時間序列提取fMRI 數(shù)據(jù)包含大量非腦組織體素直接全腦計算會引入大量噪聲。通常需要先使用腦掩膜brain mask或圖譜把數(shù)據(jù)限定在灰質(zhì)或特定 ROI 內(nèi)。nilearn提供了非常方便的接口from nilearn.input_data import NiftiLabelsMasker, NiftiMasker # 使用標(biāo)準(zhǔn)圖譜 AAL提取每個 ROI 的平均時間序列 masker NiftiLabelsMasker( labels_imgpath/to/aal.nii.gz, standardizeTrue, memorycache, verbose1 ) # 輸入 4D 數(shù)據(jù)輸出 2D 數(shù)組形狀為 (時間點數(shù), ROI數(shù)) time_series masker.fit_transform(path/to/sub-01_task-rest_bold.nii.gz) print(time_series.shape)NiftiLabelsMasker是最常用的工具之一它自動完成配準(zhǔn)、重采樣、ROI 信號提取、標(biāo)準(zhǔn)化等步驟。輸出的time_series每一列代表一個腦區(qū)在不同時間點上的平均信號。5.3 功能連接矩陣的構(gòu)建拿到 ROI 時間序列后下一步通常就是計算功能連接矩陣import numpy as np # 計算 Pearson 相關(guān)系數(shù)矩陣 connectome np.corrcoef(time_series.T) # 對角線置零去除自相關(guān) np.fill_diagonal(connectome, 0) print(Connectome shape:, connectome.shape)這個連接矩陣就是后續(xù)分類的輸入特征??梢园丫仃囅卤泶鎯?npy或.csv文件供傳統(tǒng)機器學(xué)習(xí)使用也可以轉(zhuǎn)成 PyTorch Tensor 輸入圖神經(jīng)網(wǎng)絡(luò)。5.4 簡單 SVM 分類基線在做深度學(xué)習(xí)之前強烈建議先跑一個簡單的 SVM 基線。一方面能檢驗特征是否有效另一方面深度學(xué)習(xí)的效果必須超過基線才有意義。from sklearn.model_selection import cross_val_score from sklearn.svm import SVC import numpy as np # X: 上三角連接矩陣展平后的特征 # y: 標(biāo)簽數(shù)組, 0/1 # 取上三角避免對稱矩陣的重復(fù)信息 triu_idx np.triu_indices_from(connectome, k1) X connectome[triu_idx].reshape(1, -1) clf SVC(kernellinear, C1.0) scores cross_val_score(clf, X, y, cv5, scoringaccuracy) print(fCV accuracy: {scores.mean():.3f} ± {scores.std():.3f})在 ABIDE 數(shù)據(jù)集上線性 SVM 的分類準(zhǔn)確率通常在 60% 到 70% 左右具體取決于預(yù)處理和特征選擇。要超過這個基線深度學(xué)習(xí)模型必須能提取到 SVM 學(xué)不到的更復(fù)雜的特征。5.5 簡單 2D CNN 分類模型當(dāng)功能連接矩陣的維度不高時一種常見的做法是直接把它當(dāng)作單通道圖像輸入 2D CNN。盡管它并不是真正的“自然圖像”但 CNN 能捕捉到相鄰 ROI 之間的局部相關(guān)性模式。import torch import torch.nn as nn class ConnectomeCNN(nn.Module): def __init__(self, n_regions116, n_classes2): super().__init__() self.conv1 nn.Conv2d(1, 32, kernel_size3, padding1) self.conv2 nn.Conv2d(32, 64, kernel_size3, padding1) self.pool nn.MaxPool2d(2) self.flatten nn.Flatten() # 動態(tài)計算全連接層輸入維度 dummy torch.zeros(1, 1, n_regions, n_regions) flat_dim self._get_flat_dim(dummy) self.fc nn.Linear(flat_dim, n_classes) def _get_flat_dim(self, x): x self.pool(torch.relu(self.conv1(x))) x self.pool(torch.relu(self.conv2(x))) return self.flatten(x).shape[1] def forward(self, x): x torch.relu(self.conv1(x)) x self.pool(x) x torch.relu(self.conv2(x)) x self.pool(x) x self.flatten(x) return self.fc(x)這段代碼是核心片段需要配合數(shù)據(jù)加載和訓(xùn)練腳本使用。n_regions需要與圖譜的 ROI 數(shù)量一致。5.6 時空序列建模的 RNN 方案如果不想丟失時間信息可以把 ROI 時間序列直接輸入循環(huán)神經(jīng)網(wǎng)絡(luò)。此時每個時間點的輸入是一個腦區(qū)信號向量import torch.nn as nn class RNNClassifier(nn.Module): def __init__(self, n_regions116, hidden_size64, n_classes2): super().__init__() self.lstm nn.LSTM( input_sizen_regions, hidden_sizehidden_size, batch_firstTrue, bidirectionalTrue ) self.fc nn.Linear(hidden_size * 2, n_classes) def forward(self, x): # x 形狀: (batch, T, n_regions) out, _ self.lstm(x) # 取最后一個時間步的輸出 last_out out[:, -1, :] return self.fc(last_out)這種模型的任務(wù)理解是每個時間點各腦區(qū)的活動模式經(jīng)過 LSTM 編碼后最后匯總成整個掃描序列的表示再做分類。6. 完整實戰(zhàn)基于 ABIDE 的 ASD 分類接下來用一個相對完整的項目把上面所有環(huán)節(jié)串起來。由于 ABIDE 原始數(shù)據(jù)下載需要申請這里提供一套代碼框架你可以根據(jù)自己的數(shù)據(jù)目錄調(diào)整路徑。6.1 數(shù)據(jù)準(zhǔn)備假設(shè)你已經(jīng)下載了 ABIDE 預(yù)處理的靜息態(tài) fMRI 數(shù)據(jù)每個被試的文件名格式為sub-50001_task-rest_bold.nii.gz同時準(zhǔn)備一個labels.csv包含兩列subject_id和label。subject_id,label 50001,0 50002,1 50003,1 ...標(biāo)簽為 0 表示健康對照1 表示 ASD 患者。6.2 批量提取功能連接矩陣先把每個被試的 fMRI 數(shù)據(jù)經(jīng)過圖譜分割和時間序列提取得到對應(yīng)的功能連接矩陣。import os import glob import numpy as np import pandas as pd from nilearn.input_data import NiftiLabelsMasker def build_connectomes(func_dir, labels_file, atlas_path, output_dir): os.makedirs(output_dir, exist_okTrue) labels_df pd.read_csv(labels_file) masker NiftiLabelsMasker( labels_imgatlas_path, standardizeTrue, memorycache, memory_level2, n_jobs2 ) for _, row in labels_df.iterrows(): sub_id row[subject_id] func_path os.path.join(func_dir, fsub-{sub_id}_task-rest_bold.nii.gz) if not os.path.exists(func_path): print(fMissing: {func_path}) continue # 提取 ROI 時間序列 ts masker.fit_transform(func_path) # 計算功能連接矩陣 conn np.corrcoef(ts.T) np.fill_diagonal(conn, 0) # 保存 save_path os.path.join(output_dir, fsub-{sub_id}_connectome.npy) np.save(save_path, conn) print(fFinished: {sub_id}, shape{conn.shape}) print(All connectomes are saved.)這段代碼的核心邏輯就是循環(huán)每個被試做序列提取、計算相關(guān)矩陣、保存。實際運行時間取決于數(shù)據(jù)量和機器性能幾百個被試一般需要幾十分鐘到數(shù)小時。6.3 訓(xùn)練數(shù)據(jù)切分把功能連接矩陣和標(biāo)簽組裝成 PyTorch 的數(shù)據(jù)集import torch from torch.utils.data import Dataset, DataLoader class ConnectomeDataset(Dataset): def __init__(self, conn_dir, labels_file, n_regions116): labels_df pd.read_csv(labels_file) self.conn_paths [] self.labels [] for _, row in labels_df.iterrows(): sub_id row[subject_id] label int(row[label]) conn_path os.path.join(conn_dir, fsub-{sub_id}_connectome.npy) if os.path.exists(conn_path): self.conn_paths.append(conn_path) self.labels.append(label) self.n_regions n_regions def __len__(self): return len(self.conn_paths) def __getitem__(self, idx): conn np.load(self.conn_paths[idx]).astype(np.float32) # 加一個通道維度: (1, N, N) x torch.from_numpy(conn).unsqueeze(0) y torch.tensor(self.labels[idx], dtypetorch.long) return x, y注意這里的數(shù)據(jù)集假設(shè)每個 connectome 矩陣都是按同一個圖譜順序排列的。不同圖譜中 ROI 的編號順序會影響矩陣結(jié)構(gòu)實驗時必須保持一致。6.4 訓(xùn)練循環(huán)基礎(chǔ)訓(xùn)練循環(huán)如下import torch.optim as optim def train_one_epoch(model, dataloader, optimizer, criterion, device): model.train() total_loss 0 correct 0 total 0 for x, y in dataloader: x, y x.to(device), y.to(device) optimizer.zero_grad() out model(x) loss criterion(out, y) loss.backward() optimizer.step() total_loss loss.item() * x.size(0) pred out.argmax(dim1) correct (pred y).sum().item() total y.size(0) return total_loss / total, correct / total device torch.device(cuda if torch.cuda.is_available() else cpu) model ConnectomeCNN(n_regions116, n_classes2).to(device) optimizer optim.Adam(model.parameters(), lr1e-4) criterion nn.CrossEntropyLoss() for epoch in range(30): loss, acc train_one_epoch(model, train_loader, optimizer, criterion, device) print(fEpoch {epoch1}: loss{loss:.4f}, acc{acc:.4f})6.5 預(yù)期結(jié)果與說明在 ABIDE 數(shù)據(jù)集上最后的分類準(zhǔn)確率通常不會像自然圖像那樣輕松達(dá)到 90% 以上。如果預(yù)處理合適、樣本量充足二分類準(zhǔn)確率在 65% 到 75% 之間已經(jīng)算是正常范圍。影響結(jié)果的變量很多樣本量、站點差異、圖譜選擇、是否做特征選擇、訓(xùn)練集和測試集的劃分方式等。因此當(dāng)模型準(zhǔn)確率不高時不要急著堆模型結(jié)構(gòu)首先檢查數(shù)據(jù)處理流程和數(shù)據(jù)劃分是否合理然后對比 SVM 基線接著再考慮是否引入更復(fù)雜的網(wǎng)絡(luò)。7. 常見問題與排查思路7.1 典型問題速查表問題現(xiàn)象常見原因解決思路數(shù)據(jù)讀取后形狀不對NIfTI 數(shù)據(jù)可能是 3D也可能是 4D可能是按最后一維排列時間幀用nibabel.squeeze處理單例維度打印原始形狀并核對模型訓(xùn)練不收斂學(xué)習(xí)率過大、輸入數(shù)據(jù)未標(biāo)準(zhǔn)化、標(biāo)簽不平衡降低學(xué)習(xí)率檢查數(shù)據(jù)均值方差使用加權(quán)損失函數(shù)訓(xùn)練集準(zhǔn)確率高測試集很低樣本量小導(dǎo)致過擬合使用交叉驗證、數(shù)據(jù)增強、Dropout、L2 正則化不同數(shù)據(jù)中心的同一類別效果差距大跨站點數(shù)據(jù)分布差異使用數(shù)據(jù)協(xié)調(diào)工具按站點分層切分考慮域適應(yīng)方法功能連接矩陣中有 NaN某些 ROI 時間序列方差為 0或是掩膜外區(qū)域檢查 ROI 掩膜與功能數(shù)據(jù)的對齊情況對異常 ROI 進(jìn)行過濾顯存不足4D 數(shù)據(jù)直接輸入模型導(dǎo)致內(nèi)存爆炸先降維為功能連接矩陣或縮小 batch size圖譜與數(shù)據(jù)不對齊沒有做配準(zhǔn)或重采樣使用NiftiLabelsMasker前確認(rèn)圖譜與功能數(shù)據(jù)空間一致7.2 數(shù)據(jù)加載問題神經(jīng)影像數(shù)據(jù)的格式非常多常見的有.nii、.nii.gz、.dcmDICOM等。.nii.gz是最推薦的格式。如果你拿到的是 DICOM 文件夾需要先使用dcm2niix或dcm2nii轉(zhuǎn)換。轉(zhuǎn)換示例dcm2niix -o output_dir -f %s_%d input_dicom_dir轉(zhuǎn)換完成后再檢查文件名和方向信息不要假設(shè)所有 DICOM 轉(zhuǎn)出來都是正確方向的。7.3 fMRIPrep 運行失敗fMRIPrep 運行依賴 Docker 或 Singularity常見的失敗原因是鏡像下載失敗、環(huán)境變量未配置、內(nèi)存不足。排查步驟確認(rèn) Docker/Singularity 服務(wù)正常運行檢查磁盤空間是否充足fMRIPrep 輸出數(shù)據(jù)量通常很大查看日志尾部找到具體報錯信息如果內(nèi)存不足可以增加內(nèi)存或減少并行任務(wù)數(shù)。不建議在家用電腦上直接跑 fMRIPrep規(guī)范做法是在服務(wù)器上運行或者使用預(yù)處理過的公開數(shù)據(jù)。7.4 樣本不平衡問題神經(jīng)影像研究中患者組和對照組的人數(shù)經(jīng)常不平衡有些類別可能只有幾十個樣本。常見緩解辦法使用類別權(quán)重比如CrossEntropyLoss(weighttorch.tensor([1.0, 2.0]))對少數(shù)類做過采樣或者對多數(shù)類做欠采樣使用評價指標(biāo) F1-score、AUC 而不是準(zhǔn)確率在論文中同時報告 sensitivity 和 specificity。不要為了提升 accuracy 而試圖通過刪除樣本改變真實分布這樣會導(dǎo)致結(jié)果不客觀。7.5 數(shù)據(jù)泄露問題這是科研中最容易出問題的地方。數(shù)據(jù)泄露指的是訓(xùn)練集和測試集之間存在信息重疊導(dǎo)致評估結(jié)果虛高。在 fMRI 項目中最容易發(fā)生數(shù)據(jù)泄露的方式同一個被試的多次掃描分別出現(xiàn)在訓(xùn)練集和測試集沒有按站點切分導(dǎo)致測試集中的數(shù)據(jù)分布與訓(xùn)練集高度相似特征選擇時使用了全數(shù)據(jù)集的信息數(shù)據(jù)標(biāo)準(zhǔn)化時使用全數(shù)據(jù)集的均值和方差計算。最穩(wěn)妥的做法是在進(jìn)入任何特征工程或模型訓(xùn)練之前先把訓(xùn)練集、驗證集和測試集按被試級別分離并且盡量按站點分層采。8. 神經(jīng)影像深度學(xué)習(xí)的最佳實踐8.1 數(shù)據(jù)隱私與倫理合規(guī)醫(yī)學(xué)數(shù)據(jù)涉及患者隱私使用公開數(shù)據(jù)集時必須遵守數(shù)據(jù)使用協(xié)議不能隨意二次分發(fā)。如果在醫(yī)院或合作單位拿到真實患者數(shù)據(jù)需要經(jīng)過倫理審批并做到去除所有可識別信息數(shù)據(jù)加密存儲不在公共代碼倉庫提交患者數(shù)據(jù)路徑論文發(fā)表時注意被試人數(shù)的可識別風(fēng)險。這一點沒有商量余地。即使是“研究用不發(fā)表”也不能非法獲取或傳播患者數(shù)據(jù)。8.2 可復(fù)現(xiàn)性管理神經(jīng)影像分析很容易出現(xiàn)“結(jié)果不可復(fù)現(xiàn)”的問題主要原因是環(huán)境依賴復(fù)雜、預(yù)處理參數(shù)多樣、隨機種子未固定。推薦做法使用conda或 Docker 固定環(huán)境版本在代碼中固定隨機種子記錄所有預(yù)處理參數(shù)將中間產(chǎn)物命名規(guī)范帶日期或版本號代碼和配置放到 GitHub 時不要忽略 GPU 型號和 CUDA 版本的差異。8.3 模型選擇與比較深度學(xué)習(xí)模型并非唯一選擇也不是越復(fù)雜越好。在醫(yī)學(xué)影像領(lǐng)域一個關(guān)鍵原則是模型復(fù)雜度和樣本量必須匹配。樣本量在 100 到 500 時傳統(tǒng)機器學(xué)習(xí)配合功能連接特征往往比端到端深度學(xué)習(xí)效果更穩(wěn)定樣本量達(dá)到幾千甚至幾萬時深度學(xué)習(xí)模型才能發(fā)揮優(yōu)勢。因此如果項目樣本量不大優(yōu)先從線性模型和 SVM 開始深度學(xué)習(xí)作為更強大的方案進(jìn)行比較。8.4 可視化與可解釋性醫(yī)學(xué)領(lǐng)域?qū)山忉屝砸筝^高審稿人也很難接受一個完全黑箱的分類器。常用的可解釋性分析手段使用 Grad-CAM 查看模型關(guān)注哪些腦區(qū)對功能連接特征進(jìn)行置換重要性分析對比患者組與對照組的功能連接差異使用 t 檢驗并做 FDR 校正使用稀疏模型Lasso、稀疏邏輯回歸直接得到有意義的特征權(quán)重??山忉屝苑治霾粌H能增加論文的說服力也能幫助你發(fā)現(xiàn)模型的潛在問題例如模型可能學(xué)到了站點偽跡而不是真實疾病信號。8.5 計算資源與訓(xùn)練效率醫(yī)學(xué)影像項目的特點是數(shù)據(jù)大、樣本少、訓(xùn)練時間短。一臺普通的 24GB 顯存 GPU 就足以支撐絕大多數(shù)實驗。真正耗時的往往是預(yù)處理比如 fMRIPrep 和配準(zhǔn)任務(wù)多、I/O 頻繁。效率方面的建議預(yù)處理只做一次不要每次訓(xùn)練前重復(fù)運行將中間數(shù)據(jù)保存為.npy或.npy格式避免每次讀取 NIfTI 的解析開銷使用DataLoader時設(shè)置num_workers默認(rèn)值很低時需要調(diào)整如果數(shù)據(jù)太大先做 ROI 級摘要再進(jìn)模型。9. 從零開始的完整學(xué)習(xí)路徑對于零基礎(chǔ)想切入神經(jīng)影像 AI 的同學(xué)學(xué)習(xí)路徑比具體某個工具更重要。這里給出一個分階段的學(xué)習(xí)路線。階段一掌握 Python 與深度學(xué)習(xí)基礎(chǔ)約 1-2 個月不需要完全精通但至少能熟練Numpy 數(shù)組操作切片、廣播、矩陣運算PyTorch 基礎(chǔ)Tensor、Dataset、DataLoader、模型定義、訓(xùn)練循環(huán)CNN 的基本原理卷積、池化、全連接、反向傳播經(jīng)典模型結(jié)構(gòu)ResNet、VGG 的基本組成。推薦的練習(xí)題目不是醫(yī)療圖像分類而是先跑熟 CIFAR-10 或 MNIST把訓(xùn)練一整套模型的流程搞清楚。階段二熟悉神經(jīng)影像數(shù)據(jù)與工具約 1-2 個月這個階段目標(biāo)是從零加載一個 fMRI 數(shù)據(jù)并完成最基本的分析和可視化。需要掌握NIfTI 數(shù)據(jù)格式和 4D 數(shù)據(jù)的概念nibabel 讀取數(shù)據(jù)的基本操作nilearn 中NiftiMasker、NiftiLabelsMasker和NiftiSpheresMasker的用法如何用plotting.plot_connectome可視化功能連接功能連接和 ROI 分析的基本概念。可以參考 nilearn 官方教程中關(guān)于靜息態(tài) fMRI 的分析部分把每個 example 手動跑一遍。階段三跑通一個完整的疾病分類項目約 2 個月選擇一個公開數(shù)據(jù)集比如 ABIDE 或 COBRE做一遍從數(shù)據(jù)下載、預(yù)處理、特征提取、SVM 分類、深度學(xué)習(xí)模型到結(jié)果分析的全流程。注意不要在這個階段過度糾結(jié)于刷性能先跑通整個流程是最重要的。完成一個端到端的小項目后你對整個領(lǐng)域的理解會有一個質(zhì)變。階段四深入研究和選題長期在掌握了基本流程之后可以結(jié)合自己的領(lǐng)域背景選擇細(xì)分方向如果擅長算法可以研究跨站點泛化、自監(jiān)督預(yù)訓(xùn)練、圖神經(jīng)網(wǎng)絡(luò)等方向如果熟悉臨床可以針對某一種疾病做深度分析如果想做工程落地可以研究體素級模型和多模態(tài)融合如果重統(tǒng)計可以深入學(xué)習(xí)功能連接分析和因果分析。持續(xù)關(guān)注神經(jīng)影像領(lǐng)域的頂級會議和期刊例如 OHBMOrganization for Human Brain Mapping、MICCAI、NeuroImage、Human Brain Mapping 等。復(fù)現(xiàn)優(yōu)秀的論文代碼是快速提升研究水平的最有效方式。寫在最后神經(jīng)影像 AI 不是最容易的方向但確實是一個值得投入的方向。它既有真實臨床需求的牽引又有腦科學(xué)問題的深度同時臨床上的人才缺口也相對大。入門最大的障礙不是難度而是資料分散、流程不規(guī)范帶來的挫敗感。通過這篇教程建議先跑通 ABIDE 或 COBRE 的一個小型分類實驗把數(shù)據(jù)處理流程和模型建立過程完整走一遍再逐步深入新的方法。腦影像數(shù)據(jù)是 4D 時空數(shù)據(jù)與普通 CV 有本質(zhì)區(qū)別學(xué)會處理這種數(shù)據(jù)本身也是一種很有遷移價值的技能。如果教程中哪一步還不清楚建議在真實數(shù)據(jù)上多試幾次很多問題會自己在動手過程中浮現(xiàn)出來。