medSynthesisV1 完整教學
Repository: https://github.com/ginobilinie/medSynthesisV1 Stars: 195 | Fork: 45 | Language: Python | License: MIT Tags: medical-synthesis, WGAN-GP, PyTorch 論文: Medical Image Synthesis with Deep Convolutional Adversarial Networks (IEEE TBME 2018) 作者: Dong Nie et al., UNC Chapel Hill / Shen Lab
2. 核心架構
2.1 系統總覽
graph TD
subgraph 資料準備
A[原始醫學影像
NIfTI / Analyze / MetaImage] --> B[extract23DPatch
擷取 2D/2.5D/3D patch]
B --> C[HDF5 檔案
dataMR + dataCT keys]
end
subgraph 訓練迴路
C --> D[Generator_2D_slices
批次資料載入器]
D --> E{Generator 選擇}
E -->|whichNet=1| F1[UNet]
E -->|whichNet=2| F2[ResUNet]
E -->|whichNet=3| F3[UNet_LRes]
E -->|whichNet=4| F4[ResUNet_LRes
預設 推薦]
F1 & F2 & F3 & F4 --> G[合成影像 y_hat]
G --> H{損失函數組合}
H --> H1[L1 / RTL1 / MSE]
H --> H2[GDL 梯度差異損失]
H --> H3[Adversarial Loss
WGAN-GP / BCE]
G --> I[Discriminator
CNN 3-layer + FC]
I --> H3
end
subgraph 推論
J[測試影像] --> K[載入訓練好的 Generator]
K --> L[合成輸出 CT/PET]
L --> M[SSIM / MAE / PSNR 評估]
end
style F4 fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
style H3 fill:#fff3e0,stroke:#f57c00,stroke-width:2px
2.2 四種 Generator 架構比較
| 架構 | 編號 | Encoder Block | Decoder Block | Long-skip Residual | 適用情境 |
|---|---|---|---|---|---|
| UNet | 1 | UNetConvBlock | UNetUpBlock | 無 | 跨模態差異大(MRI→CT) |
| ResUNet | 2 | residualUnit | UNetUpResBlock | 無 | 同上 + 更深網路需求 |
| UNet_LRes | 3 | UNetConvBlock | UNetUpBlock | 有 out = last + input | 同模態增強(low→high dose) |
| ResUNet_LRes | 4 | residualUnit | UNetUpResBlock | 有 out = last + input + Dropout | 同模態增強(預設推薦) |
Long-skip Residual Connection (長跳殘差連接) 的設計邏輯:當輸入與輸出模態相似時(如 low-dose PET → standard PET),網路只需學習「差異量」(residual),而非完整重建,收斂更快且品質更高。
2.3 Discriminator 架構
1Input (1, 64, 64)
2 → Conv2d(1→32, 9×9) → ReLU → MaxPool(2×2)
3 → Conv2d(32→64, 5×5) → ReLU → MaxPool(2×2)
4 → Conv2d(64→64, 5×5) → ReLU → MaxPool(2×2)
5 → Flatten → FC(64*4*4 → 512) → ReLU
6 → FC(512 → 64) → ReLU
7 → FC(64 → 1)
當 --isWDist 啟用時,使用 WGAN-GP 損失(移除 Sigmoid,加入 Gradient Penalty),比傳統 BCE GAN 更穩定、更容易調參。
2.4 損失函數組合
最終的 Generator loss 為多項損失的加權組合:
1Loss_G = base * Loss_pixel + lambda_gdl * Loss_GDL + lambda_AD * Loss_adversarial
Loss_pixel:L1 (default) / Relative Threshold L1 / MSELoss_GDL:梯度差異損失,保留邊緣結構細節Loss_adversarial:WGAN-GP 距離或 BCE loss,提升合成影像的真實感
3. 安裝與設定
3.1 環境需求
1# 基本需求
2Python >= 2.7 # 原始碼為 Python 2;Python 3 需修改(見下方)
3PyTorch >= 0.3.0
4SimpleITK
5NumPy
6h5py
7scipy
3.2 建議安裝流程(使用 uv,Python 3 相容)
1# 1. 建立虛擬環境
2uv venv medsyn-env --python 3.10
3source medsyn-env/bin/activate
4
5# 2. 安裝依賴
6uv pip install torch torchvision SimpleITK numpy h5py scipy
7
8# 3. 取得原始碼
9git clone https://github.com/ginobilinie/medSynthesisV1.git
10cd medSynthesisV1
3.3 Python 3 相容性修改
原始碼為 Python 2 風格,需進行以下修改:
1# 自動修改 Python 2 語法為 Python 3
2# 1. print 語句 → print()
3# 2. .next() → .__next__() 或 next()
4# 3. xrange() → range()
5# 4. 字典的 .has_key() → in 運算子
6
7# 快速全域替換(建議手動逐檔檢查)
8find . -name "*.py" -exec sed -i 's/xrange/range/g' {} +
9find . -name "*.py" -exec sed -i 's/print \(.*\)/print(\1)/g' {} +
關鍵修改清單:
| 檔案 | 修改項目 |
|---|---|
utils.py | print 語句、xrange → range |
runCTRecon.py | print opt → print(opt) |
runTesting_Reconv2.py | 同上 |
Unet2d_pytorch.py | init.xavier_uniform → init.xavier_uniform_(PyTorch >= 0.4 deprecation) |
3.4 GPU 需求
- 訓練 2D/2.5D patch:單張 GPU(8 GB+ VRAM),batch size 32
- 訓練 3D patch:建議 16 GB+ VRAM,batch size 需降低
- 推論:4 GB+ VRAM 即可
4. 使用方式與程式碼範例
範例 1:資料前處理 — 擷取 HDF5 Patch
1"""
2Step 1: 將醫學影像切成 patch 並存為 HDF5
3使用 extract23DPatch4MultiModalImg.py(多模態)
4或 extract23DPatch4SingleModalImg.py(單模態)
5"""
6import os
7
8# --- 設定 patch 參數 ---
9d1 = 5 # 切面方向取 5 張(2.5D 輸入)
10d2 = 64 # patch 高度
11d3 = 64 # patch 寬度
12dFA = [d1, d2, d3] # 輸入 patch 尺寸 (MR)
13dSeg = [1, d2, d3] # 輸出 patch 尺寸 (CT,單切面)
14step1, step2, step3 = 1, 32, 32 # 滑窗步幅
15
16# --- 執行 patch 擷取 ---
17# 對每位受試者的 MRI 與對應 CT 做 patch extraction
18# 輸入格式:NIfTI (.nii.gz) / Analyze (.hdr/.img) / MetaImage (.mha/.mhd)
19# 輸出格式:HDF5 (.h5),每檔含 'dataMR' 與 'dataCT' 兩個 key
20
21# 命令列執行
22os.system("""
23python extract23DPatch4MultiModalImg.py \
24 --how2normalize 6
25""")
26
27# 執行後將產生的 .h5 檔分為兩個資料夾:
28# training_h5/ — 訓練用 patch
29# validation_h5/ — 驗證用 patch
how2normalize 參數說明(6 種正規化策略):
| 值 | 策略 | 適用情境 |
|---|---|---|
| 0 | 不做正規化 | 已預處理的資料 |
| 1 | 減均值除標準差 (z-score) | 通用 |
| 2 | 線性縮放至 [0, 1] | MRI |
| 3 | 逐受試者 z-score | 跨中心資料 |
| 4 | 百分位裁切 + 縮放 | 有極端值時 |
| 5 | 逐切面正規化 | 2D 訓練 |
| 6 | 組合策略(預設) | 一般推薦 |
範例 2:訓練 WGAN-GP ResUNet_LRes 模型
1"""
2Step 2: 使用 WGAN-GP + ResUNet_LRes 訓練跨模態合成模型
3主程式入口:runCTRecon.py
4"""
5
6# --- 完整訓練指令 ---
7# 以下為 MRI → CT 腦部合成的推薦參數組合
8
9"""
10python runCTRecon.py \
11 --gpuID 0 \
12 --whichNet 4 \
13 --isAdLoss \
14 --isWDist \
15 --lambda_AD 0.05 \
16 --lambda_D_WGAN_GP 10 \
17 --isGDL \
18 --lambda_gdl 0.05 \
19 --gdlNorm 2 \
20 --whichLoss 1 \
21 --batchSize 32 \
22 --numOfChannel_singleSource 5 \
23 --numOfChannel_allSource 5 \
24 --numofIters 200000 \
25 --lr 5e-3 \
26 --lr_netD 5e-3 \
27 --decLREvery 10000 \
28 --lrDecRate 0.5 \
29 --lrDecRate_netD 0.1 \
30 --dropout_rate 0.2 \
31 --how2normalize 6 \
32 --showTrainLossEvery 100 \
33 --saveModelEvery 5000 \
34 --showValPerformanceEvery 1000 \
35 --prefixModelName "./models/resunet_lres_wgangp_brain_" \
36 --prefixPredictedFN "./results/pred_brain_"
37"""
38
39# --- 關鍵參數解讀 ---
40# --whichNet 4 : ResUNet_LRes(殘差 UNet + 長跳連接)
41# --isAdLoss : 啟用對抗損失
42# --isWDist : 使用 WGAN-GP(而非 BCE GAN)
43# --lambda_AD 0.05 : 對抗損失權重(過大會產生 artifact)
44# --isGDL : 啟用梯度差異損失(保留邊緣)
45# --whichLoss 1 : L1 pixel loss(比 MSE 產生更銳利的影像)
46# --numOfChannel_singleSource 5 : 2.5D 輸入(取相鄰 5 張切面)
47# --decLREvery 10000 : 每 10K 迭代降低學習率
48
49# --- 需要在 runCTRecon.py 中手動設定的路徑 ---
50# path_patients_h5 : 訓練 HDF5 資料夾路徑
51# path_patients_h5_test : 驗證 HDF5 資料夾路徑
52# path_test : 測試影像路徑(完整 3D volume)
範例 3:推論 — 從 MRI 合成 CT
1"""
2Step 3: 載入訓練好的模型,對新受試者進行推論
3主程式入口:runTesting_Reconv2.py
4"""
5import torch
6import SimpleITK as sitk
7import numpy as np
8from Unet2d_pytorch import ResUNet_LRes
9
10# --- 載入模型 ---
11netG = ResUNet_LRes(in_channel=5, n_classes=1, dp_prob=0)
12netG.cuda()
13
14checkpoint = torch.load("./models/resunet_lres_wgangp_brain_200000.pt")
15netG.load_state_dict(checkpoint['model'])
16netG.eval()
17
18# --- 載入測試影像 ---
19mr_image = sitk.ReadImage("test_subject_mr.nii.gz")
20mr_array = sitk.GetArrayFromImage(mr_image) # shape: (D, H, W)
21
22# --- 逐切面推論(2.5D sliding window) ---
23# 取 5 張相鄰切面作為輸入 channel
24num_slices = mr_array.shape[0]
25ct_pred = np.zeros_like(mr_array, dtype=np.float32)
26
27with torch.no_grad():
28 for i in range(2, num_slices - 2):
29 # 擷取 2.5D patch(中心切面 +/- 2)
30 patch = mr_array[i-2:i+3, :, :] # shape: (5, H, W)
31 patch = patch[np.newaxis, ...] # shape: (1, 5, H, W)
32 patch_tensor = torch.from_numpy(patch).float().cuda()
33
34 # 殘差輸入(中心切面)
35 res_input = mr_array[i:i+1, :, :]
36 res_tensor = torch.from_numpy(res_input[np.newaxis, ...]).float().cuda()
37
38 # 推論
39 output = netG(patch_tensor, res_tensor)
40 ct_pred[i] = output.cpu().numpy().squeeze()
41
42# --- 儲存合成 CT ---
43ct_image = sitk.GetImageFromArray(ct_pred)
44ct_image.CopyInformation(mr_image) # 複製 spacing / origin / direction
45sitk.WriteImage(ct_image, "synthetic_ct.nii.gz")
46
47print("合成 CT 已儲存:synthetic_ct.nii.gz")
注意:以上推論範例為教學用簡化版。實際使用時需考慮 patch-based 推論(避免記憶體不足)、正規化一致性(訓練/推論需相同
how2normalize)、以及邊界處理。
5. 在生醫影像合成生態系中的定位
5.1 Bio-SDG Domain 2 分類定位
medSynthesisV1 屬於 Sub-domain C: Cross-modal Medical Image Synthesis (跨模態醫學影像合成),是該子領域的先驅性實作之一。
graph LR
subgraph "Domain 2: 生物醫學影像合成"
direction TB
subgraph A["A. 基礎平台"]
A1[nnUNet]
A2[MONAI]
A3[MONAI GenerativeModels]
end
subgraph B["B. 計算病理學"]
B1[CLAM]
B2[CONCH]
B3[Patho-GAN]
end
subgraph C["C. 跨模態合成"]
C1["medSynthesisV1
★ 本專案"]
C2[medSynthesis
TF 版本]
C3[Synthetic-CT]
end
subgraph D["D. Diffusion 模型"]
D1[conditional_DDPM]
D2[DenseDiffusion]
D3[SD-Messenger]
end
subgraph E["E. 特殊應用"]
E1[VICTRE]
E2[brain-synthesis]
E3[medigan]
end
subgraph F["F. 癌症影像"]
F1[foundation-cancer-
image-biomarker]
end
end
C1 -.->|TF 原版| C2
C1 -.->|可供訓練資料| E1
A3 -.->|新一代替代| D1
C1 -.->|統一 API 收納| E3
style C1 fill:#ffeb3b,stroke:#f57f17,stroke-width:3px
5.2 與姊妹專案 medSynthesis 的關係
| 面向 | medSynthesisV1 (本專案) | medSynthesis |
|---|---|---|
| 框架 | PyTorch | TensorFlow |
| 維護狀態 | 較活躍 | 原始版本 |
| WGAN-GP | 完整支援 | 部分支援 |
| 3D 支援 | 有(runCTRecon3d.py) | 有 |
| 架構選擇 | 4 種 Generator | 較少 |
| 社群使用 | PyTorch 生態系整合更佳 | TF 1.x 較難維護 |
5.3 GAN vs Diffusion:世代定位
medSynthesisV1 代表 GAN 世代 (2017-2020) 的跨模態合成方法。相較新一代 Diffusion Model (擴散模型):
| 面向 | GAN (medSynthesisV1) | Diffusion (conditional_DDPM 等) |
|---|---|---|
| 訓練穩定性 | 需調參(WGAN-GP 改善) | 較穩定 |
| 生成品質 | 銳利但可能有 artifact | 更自然,較少 artifact |
| 多樣性 | mode collapse 風險 | 天然高多樣性 |
| 推論速度 | 快(單次 forward pass) | 慢(數百步去噪) |
| 可控性 | 有限 | 可透過 conditioning 精細控制 |
| 成熟度 | 成熟穩定 | 仍在快速演進 |
實務建議:若需快速建立 baseline (基準線) 並在 production (生產環境) 中部署,GAN 方案(如 medSynthesisV1)仍是務實選擇;若追求最佳生成品質且可接受較長推論時間,建議評估 MONAI GenerativeModels 中的 Diffusion pipeline。
6. 與其他工具的整合
6.1 與 MONAI 整合
1"""
2將 medSynthesisV1 的訓練好模型包裝為 MONAI-compatible 推論 pipeline
3"""
4from monai.transforms import (
5 LoadImage, EnsureChannelFirst, Spacing,
6 ScaleIntensity, ToTensor, Compose
7)
8from monai.data import Dataset, DataLoader
9import torch
10
11# MONAI 前處理 → medSynthesisV1 推論 → MONAI 後處理
12preprocess = Compose([
13 LoadImage(image_only=True),
14 EnsureChannelFirst(),
15 Spacing(pixdim=(1.0, 1.0, 1.0)), # 統一 spacing
16 ScaleIntensity(),
17 ToTensor(),
18])
19
20# 載入 medSynthesisV1 模型
21from Unet2d_pytorch import ResUNet_LRes
22model = ResUNet_LRes(in_channel=5, n_classes=1)
23checkpoint = torch.load("trained_model.pt")
24model.load_state_dict(checkpoint['model'])
6.2 與 medigan 統一 API 整合
medigan 提供統一介面管理多種醫學影像生成模型。medSynthesisV1 的訓練好模型可透過 medigan 的 config 系統註冊,讓團隊成員透過一行程式碼呼叫。
6.3 與 VICTRE 虛擬臨床試驗整合
在藥物開發情境中,medSynthesisV1 合成的影像可作為 VICTRE (Virtual Imaging Clinical Trials for Regulatory Evaluation; 用於法規評估的虛擬影像臨床試驗) 框架的輸入:
- 使用 medSynthesisV1 合成多模態影像 → 擴增虛擬 cohort
- 將合成影像餵入 VICTRE pipeline → 評估影像生物標記的檢測效能
- 產生統計報告 → 支援 FDA submission 中的影像端點論述
6.4 與 AIKT Pipeline 整合建議
在 AI-Knowledge Template (AIKT) 架構下,medSynthesisV1 可扮演以下角色:
| AIKT Layer | 整合方式 |
|---|---|
| Layer 9 (paper-search) | 搜尋 cross-modal synthesis 最新文獻,追蹤 Nie et al. 的後續研究 |
| Layer 10 (paper-qa-lite) | 對合成品質評估論文做 RAG 問答 |
| Layer 18 (research-pipeline-v2) | 作為 imaging biomarker 管線的前處理模組 |
| Layer 19 (tu-plan-generator) | 在 ADMET/PK 評估中,合成缺失模態的 imaging endpoint |
7. 優缺點分析
優點
| 面向 | 說明 |
|---|---|
| 架構靈活 | 4 種 Generator + 2 種 GAN 訓練策略 + 3 種 pixel loss + GDL,組合彈性高 |
| WGAN-GP 支援 | 比傳統 GAN 穩定,降低 mode collapse (模式崩塌) 風險,調參更直觀 |
| Long-skip Residual | 針對「同模態增強」場景(low→high dose)的巧妙設計,加速收斂 |
| 2D/2.5D/3D 兼容 | 同一框架支援不同維度的 patch 訓練,適應不同硬體條件 |
| MIT 授權 | 可自由用於學術與商業用途 |
| 程式碼精簡 | 全專案僅 17 個檔案,核心邏輯清晰,適合教學與二次開發 |
| 公開資料集 | README 提供 Low-dose CT、IXI、BraTS、fastMRI、ISLES 等資料集連結 |
缺點
| 面向 | 說明 | 緩解方案 |
|---|---|---|
| Python 2 語法 | 原始碼為 Python 2,需手動遷移 | 用 2to3 工具或手動修改 |
| PyTorch 版本老舊 | 使用已 deprecated 的 API(如 init.xavier_uniform) | 更新為 init.xavier_uniform_ 等 in-place 版本 |
| 無 pip/setup.py | 不是標準 Python 套件,無法 pip install | 自行撰寫 pyproject.toml |
| 路徑寫死 | 訓練/測試路徑硬編碼在原始碼中 | 改為 argparse 或 config 檔案 |
| 無預訓練權重 | 不提供可直接使用的 pretrained model | 需自行訓練或聯繫作者 |
| 缺乏定量評估腳本 | 僅提供 compute3DSSIM.py,缺少 MAE/PSNR/FID 等 | 自行補充評估指標 |
| 文件不足 | 無 API 文件、無範例資料、無 Docker 設定 | 參考本教學補充 |
| GAN 世代侷限 | 相較 Diffusion Model,多樣性與品質天花板較低 | 作為 baseline 使用,重要場景改用 MONAI GenerativeModels |
綜合評價
medSynthesisV1 是一個具有學術參考價值的跨模態醫學影像合成框架。其 ResUNet_LRes + WGAN-GP 的組合在 2017-2020 年間代表了領域最佳實踐,至今仍可作為快速 baseline 或教學用途。但在 2026 年的生產環境中,建議將其視為「概念驗證 (PoC) 起點」,再依需求遷移至 MONAI GenerativeModels 或 conditional Diffusion 架構。
一行總結:medSynthesisV1 提供 4 種 UNet 變體 + WGAN-GP 的跨模態醫學影像合成 PyTorch 實作,適合作為 MRI→CT 合成的教學 baseline 與 PoC 起點,但需注意 Python 2 相容性與 GAN 世代侷限。
Comments