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 BlockDecoder BlockLong-skip Residual適用情境
UNet1UNetConvBlockUNetUpBlock跨模態差異大(MRI→CT)
ResUNet2residualUnitUNetUpResBlock同上 + 更深網路需求
UNet_LRes3UNetConvBlockUNetUpBlockout = last + input同模態增強(low→high dose)
ResUNet_LRes4residualUnitUNetUpResBlockout = 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 / MSE
  • Loss_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.pyprint 語句、xrangerange
runCTRecon.pyprint optprint(opt)
runTesting_Reconv2.py同上
Unet2d_pytorch.pyinit.xavier_uniforminit.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
框架PyTorchTensorFlow
維護狀態較活躍原始版本
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; 用於法規評估的虛擬影像臨床試驗) 框架的輸入:

  1. 使用 medSynthesisV1 合成多模態影像 → 擴增虛擬 cohort
  2. 將合成影像餵入 VICTRE pipeline → 評估影像生物標記的檢測效能
  3. 產生統計報告 → 支援 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 世代侷限。