DenseDiffusion 完整教學
Repository: https://github.com/naver-ai/DenseDiffusion Stars: 507 | Forks: 35 | License: Apache-2.0 Tags: diffusion, dense-control, ICCV 論文: Dense Text-to-Image Generation with Attention Modulation (ICCV 2023) 作者: Yunji Kim, Jiyoung Lee, Jin-Hwa Kim, Jung-Woo Ha (NAVER AI Lab), Jun-Yan Zhu (CMU)
2. 核心架構
2.1 系統架構圖
graph TD
A["使用者輸入"] --> B["Layout Masks
空間佈局遮罩"]
A --> C["Segment Prompts
區段文字描述"]
A --> D["Master Prompt
全局文字描述"]
B --> E["Mask Preprocessing
遮罩前處理"]
C --> F["CLIP Tokenizer
文字分詞"]
D --> F
F --> G["CLIP Text Encoder
文字編碼器"]
G --> H["Text Embeddings
文字嵌入"]
E --> I["Self-Attention Reg Maps
自注意力調控圖"]
E --> J["Cross-Attention Reg Maps
交叉注意力調控圖"]
E --> K["Size Reg Maps
面積調控圖"]
H --> L["Modified UNet Forward
修改後的 UNet 前向傳播"]
I --> L
J --> L
K --> L
L --> M["DDIM Scheduler
DDIM 排程器"]
M --> N["Generated Image
生成影像"]
style A fill:#e1f5fe
style L fill:#fff3e0
style N fill:#e8f5e9
2.2 注意力調變機制
DenseDiffusion 的核心是 mod_forward 函式,它替換了 UNet 中所有 Attention 層的 __call__ 方法。調變邏輯如下:
Cross-Attention 調變 (creg):控制文字 token 與空間位置的對應關係。對於每個文字 token,根據其所屬 segment 的 mask 強化對應區域的 attention score,同時抑制非對應區域。
Self-Attention 調變 (sreg):控制空間位置之間的相互影響。同一 segment 內的 pixel 之間的 attention 被強化,不同 segment 之間的 attention 被抑制,確保各區域的視覺特徵保持獨立。
時間步衰減函式:
1treg = (timestep / 1000)^5
前 30% 的 diffusion 步驟進行調變(COUNT/32 < 50*0.3),之後關閉調變讓模型自由生成細節。這個設計確保佈局在早期步驟被固定,後期專注於高頻細節。
2.3 資料流程
sequenceDiagram
participant U as 使用者
participant P as Preprocessor
participant T as Text Encoder
participant UN as UNet (Modified)
participant S as DDIM Scheduler
U->>P: Layout masks + segment prompts
P->>P: 建立 binary masks (每個 segment)
P->>P: 多解析度插值 (64x64, 32x32, 16x16, 8x8)
P->>T: 全局 prompt + 各 segment prompt
T->>T: Token 對齊:segment prompt tokens 對應到 master prompt 中的位置
T-->>UN: cond_embeddings (條件嵌入)
loop 每個 timestep (共 50 步)
S->>UN: noisy latent
Note over UN: 前 15 步 (30%):啟用注意力調變
UN->>UN: Cross-Attn: token-region 對齊
UN->>UN: Self-Attn: region 內聚合
UN->>UN: Size regularization
UN-->>S: predicted noise
S->>S: DDIM denoise step
end
S-->>U: 生成影像
2.4 關鍵超參數
| 參數 | 符號 | 預設值 | 作用 |
|---|---|---|---|
| Cross-attention weight | w^c (creg) | 1.0 | 文字-區域對齊強度,越高則物件越嚴格限制在指定區域 |
| Self-attention weight | w^s (sreg) | 0.3 | 區域間隔離程度,越高則不同區域的視覺特徵越獨立 |
| Size regularization | sizereg | 1.0 | 面積自適應調整強度,防止大區域主導小區域 |
| Timestep threshold | 30% | 15/50 步 | 前 30% 步驟做調變,後 70% 自由生成 |
| Max segments | MAX_COLORS | 12 | 最多支援 12 個獨立區域 |
3. 安裝與設定
3.1 環境需求
- Python 3.8+
- CUDA-capable GPU(建議 VRAM >= 8 GB,Stable Diffusion v1.5 基底)
- Hugging Face 帳號與 access token(用於下載 SD v1.5 權重)
3.2 安裝步驟
1# 1. 建立虛擬環境(使用 uv,符合 AIKT 規範)
2uv venv .venv --python 3.10
3source .venv/bin/activate
4
5# 2. Clone repository
6git clone https://github.com/naver-ai/DenseDiffusion.git
7cd DenseDiffusion
8
9# 3. 安裝依賴(注意版本鎖定)
10uv pip install -r requirements.txt
11
12# requirements.txt 內容:
13# diffusers==0.20.2
14# transformers==4.28.0
15# gradio==3.43.2
16# accelerate
版本警告:程式碼在啟動時會檢查
diffusers.__version__ != '0.20.2'並強制退出。這是因為mod_forward函式直接 monkey-patch UNet 的 Attention 層內部 API,不同版本的 diffusers 會改變此 API。若需升級,必須對照新版 diffusers 的Attention.__call__簽名重寫mod_forward。
3.3 設定 Hugging Face Token
1# 方式一:環境變數
2export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxx"
3
4# 方式二:修改 gradio_app.py 第 77 行
5# HF_TOKEN = 'hf_xxxxxxxxxxxxxxxxxxxxxxxx'
6
7# 方式三:huggingface-cli 登入(推薦)
8huggingface-cli login
3.4 啟動 Gradio 介面
1python gradio_app.py
2# 預設啟動於 http://0.0.0.0:7860
3.5 常見安裝問題
| 問題 | 原因 | 解決方案 |
|---|---|---|
Please use diffusers v0.20.2 | 版本不符 | uv pip install diffusers==0.20.2 |
| CUDA out of memory | VRAM 不足 | 使用 variant="fp16" (已預設) 或降低 batch size |
| 模型下載失敗 | HF Token 未設定 | 執行 huggingface-cli login |
| Gradio 介面無法連線 | 防火牆或 port 衝突 | 加 --share 參數或改 port |
4. 使用方式與程式碼範例
4.1 範例一:Gradio 互動式介面
Gradio 介面提供完整的四步驟工作流:
1# gradio_app.py 已包含完整流程,直接啟動即可
2# python gradio_app.py
3
4# 四步驟操作流程:
5# Step 1: 在 canvas 上用不同顏色繪製佈局
6# Step 2: 為每個顏色區段(segment)輸入文字描述
7# Step 3: 調整全局描述文字(預設為各 segment 文字的串接)
8# Step 4: 調整超參數並生成
9
10# 超參數建議:
11# - w^c (creg) = 1.0:標準文字-區域對齊
12# - w^s (sreg) = 0.3:適度的區域隔離
13# - sizereg = 1.0:完全啟用面積自適應
4.2 範例二:程式化批次生成(生醫影像應用)
以下範例展示如何將 DenseDiffusion 用於程式化的批次生成,適合生醫影像合成場景:
1"""
2DenseDiffusion 程式化批次生成範例
3適用場景:批次合成具有指定組織佈局的病理影像
4"""
5import torch
6import numpy as np
7from PIL import Image
8import torch.nn.functional as F
9import diffusers
10from diffusers import DDIMScheduler
11
12# ---- 載入模型 ----
13device = "cuda"
14pipe = diffusers.StableDiffusionPipeline.from_pretrained(
15 "runwayml/stable-diffusion-v1-5",
16 variant="fp16",
17 torch_dtype=torch.float16,
18).to(device)
19pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
20pipe.scheduler.set_timesteps(50)
21sp_sz = pipe.unet.sample_size # 通常為 64
22
23# ---- 定義佈局與描述 ----
24# 模擬一個簡化的組織佈局:
25# - 背景(白色): 正常組織
26# - 區域 1(左半): 染色較深的區域
27# - 區域 2(右半): 染色較淺的區域
28
29def create_rectangular_masks(h, w):
30 """建立簡易矩形佈局遮罩"""
31 bg_mask = np.ones((h, w), dtype=np.float32)
32 region1 = np.zeros((h, w), dtype=np.float32)
33 region2 = np.zeros((h, w), dtype=np.float32)
34
35 # 左半部分為區域 1
36 region1[:, :w//2] = 1.0
37 # 右半部分為區域 2
38 region2[:, w//2:] = 1.0
39 # 背景為兩個區域的補集
40 bg_mask = 1.0 - np.clip(region1 + region2, 0, 1)
41
42 return [bg_mask, region1, region2]
43
44masks = create_rectangular_masks(512, 512)
45prompts = [
46 "a high resolution microscopy image of tissue", # master prompt
47 "background with uniform pink staining", # bg segment
48 "densely packed dark purple nuclei cluster", # region 1
49 "sparse pale eosinophilic cytoplasm region", # region 2
50]
51
52# ---- 前處理遮罩 ----
53def preprocess_mask(mask_np, h, w, dev):
54 mask = torch.from_numpy(mask_np).float().unsqueeze(0).unsqueeze(0).to(dev)
55 mask = F.interpolate(mask, size=(h, w), mode='nearest')
56 return mask
57
58layouts = torch.cat([
59 preprocess_mask(m, sp_sz, sp_sz, device) for m in masks
60])
61
62# ---- 建立調控圖 (與 gradio_app.py 邏輯一致) ----
63sreg_maps = {}
64reg_sizes = {}
65sizereg_val = 1.0
66
67for r in range(4):
68 res = int(sp_sz / np.power(2, r))
69 layouts_s = F.interpolate(layouts, (res, res), mode='nearest')
70 layouts_s = (
71 layouts_s.view(layouts_s.size(0), 1, -1)
72 * layouts_s.view(layouts_s.size(0), -1, 1)
73 ).sum(0).unsqueeze(0)
74 reg_sizes[int(np.power(res, 2))] = (
75 1 - sizereg_val * layouts_s.sum(-1, keepdim=True) / np.power(res, 2)
76 )
77 sreg_maps[int(np.power(res, 2))] = layouts_s
78
79print(f"已建立 {len(sreg_maps)} 個解析度的 self-attention 調控圖")
80print(f"解析度: {list(sreg_maps.keys())}")
81# 輸出: 解析度: [4096, 1024, 256, 64]
4.3 範例三:評估佈局精確度 (IoU 計算)
DenseDiffusion 提供了評估生成影像佈局精確度的工具,使用 cross-attention map 與目標 mask 之間的 IoU(Intersection over Union; 交集比聯集):
1"""
2評估生成影像的佈局精確度
3對應 repo 中的 eval_iou.ipynb
4"""
5import torch
6import numpy as np
7
8def compute_layout_iou(attention_maps: dict, target_masks: list,
9 resolution: int = 64) -> dict:
10 """
11 計算 cross-attention map 與目標 layout mask 之間的 IoU
12
13 Parameters
14 ----------
15 attention_maps : dict
16 從 UNet 中間層提取的 cross-attention maps
17 key = spatial_resolution^2, value = tensor [B, H*W, 77]
18 target_masks : list[np.ndarray]
19 每個 segment 的目標 binary mask
20 resolution : int
21 評估的空間解析度
22
23 Returns
24 -------
25 dict
26 包含每個 segment 的 IoU 分數與整體平均
27 """
28 results = {}
29 ious = []
30
31 for seg_idx, mask in enumerate(target_masks):
32 # 將目標 mask resize 到評估解析度
33 mask_tensor = torch.from_numpy(mask).float().unsqueeze(0).unsqueeze(0)
34 mask_resized = torch.nn.functional.interpolate(
35 mask_tensor, size=(resolution, resolution), mode='nearest'
36 ).squeeze().flatten()
37
38 # 從 attention map 提取對應 token 的空間分佈
39 attn_key = resolution * resolution
40 if attn_key in attention_maps:
41 attn = attention_maps[attn_key] # [B, H*W, 77]
42 # 取該 segment 對應 token 範圍的最大 attention
43 seg_attn = attn[0, :, seg_idx].detach().cpu()
44
45 # 二值化 attention map (Otsu threshold 或簡單閾值)
46 threshold = seg_attn.mean()
47 attn_binary = (seg_attn > threshold).float()
48
49 # 計算 IoU
50 intersection = (attn_binary * mask_resized).sum()
51 union = ((attn_binary + mask_resized) > 0).float().sum()
52 iou = (intersection / (union + 1e-8)).item()
53
54 results[f"segment_{seg_idx}"] = {
55 "iou": round(iou, 4),
56 "mask_coverage": round(mask_resized.sum().item()
57 / mask_resized.numel(), 4),
58 }
59 ious.append(iou)
60
61 results["mean_iou"] = round(np.mean(ious), 4) if ious else 0.0
62 return results
63
64# 使用範例
65# target_masks = [bg_mask, tumor_mask, stroma_mask]
66# iou_results = compute_layout_iou(attention_maps, target_masks)
67# print(f"平均 IoU: {iou_results['mean_iou']}")
5. 在生醫影像合成生態系中的定位
5.1 Domain 2-D 子領域定位
DenseDiffusion 屬於 Domain 2-D: Diffusion Models for Medical Images 子領域,與 conditional_DDPM、SD-Messenger 並列。其獨特定位在於:
graph LR
subgraph "Domain 2-D: Diffusion for Medical Images"
A["conditional_DDPM
條件式 DDPM
需要訓練"] --> D["生醫影像合成"]
B["DenseDiffusion
免訓練注意力調變
空間佈局控制"] --> D
C["SD-Messenger
跨模態訊息傳遞
模態轉換"] --> D
end
subgraph "上游基礎設施"
E["MONAI GenerativeModels
醫學生成模型框架"]
F["Stable Diffusion v1.5
預訓練基底"]
end
subgraph "下游應用"
G["VICTRE
虛擬臨床試驗"]
H["medigan
統一合成 API"]
I["foundation-cancer
癌症影像 biomarker"]
end
F --> B
E --> A
D --> G
D --> H
D --> I
style B fill:#fff3e0,stroke:#ff9800
5.2 與同領域工具的比較
| 特性 | DenseDiffusion | conditional_DDPM | SD-Messenger | ControlNet |
|---|---|---|---|---|
| 需要訓練 | 否 (Training-free) | 是 | 是 | 是 |
| 空間佈局控制 | 強 (多區域) | 弱 (全域條件) | 中 | 強 (邊緣/深度) |
| 基底模型 | SD v1.5 | 自建 DDPM | SD 系列 | SD 系列 |
| 多區域描述 | 最多 12 區域 | 不支援 | 不支援 | 不直接支援 |
| 醫學影像特化 | 需 domain adaptation | 可直接訓練 | 可直接訓練 | 需 fine-tune |
| 推論速度 | 快 (僅修改 attention) | 標準 | 標準 | 略慢 |
5.3 Blue Ocean 分析:DenseDiffusion 在生醫的獨特機會
- 病理切片佈局合成:傳統方法只能控制「有無腫瘤」,DenseDiffusion 可以控制「腫瘤在左上角、基質在中央、淋巴浸潤在邊緣」的精確佈局
- 多器官 CT 合成:一張 CT 切片中有肝臟、腎臟、脾臟等多器官,每個器官需要獨立的外觀描述
- 藥物反應視覺化:模擬藥物治療前後的組織變化,控制不同區域的反應程度
- 稀有表型資料增強:透過精確的空間控制,合成臨床上罕見但具有特定空間特徵的病例
6. 與其他工具的整合
6.1 與 MONAI GenerativeModels 整合
1# 概念流程:使用 MONAI 的 segmentation 輸出作為 DenseDiffusion 的佈局輸入
2
3# Step 1: MONAI 語義分割 → 產出多類別 mask
4# Step 2: 將 MONAI mask 轉換為 DenseDiffusion 的 binary_matrixes 格式
5# Step 3: 為每個類別撰寫描述性 prompt
6# Step 4: 使用 DenseDiffusion 生成合成影像
7
8def monai_masks_to_dense_layout(segmentation_output, class_names):
9 """
10 將 MONAI segmentation 輸出轉換為 DenseDiffusion 格式
11
12 Parameters
13 ----------
14 segmentation_output : np.ndarray
15 shape (H, W),每個 pixel 的值代表類別 index
16 class_names : list[str]
17 每個類別的文字描述
18
19 Returns
20 -------
21 binary_matrixes : list[np.ndarray]
22 每個類別的 binary mask
23 prompts : list[str]
24 segment 描述列表
25 """
26 binary_matrixes = []
27 prompts = []
28
29 unique_classes = np.unique(segmentation_output)
30 for cls_idx in unique_classes:
31 mask = (segmentation_output == cls_idx).astype(np.float32)
32 binary_matrixes.append(mask)
33 if cls_idx < len(class_names):
34 prompts.append(class_names[cls_idx])
35
36 return binary_matrixes, prompts
6.2 與 medigan 整合
medigan 提供統一的生成模型 API。DenseDiffusion 可作為 medigan 的 backend generator(後端生成器)之一:
1# 概念整合:將 DenseDiffusion 包裝為 medigan 相容的 generator
2
3# medigan 標準介面
4# generators.generate(model_id="dense_diffusion_pathology",
5# layout=layout_masks,
6# prompts=segment_prompts)
7
8# DenseDiffusion 提供的獨特功能:
9# - 佈局導向的條件生成(其他 medigan generator 通常不支援)
10# - 免訓練,可快速適配新的描述詞彙
11# - 透過 prompt engineering 適配不同的醫學影像 domain
6.3 與 AIKT Pipeline 整合
在 AI-Knowledge Template 流程中的定位:
| AIKT Layer | 整合方式 |
|---|---|
| Layer 9 (paper-search) | 搜尋 DenseDiffusion 後續應用論文,追蹤醫學影像 attention modulation 研究 |
| Layer 10 (paper-qa-lite) | 對 DenseDiffusion 論文做 RAG 問答,深入理解技術細節 |
| Layer 12 (gh-tutorial-qd) | 本教學即為 gh-tutorial-qd 的產物 |
| Layer 15 (paper-tutorial) | 將 DenseDiffusion 論文與相關醫學應用論文做整合教學 |
| Layer 18 (research-pipeline) | 在 pre-IND 研究管線中,用 DenseDiffusion 合成影像 biomarker 訓練資料 |
| Layer 19 (tu-plan-generator) | ToolUniverse 可查詢 DenseDiffusion 相關的 imaging biomarker 標準 |
6.4 與 VICTRE 虛擬臨床試驗整合
DenseDiffusion 可為 VICTRE 虛擬臨床試驗提供更多樣化的合成影像:
- VICTRE 產出 phantom → DenseDiffusion 將 phantom segmentation 作為佈局輸入
- 為不同組織區域指定真實的影像外觀描述
- 產出多樣化的合成影像供虛擬 reader study 使用
7. 優缺點分析
7.1 優點
| 面向 | 說明 |
|---|---|
| 免訓練 | 不需任何額外訓練資料或 GPU 訓練時間,大幅降低進入門檻 |
| 精確空間控制 | 最多 12 個獨立區域,每個區域可有獨立的文字描述 |
| 輕量級 | 僅修改 attention forward pass,不增加模型參數 |
| 程式碼簡潔 | 核心邏輯集中在 gradio_app.py 和 utils.py 兩個檔案,約 400 行 |
| 可組合性 | 基於 Stable Diffusion 生態系,可與 ControlNet、IP-Adapter 等技術疊加 |
| 即時互動 | Gradio 介面支援即時繪製佈局、即時調整參數 |
| Apache-2.0 授權 | 商業友善的開源授權 |
7.2 缺點與限制
| 面向 | 說明 | 影響程度 |
|---|---|---|
| 版本鎖定 | 嚴格綁定 diffusers==0.20.2,無法使用最新版 diffusers 的功能與效能改進 | 高 |
| Monkey-patch 架構 | 直接替換 Attention __call__,與其他 attention 修改技術(如 xFormers, Flash Attention)衝突 | 高 |
| 自然影像基底 | 基於 SD v1.5 預訓練權重,醫學影像需要 domain-specific fine-tuning 才能獲得真實的組織外觀 | 高 |
| 2D 限制 | 僅支援 2D 影像生成,無法直接處理 3D volumetric(體積)醫學影像 | 中 |
| 無定量醫學驗證 | 論文評估以自然影像為主,缺乏 FID/IS 等醫學影像生成品質指標 | 中 |
| 全域變數架構 | sreg_maps、creg_maps 等使用全域變數,不支援並行推論 | 中 |
| 區域上限 12 | 複雜的醫學影像(如全景病理切片)可能需要更多區域 | 低 |
7.3 生醫應用的實際建議
- 短期可行:使用 DenseDiffusion 做概念驗證(PoC),驗證「佈局引導的醫學影像合成」是否在目標任務上有價值
- 中期投入:將 SD v1.5 替換為醫學影像 fine-tuned 的 diffusion model(如 RoentGen、MedDiffusion),保留 DenseDiffusion 的 attention modulation 邏輯
- 長期方向:考慮 3D 擴展(將 2D attention modulation 推廣到 3D UNet),或整合 SDXL/SD3 的更新架構
7.4 與 GAN 方法的比較(生醫脈絡)
| 面向 | DenseDiffusion (Diffusion) | Patho-GAN 等 (GAN) |
|---|---|---|
| 影像品質 | 高,但依賴預訓練基底的 domain 適配度 | 可直接在目標 domain 訓練,品質穩定 |
| 多樣性 | 高,每次推論可產出不同變化 | 受 mode collapse 風險 |
| 空間控制 | 強(本專案核心優勢) | 通常依賴條件 GAN 架構,靈活度較低 |
| 訓練成本 | 免訓練(但可能需要 fine-tune 基底) | 需從頭訓練或 fine-tune |
| 推論速度 | 較慢(50 步 DDIM) | 單步前向傳播,極快 |
| 隱私保護 | 可透過 prompt-only 控制生成,不直接接觸真實資料 | 訓練時必須接觸真實資料 |
附錄:檔案結構
1DenseDiffusion/
2├── gradio_app.py # 主程式:Gradio 介面 + UNet attention monkey-patch
3├── utils.py # 工具函式:mask 前處理、sketch/prompt 處理
4├── inference.ipynb # 推論範例 Notebook
5├── eval_iou.ipynb # IoU 評估 Notebook
6├── requirements.txt # 依賴鎖定(diffusers==0.20.2)
7├── dataset/
8│ ├── valset.pkl # 驗證集 prompt metadata
9│ ├── valset_layout.tar.gz # 驗證集佈局影像
10│ ├── testset.pkl # 測試集 prompt metadata
11│ ├── testset_instances.pkl # 測試集 instance metadata
12│ └── testset_layout.tar.gz # 測試集佈局影像
13├── figures/ # README 用的說明圖
14├── LICENSE # Apache-2.0
15└── NOTICE # 第三方授權聲明
Comments