brain-synthesis-lesion-segmentation 完整教學

Repository: https://github.com/harshitAgr/brain-synthesis-lesion-segmentation Stars: 40 | Fork: 33 | Language: Python (TensorFlow) Tags: brain, GAN, NVIDIA-DLI 論文: Medical Image Synthesis for Data Augmentation and Anonymization using Generative Adversarial Networks 最後更新: 2025-12-01

2. 核心架構

2.1 整體管線


graph TD
    subgraph 資料準備
        A[ISLES'18 原始 NIfTI] -->|預處理 Notebook| B[2D PNG 切片
或 3D PKL 體積] end subgraph 模型訓練 B --> C{選擇模式} C -->|無條件| D[GAN 2D
gan2d.py] C -->|條件式 2D| E[pix2pix 2D
pix2pix2d.py] C -->|條件式 3D| F[pix2pix 3D
pix2pix3d.py] end subgraph Generator 架構 G[Input Image
CT Perfusion] --> H[U-Net Encoder
8 層 Downsample] H --> I[Bottleneck
1x1x512] I --> J[U-Net Decoder
7 層 Upsample + Skip] J --> K[Output
合成病灶標籤] end subgraph Discriminator 架構 L[Input + Target
或 Input + Generated] --> M[PatchGAN
70x70 patches] M --> N[Real / Fake
判別] end subgraph 後處理 E --> O[2D 預測 PNG] F --> P[3D 預測 PKL] O -->|merge_2d_test_to_nii.py| Q[NIfTI 輸出] P -->|convert_3d_test_to_nii.py| Q end style G fill:#e1f5fe style K fill:#c8e6c9 style Q fill:#fff3e0

2.2 Generator 詳細架構(U-Net + Skip Connections)

Generator(生成器)採用經典 U-Net(U 型網路)架構,包含:

  • Encoder(編碼器):8 層 Downsample block,每層包含 Conv2D/Conv3D (stride=2) + BatchNorm + LeakyReLU,逐步將空間解析度從 256x256 壓縮到 1x1。
  • Decoder(解碼器):7 層 Upsample block,每層包含 Conv2DTranspose/Conv3DTranspose (stride=2) + BatchNorm + Dropout(0.5, 前三層) + ReLU + Skip Connection(跳接連接),與 Encoder 對應層 concatenate。
  • 最終輸出:Conv2DTranspose → Tanh activation,輸出 3 通道影像([-1, 1] 範圍)。

關鍵設計:前三層 Decoder 使用 Dropout (50%) 作為正則化(Regularization; 正則化),避免 GAN 對小資料集的 mode collapse(模式崩潰)。

2.3 Discriminator 詳細架構(PatchGAN)

Discriminator(判別器)採用 PatchGAN(Patch-based Discriminator; 基於影像區塊的判別器),在 70x70 pixel patch 上做真假判別:

  • 接收 [input_image, target/generated] concatenated 的 6 通道輸入
  • 4 層 Conv2D (stride=2) + BatchNorm + LeakyReLU 逐步下採樣
  • 最終 Conv2D 輸出 1 通道 patch-level 判別結果
  • 使用 ResNet-style 的 _IdentityBlock_ConvBlock 作為基礎 building block

2.4 損失函數設計

1Total Generator Loss = GAN Loss + λ * L1 Loss
  • GAN Loss:Sigmoid cross-entropy,讓 Generator 騙過 Discriminator
  • L1 Loss:生成影像與 ground truth 的逐像素絕對差異(pixel-wise absolute difference)
  • λ = 100:L1 loss 權重(強調結構保真度 > 對抗訓練)
  • Patch-based Discriminator Loss:針對 70x70 patch 採樣 1000 個 patch 分別判別,聚焦病灶區域

2.5 2D vs 3D 模式差異

特性pix2pix 2Dpix2pix 3D
卷積層Conv2D / Conv2DTransposeConv3D / Conv3DTranspose
輸入尺寸(bs, 256, 256, 3)(bs, 24, 256, 256, 3)
Patch 尺寸70x7024x70x70
資料載入PNG 圖片PKL 序列化體積
輸出轉換merge_2d → NIfTIconvert_3d → NIfTI
Stride 設計均勻 stride=2非均勻 stride(z 軸 [1] 或 [3])

3D 版本的 stride 設計值得注意:z 軸(切片方向)僅在特定層使用非 1 的 stride,因為 ISLES'18 的 z 方向解析度(24 slices)遠低於 xy 平面(256x256),若全方向等比下採樣會導致 z 軸過早歸零。


3. 安裝與設定

3.1 環境需求

注意:本專案使用 TensorFlow 1.x Eager Execution API(tf.contrib.eagertf.enable_eager_execution()),不相容 TensorFlow 2.x。建議使用虛擬環境隔離。

套件版本建議用途
Python3.6-3.7TF 1.x 相容
TensorFlow (GPU)1.12-1.15核心框架
CUDA9.0-10.0GPU 加速
cuDNN7.xGPU 加速
nibabel>= 2.3NIfTI 讀寫
scipy< 1.3scipy.misc.imread / imsave
matplotlib>= 2.x視覺化
seaborn>= 0.9視覺化
glob2>= 0.6遞迴檔案搜尋
Pillow (PIL)>= 5.x影像處理

3.2 安裝步驟

 1# 建議使用 conda 建立 TF 1.x 隔離環境
 2conda create -n brain-synth python=3.7
 3conda activate brain-synth
 4
 5# 安裝 TensorFlow 1.x GPU 版
 6pip install tensorflow-gpu==1.15
 7
 8# 安裝相依套件
 9pip install nibabel scipy==1.2.1 matplotlib seaborn glob2 Pillow
10
11# 複製專案
12git clone https://github.com/harshitAgr/brain-synthesis-lesion-segmentation.git
13cd brain-synthesis-lesion-segmentation

3.3 資料準備

取得 ISLES'18 資料

  1. 前往 ISLES'18 Challenge 註冊並下載資料
  2. 解壓縮至 datasets/ISLES2018/ 目錄

預處理(2D 模式)

使用 utils/isles18_sample_2d.ipynb

1# 啟動 Jupyter Notebook 進行預處理
2jupyter notebook utils/isles18_sample_2d.ipynb

此 notebook 會將 NIfTI 格式的多序列 CTP 影像轉為 256x256 PNG 切片,分別存成 input image (Image A) 和 label (Image B) 的配對資料夾。

預處理(3D 模式)

使用 utils/isles18_sample_3d.ipynb,將多序列影像與標籤封裝成 PKL(Python Pickle)格式的 3D 體積。

3.4 目錄結構

 1brain-synthesis-lesion-segmentation/
 2├── gan2d.py                        # GAN 2D 訓練入口
 3├── pix2pix2d.py                    # pix2pix 2D 訓練入口
 4├── pix2pix3d.py                    # pix2pix 3D 訓練入口
 5├── models/
 6   ├── gan2d.py                    # GAN Generator + Discriminator
 7   ├── pix2pix2d.py                # pix2pix 2D U-Net Generator + PatchGAN
 8   ├── pix2pix3d.py                # pix2pix 3D U-Net Generator + PatchGAN
 9   ├── blocks2d.py                 # ResNet-style 2D building blocks
10   └── blocks3d.py                 # ResNet-style 3D building blocks
11├── data/
12   ├── gan2d_loader.py             # GAN 2D 資料載入器
13   ├── pix2pix2d_loader.py         # pix2pix 2D 配對資料載入器
14   └── pix2pix3d_loader.py         # pix2pix 3D 配對資料載入器
15└── utils/
16    ├── isles18_sample_2d.ipynb     # 2D 預處理 notebook
17    ├── isles18_sample_3d.ipynb     # 3D 預處理 notebook
18    ├── merge_2d_test_to_nii.py     # 2D 預測結果 → NIfTI
19    └── convert_3d_test_to_nii.py   # 3D 預測結果 → NIfTI

4. 使用方式與程式碼範例

4.1 範例一:無條件 GAN 2D 腦切片生成

這是最基礎的模式——從隨機雜訊生成 64x64 灰階腦部切片,用於理解 GAN 基本原理。

 1# === 執行 GAN 2D 訓練 ===
 2# 前置條件:已將腦部切片 PNG 存至 data_dir
 3
 4python gan2d.py --data_dir=./datasets/brain_slices_png/
 5
 6# --- 底層運作說明 ---
 7# gan2d.py 內部流程:
 8#
 9# 1. 資料載入:data/gan2d_loader.py
10#    - 讀取 data_dir 下所有 .png,resize 到 64x64,歸一化到 [-1, 1]
11#    - dataset = tf.data.Dataset.from_tensor_slices(files)
12#    - batch_size = 256, prefetch = 256 * 4
13#
14# 2. 模型初始化:models/gan2d.py
15#    - Generator: noise(100) → Dense(8*8*64) → 5 層 Conv2DTranspose → tanh → (64,64,1)
16#    - Discriminator: (64,64,1) → 5 層 Conv2D → Dense(1) → real/fake
17#
18# 3. 訓練迴圈(150 epochs):
19#    - noise = tf.random_normal([256, 100])
20#    - gen_loss = sigmoid_cross_entropy(ones, D(G(noise)))
21#    - disc_loss = sigmoid_cross_entropy(ones, D(real)) + sigmoid_cross_entropy(zeros, D(G(noise)))
22#    - 每 1 epoch 存圖,每 15 epoch 存 checkpoint
23
24# 4. 輸出:image_at_epoch_XXXX.png(4x4 grid 的生成結果)

學習重點:此模式展示了 GAN 的基礎架構,但無條件生成無法控制輸出內容。在醫學影像場景中,我們需要 條件式 生成——指定輸入影像後生成對應的標籤或合成影像。

4.2 範例二:pix2pix 2D 條件式影像合成(核心用法)

這是本專案最核心的模式——從 CT Perfusion 影像(多序列)合成對應的中風病灶分割標籤。

 1# === pix2pix 2D 訓練 ===
 2python pix2pix2d.py \
 3  --data_dir=./datasets/isles18_2d/train/ \
 4  --test_dir=./datasets/isles18_2d/test/ \
 5  --output_file_dir=./output_2d/ \
 6  --disc_dim_method=patch-based \
 7  --swap_noise_imB_channel_13=True
 8
 9# --- 關鍵參數說明 ---
10# --data_dir            : 訓練資料目錄(含 imageA/ 和 imageB/ 子目錄)
11# --test_dir            : 測試資料目錄
12# --output_file_dir     : 輸出目錄(訓練過程圖 + 測試預測)
13# --disc_dim_method     : 判別器策略(patch-based 為 70x70 patch 採樣)
14# --swap_noise_imB_channel_13 : 通道交換雜訊增強(10% 機率觸發)
15
16# === 底層流程 ===
17#
18# 1. 資料載入(data/pix2pix2d_loader.py):
19#    - load_image(imageA_path, imageB_path, is_train=True)
20#    - 訓練時:resize 到 300x300 → random crop 到 256x256 → 50% 機率水平翻轉
21#    - 測試時:直接 resize 到 256x256
22#    - 歸一化到 [-1, 1]
23#
24# 2. 資料增強(pix2pix2d.py train()):
25#    - swap_noise_imB_channel_13:10% 機率翻轉 target 通道順序 + 加入 Gaussian noise
26#    - 這是為了防止 Generator 過度依賴特定通道順序
27#
28# 3. 訓練損失:
29#    gen_total_loss = gan_loss + LAMBDA(100) * l1_loss
30#    disc_loss = real_loss + generated_loss
31#    + patch-based: 從病灶區域採樣 1000 個 70x70 patch 做額外判別
32#
33# 4. 測試推論:
34#    prediction = generator(test_input, training=True)  # BN 用 batch stats
35#    prediction[prediction > 0.5] = 1  # 二值化閾值
36
37# === 測試結果轉 NIfTI ===
38python utils/merge_2d_test_to_nii.py
39# 將各切片 PNG 依 case 合併回 3D NIfTI 格式,供醫學影像軟體(如 ITK-SNAP)檢視

關鍵設計亮點

  • Patch-based Discriminator:不是對整張圖做一次真假判別,而是聚焦在病灶區域的 70x70 patch 上。因為中風病灶在整張腦部影像中通常只佔很小面積(<5%),全圖判別會讓 Discriminator 忽略病灶細節。
  • 通道交換雜訊:CTP 多序列(CBF/CBV/MTT)在不同通道中呈現不同的灌注特徵,隨機交換通道並加 noise 可迫使 Generator 學習更泛化的特徵表示。
  • 推論時 training=True:刻意使用 batch statistics 而非 accumulated statistics,因為訓練集太小,accumulated BN statistics 不可靠。

4.3 範例三:pix2pix 3D 全體積合成

3D 模式直接處理整個腦部 3D 體積,保留了切片間的空間連續性(Inter-slice Spatial Continuity; 切片間空間連續性)。

 1# === pix2pix 3D 訓練 ===
 2python pix2pix3d.py \
 3  --data_dir=./datasets/isles18_3d/train/ \
 4  --test_dir=./datasets/isles18_3d/test/ \
 5  --output_file_dir=./output_3d/ \
 6  --disc_dim_method=patch-based
 7
 8# === 底層差異(vs 2D) ===
 9#
10# 1. 資料載入(data/pix2pix3d_loader.py):
11#    - 從 PKL 載入 3D 體積(24 x 256 x 256 x channels)
12#    - 訓練增強僅做水平翻轉(np.flip(image, 2))
13#    - 3D random cropping 因計算量過大已在原始碼中註解掉
14#
15# 2. Generator 架構差異:
16#    - Conv3D / Conv3DTranspose 取代 Conv2D / Conv2DTranspose
17#    - 非均勻 stride 設計:
18#      down4-down7: stride=[1,2,2]  (z 軸不縮)
19#      down8:       stride=[3,2,2]  (z 軸從 3→1)
20#      up1:         stride=[3,2,2]  (z 軸從 1→3)
21#      up2-up5:     stride=[1,2,2]  (z 軸不擴)
22#    - 理由:z 解析度 24 << xy 解析度 256
23#
24# 3. Patch 尺寸:[24, 70, 70](整個 z 深度 x 70x70 xy patch)
25#
26# 4. 測試輸出為 PKL → 需轉換為 NIfTI:
27
28# === 測試結果轉 NIfTI ===
29python utils/convert_3d_test_to_nii.py
30# 從 PKL 載入 3D 預測,對齊原始 CT 空間資訊後存為 NIfTI
31# 重要:使用原始 CT 的 data dtype 和 affine matrix 確保空間一致性

3D 模式的實務考量

  • 記憶體需求顯著增加:24x256x256x3 的 float32 體積約 18 MB/sample,加上 Generator 中間層記憶體,單張 GPU 至少需 12 GB VRAM
  • BATCH_SIZE = 1 是硬性限制,無法增大
  • 3D 模式的優勢在於保留了切片間的解剖連續性,避免 2D 模式中相鄰切片預測不一致的問題

5. 在生醫影像合成生態系中的定位

5.1 Domain 2 子領域歸屬

本專案屬於 Sub-domain E: Specialized Applications(特化應用),具體對應「腦部影像合成(Brain Image Synthesis; 腦部影像合成)」方向。


graph LR
    subgraph "Domain 2: 生醫影像合成"
        A["A. 平台工具
nnUNet / MONAI /
MONAI GenModels"] B["B. 計算病理
CLAM / CONCH /
Patho-GAN"] C["C. 跨模態合成
medSynthesisV1 /
medSynthesis /
Synthetic-CT"] D["D. Diffusion 模型
conditional_DDPM /
DenseDiffusion /
SD-Messenger"] E["E. 特化應用
VICTRE / medigan /
brain-synthesis"] F["F. 癌症影像
foundation-cancer-
image-biomarker"] end E --> E1["brain-synthesis
★ 本專案"] E --> E2["VICTRE
虛擬臨床試驗"] E --> E3["medigan
統一生成 API"] style E1 fill:#ffcc80,stroke:#e65100,stroke-width:3px style E fill:#fff3e0

5.2 與同生態系專案的比較

維度brain-synthesis (本專案)medSynthesisV1conditional_DDPMmedigan
生成方法pix2pix (cGAN)3D U-Net cGANDDPM (Diffusion)多模型聚合
目標任務CT→病灶標籤MRI→CT 跨模態無條件/條件式生成統一 API
維度支援2D + 3D3D2D視後端而定
框架TensorFlow 1.xPyTorchPyTorchPyTorch
教學導向NVIDIA DLI workshop研究導向研究導向工程導向
隱私應用匿名化合成

5.3 在藥物開發中的應用場景

  1. 影像生物標記驗證(Imaging Biomarker Validation; 影像生物標記驗證):合成帶有已知病灶的腦部影像,作為影像分析管線的 ground truth 基準。當開發中風治療藥物需要評估「治療後病灶體積縮小」這個療效指標時,合成影像可用於驗證量測演算法的準確性。

  2. 虛擬臨床試驗資料增強(Virtual Trial Data Augmentation; 虛擬試驗資料增強):在 Phase II 影像學終點評估中,若實際收案量不足,可使用合成資料輔助訓練自動化分析模型。但須注意:合成資料僅能用於工具開發,不能替代臨床證據

  3. 隱私保護的多中心研究(Privacy-preserving Multi-site Studies; 隱私保護多中心研究):將各機構的影像風格轉為合成影像後分享,保留病灶解剖特徵但移除個人可識別資訊(PII; 個人可識別資訊)。


6. 與其他工具的整合

6.1 與 MONAI / nnUNet 的整合

本專案的合成影像可作為 MONAI 或 nnUNet 分割管線的額外訓練資料:

 1# 概念範例:將 brain-synthesis 產出的合成資料注入 MONAI 訓練管線
 2
 3import nibabel as nib
 4from monai.transforms import (
 5    Compose, LoadImaged, EnsureChannelFirstd,
 6    ScaleIntensityd, RandCropByPosNegLabeld
 7)
 8from monai.data import CacheDataset, DataLoader
 9
10# 1. 收集真實資料 + 合成資料
11real_data = [
12    {"image": f"real_case_{i}/ct.nii", "label": f"real_case_{i}/label.nii"}
13    for i in range(63)
14]
15
16# brain-synthesis 產出的合成 NIfTI(由 merge_2d_test_to_nii.py 或 convert_3d_test_to_nii.py 生成)
17synthetic_data = [
18    {"image": f"synthetic_case_{i}/ct.nii", "label": f"synthetic_case_{i}/label.nii"}
19    for i in range(200)  # 合成 200 例額外資料
20]
21
22# 2. 合併資料集(真實 + 合成)
23combined = real_data + synthetic_data
24
25# 3. 定義 MONAI transform pipeline
26transforms = Compose([
27    LoadImaged(keys=["image", "label"]),
28    EnsureChannelFirstd(keys=["image", "label"]),
29    ScaleIntensityd(keys=["image"]),
30    RandCropByPosNegLabeld(
31        keys=["image", "label"],
32        label_key="label",
33        spatial_size=(96, 96, 96),
34        pos=1, neg=1, num_samples=4
35    ),
36])
37
38# 4. 建立 DataLoader
39dataset = CacheDataset(data=combined, transform=transforms, cache_rate=1.0)
40loader = DataLoader(dataset, batch_size=2, shuffle=True)
41
42# 注意:合成資料的品質直接影響下游分割效能
43# 建議做法:先訓練 → 合成 → 人工品質審核 → 過濾 → 再注入訓練

6.2 與 AIKT Pipeline 的整合

1AIKT inbox/     ← brain-synthesis 論文筆記 + 合成影像品質報告
2AIKT projects/  ← 合成資料生成實驗管理
3  └── research-YYMMDD-brain-synth/
4      ├── models/           # 訓練好的 Generator checkpoint
5      ├── synthetic_nifti/  # 合成 NIfTI 輸出
6      ├── quality_report.md # FID / SSIM / Dice 評估
7      └── integration.md    # 與下游管線整合紀錄

6.3 從 TensorFlow 1.x 遷移到 PyTorch 的考量

由於本專案使用已停止維護的 TensorFlow 1.x API,在實際應用中建議遷移至 PyTorch。核心映射如下:

TF 1.x 元件PyTorch 對應
tf.keras.layers.Conv2Dtorch.nn.Conv2d
tf.keras.layers.Conv2DTransposetorch.nn.ConvTranspose2d
tf.keras.layers.BatchNormalizationtorch.nn.BatchNorm2d
tf.GradientTape()loss.backward() + optimizer.step()
tf.contrib.eager.defun不需要(PyTorch 預設 eager)
tf.data.Datasettorch.utils.data.DataLoader

若需要 3D 版本,MONAI 已內建 pix2pix-style generator,可直接使用 monai.networks.nets.UNet 作為 Generator backbone。


7. 優缺點分析

7.1 優點

面向說明
教學價值高源自 NVIDIA DLI workshop,程式碼結構清晰、註解完整,是學習醫學影像 GAN 的優秀入門教材
2D + 3D 雙模式同時提供 2D 切片和 3D 體積的實作,方便比較兩種方法的優劣
Patch-based Discriminator針對醫學影像中「病灶佔比極小」的特性設計,聚焦在病灶區域做判別
資料增強策略完整包含 random jittering、mirroring、通道交換雜訊等多種增強手段
端到端 Pipeline從預處理 Notebook 到 NIfTI 輸出轉換都有提供
雙重應用目標同時解決 data augmentation 和 data anonymization

7.2 缺點與限制

面向說明
框架過時TensorFlow 1.x + tf.contrib.eager 已不受支持,TF 2.x 不相容
依賴已棄用 APIscipy.misc.imread/imsave 在 scipy >= 1.3 已移除
缺乏量化評估repo 中無 FID (Frechet Inception Distance; 弗雷謝起始距離)、SSIM (Structural Similarity; 結構相似度)、Dice Score 等標準評估指標的實作
無預訓練模型未提供訓練好的 checkpoint,使用者需自行訓練
資料集取得門檻ISLES'18 需註冊申請,BRATS/ADNI 有嚴格的資料使用協議
無 License未宣告開源授權,法律使用有不確定性
記憶體效率3D 模式 batch_size 被限制為 1,訓練效率受限
無自動化管線缺少 Dockerfile、requirements.txt、Makefile 等標準化工程設施

7.3 與 Diffusion Model (DM) 方法的比較

本專案使用的 pix2pix (cGAN) 方法已是 2018 年的技術,當前醫學影像合成領域已逐步轉向 Diffusion Model。比較如下:

維度pix2pix (cGAN)Diffusion Model (DDPM)
訓練穩定性較差(mode collapse 風險)較好(穩定收斂)
影像品質中等(容易出現棋盤格偽影)高(細節更豐富)
推論速度快(單次前向傳播)慢(需數百步反向擴散)
條件控制強(paired image-to-image)中等(需額外 conditioning 機制)
記憶體需求中等
3D 支援本專案已有實作仍在研究階段

7.4 藍海機會

  1. 3D 體積合成的 Diffusion 化:將本專案的 3D pix2pix 架構升級為 3D Latent Diffusion Model (LDM; 潛在擴散模型),結合 MONAI GenerativeModels 的 3D LDM 框架。
  2. 多模態腦部合成:CT→MRI→PET 的連鎖合成,一次生成多模態的配對資料,減少多模態研究中的 missing modality 問題。
  3. 隱私保護的聯邦合成(Federated Synthesis; 聯邦合成):在 Federated Learning 架構下訓練 Generator,各機構的原始資料不離開本地,只共享模型權重。
  4. 病灶可控合成(Lesion-controllable Synthesis; 病灶可控合成):整合 text-guided 或 layout-guided 機制,讓使用者指定病灶位置、大小和類型後生成對應影像。

一行摘要: brain-synthesis-lesion-segmentation 是 NVIDIA DLI workshop 的教學級 pix2pix cGAN 實作,提供 2D/3D 雙模式從 CT Perfusion 合成腦中風病灶標籤,架構清晰適合入門學習,但 TF 1.x 框架已過時,實務應用建議遷移至 PyTorch/MONAI 並考慮 Diffusion Model 替代方案。