GPT-Image-2 MVP — 不訓 base 模型,純 API,先看見 (image, mask, JSON) 三件套
SVGE 要解決的是巡檢場景中高質量、可標註、可控合成資料不足的問題。但在資源不足階段,如果兩週 MVP 同時追求最終模型棧、嚴格可控標註、UAV-oblique domain adaptation、下游 mAP 提升、私有化與合規,目標會過載,短期也難形成可展示、可談判、可換取資源的成果。
因此,Phase 0 的核心不是證明 SVGE 已經完成,而是建立一個足夠可信的早期證據:合作方能看懂資料包形態,願意繼續投入資金、算力、真實資料或試點場景。
SVGE 採用分階段降風險:Phase 0 驗證「樣品包是否值得投入下一輪資源」;Phase 1 驗證「該能力是否能被重複、私有化、嚴格標註並通過下游模型效果檢驗」。
| 階段 | 核心問題 | 成功標準 |
|---|---|---|
| Phase 0:樣品價值驗證 | 可控生成巡檢資料包是否能被資源方快速理解,並推動資料合作或試點立項? | 8–20 張高質樣品 + 2–3 組 image/mask/bbox/JSON + 明確合作方反饋 |
| Phase 1:工程與模型驗證 | 樣品能力是否能被重複生產、私有化部署、訓練級標註並在真實測試集上產生效果? | 真實 UAV-oblique data、可替換生成後端、標註 QA、下游 detector/segmenter 評測 |
這個拆分保留了 UAV-oblique 作為正式差異化方向,但避免在沒有資料、算力和試點前,把正式研發壓進樣品 MVP。
完整研發需要資料、算力、標註、評測和合規閉環,應在需求與資源確認後啟動。Phase 0 先產出可視化樣品包,讓資源方直觀看到三件事:巡檢場景可以被生成,生成結果可以被標註,標註可以被包裝成結構化資料。
Phase 0 的成功不是 mAP lift,而是資源信號。如果樣品包能帶來 LOI、試點資料、GPU 支持、付費評估或具名技術評審意願,它就完成了本階段任務。
| 早期證據 | 觀察方式 |
|---|---|
| Visual credibility | 8–20 張精選巡檢圖是否足以讓非技術資源方理解場景價值 |
| Data-package plausibility | 2–3 組完整 image + mask + bbox + JSON 是否能說明 SVGE 不是單純生圖 |
| Resource signal | 是否取得 LOI、試點場景、真實資料、算力或付費評估意向 |
Phase 0 的方法不是訓練模型,而是建立可重複的資料包流程。底層生成後端在本階段可替換;SVGE 的核心資產是 workflow、schema、標註格式、場景控制語言、quality notes 和 reject reason。
這裡的耐久資產不是單張生成圖,而是「給定一個巡檢場景規格,能產出一個可被理解、可被審查、可被討論的資料包」這個流程。
| 方法單元 | 最小要求 |
|---|---|
| 場景規格 | 記錄道路類型、巡檢任務、天氣/光照、目標物、可控軸與預期展示點 |
| 圖像生成 | 只保留通過人工視覺審查的候選,不把 raw generations 當成果 |
| 後驗標註 | bbox 包住目標,mask 與 image 對齊,類別和屬性能被人讀懂 |
| JSON 包裝 | 包含 scene、instances、attributes、quality notes、provenance、reject reason |
Phase 0 交付物應像一個小型資料集論文的 artifact:可看、可查、可復現到一定程度,但不宣稱 training-grade 或 production-grade。
為避免過度承諾,Phase 0 需要明確 claims boundary。它可以證明「資料包形態值得討論」,但不能直接推出「合成資料已經提升模型性能」。
| Phase 0 可以主張 | Phase 0 不應主張 |
|---|---|
| SVGE prototype 可生成可展示、可標註、可討論的巡檢資料樣品 | 樣品已是 training-grade label 或 production-grade dataset |
| 資料包格式能表達 scene、instance、mask、bbox、attributes 和 QA notes | 合成資料已在真實測試集上穩定提升 mAP / recall |
| 合作方可基於樣品判斷是否提供資料、試點或研發資源 | 已完成 UAV-oblique production stack、信創合規或私有化部署 |
內部需保留完整 provenance:生成後端、prompt/spec、生成日期、人工修改、標註工具、審查人、reject reason,以及是否使用任何真實客戶資料。對外則聚焦 SVGE workflow 與資料包能力,底層生成後端保持可替換。
Critic audit 不是否定 Phase 0,而是限定 Phase 0 的可聲稱範圍。所有不能在樣品階段解決的問題,都應轉化為 Phase 1 的研發要求。
| 限制 | Phase 0 處理方式 | Phase 1 任務 |
|---|---|---|
| 樣本量不足以證明 mAP lift | 不做統計結論,只收集展示價值與合作方反饋 | 真實 test set、多 seed、paired bootstrap、固定 baseline |
| 標註仍是展示級 | 人工審查 bbox/mask/JSON 是否可讀、可展示 | 訓練級 annotation QA、IoU gate、schema 對齊養護標準 |
| closed backend 依賴 | 內部使用快速生成後端做樣品;對外強調 workflow 可替換 | FLUX/AeroGen/國產基底 + LoRA/ControlNet 私有化路線 |
| UAV-oblique 差異化尚未完成 | 用樣品驗證需求和合作入口 | 收集真實 UAV-oblique data,建立正式 domain taxonomy |
Phase 1 是 SVGE 的技術防守層。它把 Phase 0 驗證過的樣品能力,推進到可重複生成、可私有化部署、可訓練級標註、可下游評測的正式 pipeline。
| Phase 1 模塊 | 要解的問題 | 候選路徑 |
|---|---|---|
| Domain data | 真實 UAV-oblique 巡檢圖、缺陷類別、養護語言 | HighRPD / UAV-PDD2023 + 客戶試點資料 |
| Generation backend | 擺脫 closed API,提升可控性與私有化能力 | AeroGen spike、FLUX.2 + ControlNet、國產基底 + LoRA |
| Annotation pipeline | 從展示級 mask 走向訓練級標註 | SAM 後驗 + 人工 QA + schema 對齊 JT/T 1432 |
| Downstream proof | 從樣品價值走向模型效果證明 | YOLO / Mask2Former 多 seed + paired bootstrap |
兩週內的工作應服務一個目標:讓樣品包足以進入投資、BD、試點和資料合作對話。AeroGen / FLUX 等技術預研可以並行保留,但不能搶 Phase 0 主線。
結論:Phase 0 的正確目標不是證明 SVGE 已完成,而是以最小成本證明 SVGE 的樣品形態足以換取下一階段正式研發所需的資源。
以下進入 Phase 0 技術細節:Quick Mode 如何把樣品包跑起來
關鍵領悟:樣例顯示 GPT-Image-2 多 instance、屬性綁定、場景元素一致性都很強。之前我擔心的「多 instance 串色」問題在實測樣例中不嚴重。對 SVGE 大多數下游任務(detection / scene understanding / robot perception / VLA training / benchmark),Quick Mode 一條路就夠。
用戶實測 6 張高速公路場景(多車輛 + 路障 + 維修設備 + 不同時段/天氣),每張展示 GPT-Image-2 在 SVGE 目標場景下的真實能力:
| 維度 | 樣例證據 | 對 SVGE 的意義 |
|---|---|---|
| 多 instance(4–6 物體) | 每張 4–6 車輛同時存在、各自獨立 | Quick Mode 多 instance 可行,不需要 InstanceDiffusion-style adapter |
| 屬性綁定 | 白 truck / 銀 sedan / 灰 SUV / 深色 sedan 在同圖無串色;圖 2 全白系是 prompt 顯式指定 | 屬性 prompt 有效,per-instance caption 可控 |
| 場景元素一致 | 6 張都有錐形路障 + 右側警戒區 + 至少 1 個維修設備(箭頭板/維修車/照明車) | 場景模板量產可行,prompt 能穩定召喚行業專屬元素 |
| 時段控制 | 黃昏(1, 5, 6)/ 白天(2)/ 夜雨(3)/ 雨天(4)/ 冷藍 twilight(7, 8)— 光線方向、色溫、強度都對 | 光線軸可控,「sunset / daytime / night / rainy / twilight」直接 prompt,至少 5 檔 |
| 天氣控制 | 雨天反射、濕路面、夜雨頭燈眩光、夕陽長影都符合物理 | 天氣軸可控 |
| 視角一致性 | 6 張都是「高架斜俯瞰、3–4 車道、視野往遠方收斂」 | camera angle 可控,能保持構圖風格 |
| 物理細節 | 陰影方向、紅色尾燈滲色、路面斑剝、輪胎水霧都真實 | 細節品質高,下游模型不容易學到 artifact |
| 行業 domain 元素 | 道路維修場景的箭頭板、警示斜紋、維修車形態、照明車都對 | 基底訓練分布覆蓋此 domain,無需額外 LoRA |
下圖是用戶已經提供的 mask 標註範例 — 對樣例 6(夕陽 cinematic)類構圖的 7 個車輛 instance 做了二值前景分離。這正是 SVGE Pipeline Stage 4(SAM 3.1 後驗 + 細化)的目標輸出格式:
| Mask 屬性 | 本範例 | SVGE 規格目標 | 狀態 |
|---|---|---|---|
| 解析度 | 1672×941(與 GPT-Image-2 輸出 1:1 對齊) | 1:1 與生成圖一致 | ✅ 對齊 |
| Instance 分離 | 7 個獨立白色 blob | 每 instance 獨立通道 | ⚠️ 此圖是合成單通道;實際 pipeline 需拆成 N 通道 |
| 邊緣品質 | 連續、無洞、無雜點 | SAM 3.1 級別 | ✅ 達標 |
| 覆蓋完整性 | 含車身輪胎 + 後輪罩 | 不丟細節 | ✅ 達標 |
| 背景純淨度 | 純黑、無偽前景 | 無假陽性 | ✅ 達標 |
SVGE 主文件 §1.3 列了 6 類下游服務。並非所有下游都需要嚴格 mask 邊界精度:
| 下游任務 | 對 mask 邊界精度需求 | Quick Mode 是否足夠 |
|---|---|---|
| Detection(YOLO 等) | bbox 為主,mask 粗細可接受 | ✅ 完全夠 |
| Instance Segmentation(Mask R-CNN) | mask IoU > 0.5 | ✅ SAM 3.1 後驗能達標 |
| Semantic Segmentation 細粒度 | boundary 像素級精確 | ⚠️ 邊緣 case,視任務 |
| Scene Understanding / VLM 訓練 | 不需要精確 mask | ✅ 完全夠 |
| Robot Perception / VLA Training | bbox + 粗 mask 即可 | ✅ 完全夠 |
| Benchmark / Demo / 邊角案例擴展 | 視覺合理即可 | ✅ 完全夠 |
結論:SVGE 主文件列的 6 類下游,5 類用 Quick Mode 就夠。Strict Mode 只在做純語義分割訓練資料時才必要。這是「Quick Mode 為主路徑、Strict 退到後備」的合理性所在。
| 輪次 | 我答了什麼 | 狀態 |
|---|---|---|
| 第 1 輪 | image-first:GPT-Image-2 純 prompt 生圖 → SAM 3.1 反推 (class, bbox, mask) | 部分對(Quick Mode 路徑),但沒明說違反 SVGE mask-first 主路徑 |
| 第 2 輪(用戶駁) | 用戶問「(class, bbox, mask) 不是應該一起定好嗎」 | — |
| 我改答 | strict mask-first:用戶提供 mask → GPT edit → 系統不抽,只驗證 | 部分對(Strict Mode 路徑),但對「先要點結果」太重 |
| 用戶再駁 | 「不對,再看 HTML」 | — |
| 第 3 輪(這次) | 承認兩種模式都有效,按目標選;output mask 本來就該是 image-aligned 不是用戶 spec mask | 應該對齊正確了 |
真正答案:輸出 mask = Stage 4 image-aligned 的 refined mask。但用 IoU(refined, stage2_intent) > 0.7 作為「服從度」門檻,IoU 太低就 reject 整個樣本。(class, bbox) 從用戶意圖保留,mask 對齊實際生成圖。
(image, mask 對齊到 image, JSON 描述 image)
images.edit API 是 單 mask + 單 prompt,沒有 per-instance prompt 概念。對 SVGE 多 instance 場景:
樣例顯示 GPT-Image-2 不擅長精確 bbox 控制,但很擅長「語義位置」(左/中/右車道、近/中/遠視野)。所以 v0 的 prompt 構造把 bbox 翻成自然語言位置:
def build_prompt_from_spec(spec):
parts = []
# 1) 場景骨架(樣例都吃這套)
parts.append(f"{spec.scene.style} aerial view of a highway")
parts.append(spec.scene.lighting) # "sunset" / "daytime" / "night with rain"
if getattr(spec.scene, 'weather', None):
parts.append(f"in {spec.scene.weather} weather")
# 2) per-instance 描述(GPT-Image-2 能處理的精度)
for obj in spec.objects:
color = obj.attributes.get('color', '')
location = bbox_to_lane(obj.bbox) # ★ 關鍵轉換
parts.append(
f"a {color} {obj.class_name} in the {location}"
)
# 3) 場景一致性元素(樣例都有:cones / arrow board / maintenance vehicle)
if spec.scene.background == "road_inspection":
parts.append("orange traffic cones lining the right shoulder")
parts.append("yellow arrow signal board on the right")
if spec.scene.background == "highway_construction":
parts.append("road maintenance vehicles with red and white chevron warning patterns")
return ", ".join(parts)
def bbox_to_lane(bbox):
"""把 normalized bbox 轉成「車道 + 視野位置」的自然語言。
Args:
bbox: (x, y, w, h) all in [0, 1]
Returns:
str like "left lane in middle view" / "right shoulder in foreground"
"""
x, y, w, h = bbox
cx = x + w / 2
cy = y + h / 2
# 水平位置 → 車道
if cx < 0.25: lane = "left lane"
elif cx < 0.45: lane = "left-middle lane"
elif cx < 0.55: lane = "middle lane"
elif cx < 0.75: lane = "right-middle lane"
elif cx < 0.92: lane = "right lane"
else: lane = "right shoulder"
# 垂直位置 → 視野遠近
if cy < 0.30: depth = "far view"
elif cy < 0.55: depth = "middle view"
elif cy < 0.80: depth = "near view"
else: depth = "foreground"
return f"{lane} in {depth}"
不同下游任務對 mask 精度的容忍度不同。Quick Mode 的 SAM-bbox-IoU 過濾門檻應依下游任務動態調整,避免「一刀切 0.5」帶來的浪費或品質不足:
| 下游任務 | 建議 IoU 門檻 | 預期通過率 | 備註 |
|---|---|---|---|
| Detection(YOLO 等 bbox-only) | 0.3(鬆) | ~85% | bbox 才是 ground truth,mask 只是輔助 |
| Instance Segmentation(COCO-style) | 0.5(標準) | ~70% | 標準 COCO mAP 門檻 |
| Scene Understanding / VLM 訓練 | 0.4 | ~80% | 不直接用 mask 訓練 |
| Robot Perception / VLA Training | 0.4 | ~80% | 抓取需大致位置即可 |
| Semantic Segmentation 細粒度 | 0.7(嚴) | ~30% | 應切 Strict Mode 或 FLUX.2 + ControlNet |
| Demo / Benchmark 多樣性 | 0.3(鬆) | ~85% | 視覺合理即可 |
filter.mask_bbox_iou_threshold 欄位,按下游任務動態設置。預設 0.4(兼顧通過率與品質),生產 segmentation 訓練資料時切 0.5 或 0.7。
多數時候你不需要切過來。Quick Mode 的 SAM 3.1 後驗抽 mask 對 6 個下游任務的 5 個都夠用。
| 維度 | Quick Mode | Strict Mode |
|---|---|---|
| (class, bbox, mask) 在哪定? | Stage 4 後驗(SAM 抽) | Stage 2 派生鎖定 |
| 用戶 spec 的 mask 角色 | 選用,沒給也不影響 | 核心輸入(沒給就派生) |
| 用戶 spec 的 bbox 角色 | 驗證 SAM 結果(鬆 IoU 0.5) | 強制條件 + 驗證 IoU 0.7 |
| GPT-Image-2 用法 | images.generate 純文字 | images.edit 帶 mask |
| 多 instance 處理 | 較好(單次 generate,無 mask 串色) | 較差(mask edit 屬性串色,需逐 instance) |
| 適合 spec 複雜度 | 1–4 instance | 1–2 instance(單次)/ 1–3 instance(逐 instance) |
| 輸出 mask | SAM 抽(自然對齊 image) | SAM verify_mask(對齊 image,且 IoU > 0.7 確認對得住意圖) |
| Reject rate(預期) | 30-50% | 70-80% |
| 每 1k 通過樣本的 GPT-Image-2 成本 | 1.5k 張 × $0.05 = ~$75 | 4k 張 × $0.05 = ~$200 |
| 適合目標 | 看點結果、demo、samples | 下游 detection / segmentation 訓練資料 |
| 對應 SVGE 主文件 | 更接近 B 子系統範式 | 對齊 A 子系統 §8.A |
| API | 輸入 | 實際行為 |
|---|---|---|
images.generate | prompt 文字 | 無位置控制 |
images.edit | image + mask + prompt | mask alpha=0 區域「鼓勵」編輯,但邊界會軟化,不像 ControlNet 強制 |
| FLUX.2 / SD 3.5 + ControlNet | image + ControlNet 條件 + prompt | 嚴格 mask 條件,邊界精度高 |
| 方案 | 適合 | 缺點 |
|---|---|---|
| A. 全 composite + 全局 prompt | 屬性不衝突("3 cars in parking lot") | 屬性互衝會串色 |
| B. 逐 instance edit | 強制屬性精確 | N 次 API call、後面改前面、貴又不穩 |
| C. 切 Gemini 2.5 Flash Image | 多 reference 原生支援 | 不是 GPT-Image-2,但用戶可能要重新評估 |
| D. 切本地 FLUX.2 + ControlNet | 最嚴格 + InstanceDiffusion 風格 per-instance | 需 GPU、需自己 host |
| 項目 | 量 | 單價 | 小計 |
|---|---|---|---|
| GPT-Image-2 generate(reject 25%,樣例校準) | 1.3k 張 | ~$0.04-0.05/張 | $52-65 |
| SAM 3.1 inference(本地 RTX 4090) | 1.3k 張 | 免費 | $0 |
| Qwen3-VL 8B 本地 | ~3-5k instance | 免費 | $0 |
| SigLIP 2 評分 | 1.3k 張 | 免費 | $0 |
| 合計 | — | — | $52-65 |
樣例顯示 GPT-Image-2 在道路維修 domain 命中率高,reject 預期從原估的 33% 下調到 25%。實際數字以 D2(100 張壓力測)為準。
| 項目 | 量 | 單價 | 小計 |
|---|---|---|---|
| GPT-Image-2 edit(reject 75%) | 4k 張 | ~$0.05/張 | $200 |
| 多 instance 逐 edit 加成(平均 1.5×) | +50% | — | +$100 |
| SAM 3.1 + Qwen3-VL(本地) | — | 免費 | $0 |
| 合計 | — | — | $200-300 |
| 項目 | 量 | 單價 | 小計 |
|---|---|---|---|
| FLUX.2 [klein] 9B 本地推理 | 3k 張(reject 67%) | RTX 4090 ~6 sec/張 | 5 hr 電費 ≈ $0 |
| 初始模型下載 | ~18 GB | — | — |
| SAM 3.1 / Qwen3-VL / SigLIP 2 | — | 免費 | $0 |
| 合計 | — | — | ~$0(電費忽略) |
結論:Quick Mode 是「先看點結果」最便宜的路($75 / 1k 樣本,半天)。Strict Mode 是中介選項。真要規模化生產訓練資料,本地 FLUX.2 邊際成本歸零是長期解。
對應 prototype_v0/src/,新增 v0_workflow.py 統一兩模式 entry point:
from openai import OpenAI
from sam3 import SAM3Predictor
from transformers import AutoModel, AutoProcessor
import numpy as np
class V0Workflow:
def __init__(self, mode: str = "quick", config: dict = None):
assert mode in ["quick", "strict"]
self.mode = mode
self.openai = OpenAI()
self.sam3 = SAM3Predictor.from_pretrained("facebook/sam3.1")
self.qwen3vl = self._load_qwen3vl()
self.siglip = self._load_siglip2()
self.config = config or {}
def generate(self, spec):
if self.mode == "quick":
return self._quick_pipeline(spec)
else:
return self._strict_pipeline(spec)
# ============== Quick Mode ==============
def _quick_pipeline(self, spec):
prompt = self._build_prompt(spec)
# Stage 3: 純文生圖
resp = self.openai.images.generate(
model="gpt-image-2",
prompt=prompt,
size="1024x1024",
quality="high",
n=3,
)
candidates = [self._download(r.url) for r in resp.data]
for img in candidates:
# Stage 4: SAM 3.1 後驗抽 (class, bbox, mask)
sam_results = self.sam3.predict(
img,
concepts=[obj.class_name for obj in spec.objects],
)
# Stage 5: Qwen3-VL 抽屬性
for inst in sam_results:
inst.attrs = self.qwen3vl.extract_attrs(img, inst.bbox)
# Stage 6: 鬆過濾
if self._quick_filter(img, sam_results, spec):
yield self._build_output(img, sam_results, spec, mode="quick")
# ============== Strict Mode ==============
def _strict_pipeline(self, spec):
# Stage 2: 鎖三元組
locked = self._lock_triples(spec) # 每個 obj → (class, bbox, mask)
composite_mask = self._composite_masks(locked)
# Stage 3: GPT-Image-2 mask edit
prompt = self._build_prompt(spec)
resp = self.openai.images.edit(
image=self._blank_canvas(),
mask=composite_mask,
prompt=prompt,
size="1024x1024",
n=3,
)
candidates = [self._download(r.url) for r in resp.data]
for img in candidates:
# Stage 4: 驗證 & 細化
verify_masks = self.sam3.predict(
img,
concepts=[t.class_name for t in locked],
)
ious = [self._iou(v.mask, l.mask)
for v, l in zip(verify_masks, locked)]
if min(ious) < 0.7:
continue # reject
# Stage 5: 過濾
if self._strict_filter(img, verify_masks, locked, spec):
yield self._build_output(
img, verify_masks, spec,
mode="strict",
intent_ious=ious,
)
def _lock_triples(self, spec):
triples = []
for obj in spec.objects:
if obj.mask:
m = self._load_mask(obj.mask)
elif obj.ref_image:
m = self._sam3_from_ref(obj.ref_image, obj.bbox)
else:
m = self._bbox_to_blob(obj.bbox)
triples.append(LockedTriple(obj.class_name, obj.bbox, m))
return triples
def _build_output(self, img, masks, spec, mode, intent_ious=None):
return {
"image": img,
"masks": [m.mask for m in masks], # image-aligned
"annotation": {
"instances": [
{
"class_name": m.class_name,
"bbox": m.bbox, # SAM 抽的或 verify 的
"mask_pixel_grounding": True,
"spec_intent_iou": intent_ious[i] if intent_ious else None,
}
for i, m in enumerate(masks)
],
"scene": spec.scene.dict(),
"mode": mode,
},
}