- Add .autoflow/ with health check, PRD, Design Doc, TDD, progress tracking - Add tests/conftest.py with PyQt5/KP SDK stubs for unit testing - Add pytest config to pyproject.toml (pythonpath, import-mode, test naming) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
23 KiB
Design Doc — Cluster4NPU UI
作者:Architect Agent
狀態:Draft
最後更新:2026-04-05
版本對應:v0.0.3(developer 分支)
1. 背景與目標
1.1 背景
Cluster4NPU UI 是一個桌面應用程式,讓使用者不需要撰寫程式碼,就能透過視覺化拖拽介面設計並執行 AI 推論 Pipeline,並將工作負載分配到多個 Kneron NPU Dongle(KL520、KL720、KL1080)上平行執行。
現有系統已完成核心 Pipeline 設計器與推論引擎的基礎建設,但缺乏:
- 效能視覺化(無法直觀看到平行處理的加速效果)
- 進階裝置管理介面
- 自動化 Benchmark 系統
- 優化建議引擎
1.2 目標
- 核心目標:使任何 AI 應用工程師都能在 5 分鐘內完成 Pipeline 設計並看到推論結果
- 差異化目標:清楚視覺化呈現多 NPU Dongle 平行處理帶來的效能加速(2x、3x、4x)
- 工程目標:提供可擴展的架構,支援 Phase 1-4 的功能迭代
1.3 範圍
本文件涵蓋:
- 現有(v0.0.3)核心架構的完整說明
- Phase 1-3 待開發功能的架構設計方向
不涵蓋:
- 雲端功能、非 Kneron 硬體、模型訓練、行動端
2. 系統架構總覽
2.1 整體分層架構
┌─────────────────────────────────────────────────────────┐
│ 使用者介面層(UI Layer) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Login Window │ │ Dashboard │ │ Dialogs │ │
│ │ (login.py) │ │(dashboard.py)│ │ (deployment, │ │
│ └──────────────┘ └──────────────┘ │ performance)│ │
│ │ └──────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 三面板佈局(Three-Panel Layout) │ │
│ │ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │ │
│ │ │ 左面板 │ │ 中面板 │ │ 右面板 │ │ │
│ │ │ 節點面板 │ │ Pipeline 編輯│ │ 設定/監控│ │ │
│ │ │(palette) │ │ (NodeGraphQt)│ │(properties│ │ │
│ │ └──────────┘ └──────────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────┐
│ 應用程式核心層(Core Layer) │
│ │
│ ┌────────────────────┐ ┌──────────────────────────┐ │
│ │ Pipeline 分析引擎 │ │ 節點系統(Nodes) │ │
│ │ (pipeline.py) │ │ (base/input/model/ │ │
│ │ │ │ preprocess/postprocess/ │ │
│ │ - Stage 偵測 │ │ output nodes) │ │
│ │ - 結構驗證 │ │ │ │
│ │ - 路徑分析 │ │ - 業務屬性管理 │ │
│ │ - 設定匯出 │ │ - 設定序列化 │ │
│ └────────────────────┘ └──────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 推論執行層(Inference Execution Layer) │ │
│ │ │ │
│ │ ┌──────────────────────┐ ┌─────────────────┐ │ │
│ │ │ InferencePipeline │ │ MultiDongle │ │ │
│ │ │ │ │ │ │ │
│ │ │ - 多 Stage 協調 │ │ - NPU 裝置管理 │ │ │
│ │ │ - 執行緒管理 │ │ - 非同步推論 │ │ │
│ │ │ - 佇列管理 │ │ - 前後處理 │ │ │
│ │ │ - FPS 計算 │ │ - 多裝置排程 │ │ │
│ │ └──────────────────────┘ └─────────────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────┐
│ 硬體抽象層(Hardware Abstraction Layer) │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Kneron KP SDK │ │
│ │ │ │
│ │ KL520 Dongle │ KL720 Dongle │ KL1080 Dongle │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
2.2 模組間依賴關係
main.py
└── ui/windows/login.py (DashboardLogin)
└── ui/windows/dashboard.py (DashboardWindow)
├── ui/windows/pipeline_editor.py
│ └── core/pipeline.py (PipelineAnalyzer)
│ └── core/nodes/*.py
├── ui/components/properties_widget.py
│ └── core/nodes/*.py
└── core/functions/InferencePipeline.py
└── core/functions/Multidongle.py
└── kp (Kneron KP SDK)
3. 核心元件說明
3.1 Pipeline 分析引擎(core/pipeline.py)
職責: 分析 NodeGraphQt 視覺圖形,識別 Pipeline 的 Stage 結構、驗證合法性、產生執行設定。
關鍵類別:
| 類別/函式 | 職責 |
|---|---|
PipelineStage |
代表一個推論 Stage,包含 ModelNode 與可選的 Pre/Postprocess Node |
analyze_pipeline_stages(node_graph) |
從視覺圖形中識別所有 Stage,依距離排序 |
get_stage_count(node_graph) |
計算 Pipeline 中的 Stage 數量(用於 UI 顯示) |
validate_pipeline_structure(node_graph) |
驗證 Pipeline 是否包含必要節點(Input、Model、Output) |
get_pipeline_summary(node_graph) |
回傳 Pipeline 統計摘要(節點數、Stage 數、驗證結果) |
設計決策:
- 採用多重節點識別策略(
__identifier__、type_、NODE_NAME、class 名稱、特定方法的存在)以提高相容性 - Stage 排序依據:計算各 ModelNode 到輸入節點的最短路徑距離(BFS)
- 所有圖遍歷方法都包含 defensive exception handling,避免 NodeGraphQt 物件狀態不一致時崩潰
介面:
# 主要公開介面
get_stage_count(node_graph: NodeGraph) -> int
analyze_pipeline_stages(node_graph: NodeGraph) -> List[PipelineStage]
validate_pipeline_structure(node_graph: NodeGraph) -> Tuple[bool, str]
get_pipeline_summary(node_graph: NodeGraph) -> Dict[str, Any]
3.2 節點系統(core/nodes/)
職責: 定義 Pipeline 中的各類節點,提供業務屬性管理與設定序列化能力。
繼承架構:
NodeGraphQt.BaseNode
└── BaseNodeWithProperties(base_node.py)
├── InputNode(input_node.py)
├── ModelNode(model_node.py)
├── PreprocessNode(preprocess_node.py)
├── PostprocessNode(postprocess_node.py)
└── OutputNode(output_node.py)
BaseNodeWithProperties 核心能力:
create_business_property(name, default, options)— 建立帶驗證選項的業務屬性validate_property(name, value)— 數值範圍、選項列表驗證get_node_config()/load_node_config(config)— JSON 序列化/還原create_node_property_widget(node, prop_name, value, options)— 根據屬性型別自動生成 Qt Widget
ModelNode 屬性(主要節點):
| 屬性 | 型別 | 說明 |
|---|---|---|
model_path |
file_path | .nef 模型檔案路徑 |
dongle_series |
choice | KL520 / KL720 / KL1080 |
num_dongles |
int (1-16) | 分配給此 Stage 的 Dongle 數量 |
port_id |
string | USB Port ID(或 auto) |
batch_size |
int (1-32) | 推論批次大小 |
max_queue_size |
int (1-100) | 輸入佇列最大長度 |
3.3 推論執行引擎(core/functions/InferencePipeline.py)
職責: 管理多 Stage Pipeline 的生命週期、協調執行緒間資料流、計算效能指標。
主要資料結構:
@dataclass
class StageConfig:
stage_id: str
port_ids: List[int]
scpu_fw_path: str # SCPU 韌體路徑
ncpu_fw_path: str # NCPU 韌體路徑
model_path: str # .nef 模型路徑
upload_fw: bool # 是否上傳韌體
max_queue_size: int # 佇列大小(預設 50)
multi_series_config: Optional[Dict] # 多系列模式設定
input_preprocessor: Optional[PreProcessor]
output_postprocessor: Optional[PostProcessor]
@dataclass
class PipelineData:
data: Any # 當前資料(影像、中間結果)
metadata: Dict[str, Any] # 時間戳、處理資訊
stage_results: Dict[str, Any] # 各 Stage 推論結果
pipeline_id: str # 唯一識別碼
timestamp: float
執行緒模型:
主執行緒(UI)
│
├── InferencePipeline.coordinator_thread(協調器)
│ │ 從 pipeline_input_queue 取資料
│ │ 依序分配給各 Stage
│ └── 收集結果放入 pipeline_output_queue
│
├── PipelineStage[0].worker_thread(Stage 0 工作執行緒)
│ └── 從 input_queue 取資料 → MultiDongle 推論 → 放入 output_queue
│
├── PipelineStage[1].worker_thread(Stage 1 工作執行緒)
│ └── ...
│
└── stats_thread(效能統計回報)
FPS 計算方式: 採用累積式計算(completed_counter / elapsed_time),與 Kneron 範例程式的計算邏輯一致,只計算真實推論結果(排除 async/processing 狀態)。
佇列管理策略:
- 輸入佇列滿時:捨棄最舊的幀(為了即時串流的實時性)
- 輸出佇列上限 50 筆:超出時捨棄最舊的結果,避免記憶體無限增長
3.4 硬體抽象層(core/functions/Multidongle.py)
職責: 封裝 Kneron KP SDK,提供統一的 NPU Dongle 管理介面,支援單裝置與多裝置(multi-series)模式。
核心抽象類別:
class DataProcessor(ABC):
def process(self, data: Any, *args, **kwargs) -> Any: ...
class PreProcessor(DataProcessor):
# 影像縮放(resize)+ 格式轉換(BGR → BGR565/RGB8888)
class PostProcessor(DataProcessor):
# 支援 4 種後處理類型:
# - FIRE_DETECTION(火焰分類)
# - CLASSIFICATION(一般分類)
# - YOLO_V3(物件偵測)
# - YOLO_V5(物件偵測,使用參考實作)
# - RAW_OUTPUT(原始輸出)
裝置規格(DongleSeriesSpec):
| 系列 | Product ID | GOPS 算力 |
|---|---|---|
| KL520 | 0x100 | 2 GOPS |
| KL720 | 0x720 | 28 GOPS |
| KL630 | 0x630 | 400 GOPS |
| KL730 | 0x730 | 1600 GOPS |
推論結果資料結構:
@dataclass
class ClassificationResult:
probability: float
class_name: str
class_num: int
confidence_threshold: float
@dataclass
class ObjectDetectionResult:
class_count: int
box_count: int
box_list: List[BoundingBox]
# Letterbox 映射資訊(用於還原到原始影像座標)
model_input_width, model_input_height: int
pad_left, pad_top, pad_right, pad_bottom: int
3.5 使用者介面層(ui/)
職責: 呈現視覺化 Pipeline 設計環境,管理節點屬性設定、效能監控顯示。
主要視窗:
DashboardLogin(ui/windows/login.py):啟動畫面、最近專案清單、新建/載入 PipelineDashboardWindow(ui/windows/dashboard.py):主工作介面,三面板佈局PipelineEditor(ui/windows/pipeline_editor.py):內嵌 NodeGraphQt 視覺編輯器
三面板配置:
| 面板 | 寬度比例 | 主要內容 |
|---|---|---|
| 左面板 | 25% | 節點面板(拖拽來源)、Pipeline 操作按鈕 |
| 中面板 | 50% | NodeGraphQt 視覺編輯器、全域狀態列 |
| 右面板 | 25% | Properties Tab(節點設定)、Performance Tab(效能監控)、Dongles Tab(裝置管理) |
3.6 應用程式入口(main.py)
職責: 應用程式初始化、單一實例保護、Qt 環境設定。
單一實例機制: SingleInstance 類別採用雙重保護:
- Qt
QSharedMemory(跨平台) - 檔案鎖(Unix: fcntl / Windows: O_CREAT|O_EXCL)
- 自動清理 5 分鐘以上的過期鎖定檔案
4. 資料流
4.1 設計階段資料流(Design Time)
使用者拖拽節點
│
▼
NodeGraphQt 視覺圖形
│
▼
core/pipeline.py
analyze_pipeline_stages()
│
▼
List[PipelineStage](邏輯 Stage 列表)
│
├──→ UI 顯示 Stage 數量(狀態列)
└──→ 驗證錯誤提示(Validation Errors)
4.2 執行階段資料流(Runtime)
輸入來源(相機 / 影片 / 圖片)
│
▼
camera_source.py / video_source.py
│ numpy.ndarray(BGR 影像幀)
▼
InferencePipeline.put_data()
│
▼
pipeline_input_queue(Queue, maxsize=100)
│
▼
coordinator_thread(協調器執行緒)
建立 PipelineData 包裝器
│
▼(依序通過每個 Stage)
PipelineStage[0].input_queue
│
▼
worker_thread[0]
1. input_preprocessor(可選的 Stage 間前處理)
2. MultiDongle.preprocess_frame()(BGR → BGR565 格式轉換)
3. MultiDongle.put_input()(送入推論佇列)
4. MultiDongle.get_latest_inference_result()(非阻塞取結果)
5. 更新 PipelineData.stage_results
│
▼
PipelineStage[0].output_queue
│
▼(下一個 Stage...)
│
▼
pipeline_output_queue(Queue, maxsize=50)
│
├──→ result_callback(UI 更新)
└──→ stats_callback(效能統計)
4.3 .mflow 檔案格式
Pipeline 儲存為 JSON 格式:
{
"nodes": [
{
"type": "ModelNode",
"name": "Stage 1 Model",
"properties": {
"model_path": "/path/to/model.nef",
"dongle_series": "720",
"num_dongles": 2
},
"position": [100, 200]
}
],
"connections": [
{"from_node": "input_0", "from_port": "output", "to_node": "model_0", "to_port": "input"}
]
}
5. 技術決策紀錄(ADR)
ADR-001:選用 PyQt5 作為 GUI 框架
決策:使用 PyQt5(>= 5.15.11)
原因:
- NodeGraphQt 依賴 PyQt5,無法使用其他框架
- PyQt5 在 Windows 上有成熟的支援
- 提供豐富的 Widget 與 Signal/Slot 機制
取捨:
- 限制 Python 版本在 3.9–3.11(PyQt5 + Kneron SDK 相容性)
- PyQt6 不向下相容,短期不考慮遷移
ADR-002:選用 NodeGraphQt 作為視覺節點編輯器
決策:使用 NodeGraphQt(>= 0.6.40)
原因:
- 提供完整的拖拽節點圖形編輯能力,開發成本低
- 支援節點連接、屬性面板、視覺化輸出
取捨:
- NodeGraphQt 的 UI 客製化能力有限(如節點顏色、形狀)
- 節點識別採用多重 fallback 機制(透過
__identifier__、NODE_NAME等),因 NodeGraphQt 版本差異可能造成 API 不一致
ADR-003:多執行緒 Pipeline 架構
決策:每個 Stage 一個 Worker Thread + 一個 Coordinator Thread
原因:
- 推論為 CPU/硬體密集操作,多執行緒可避免 UI 阻塞
- 各 Stage 獨立執行緒允許流水線(pipelining)並行,提升吞吐量
取捨:
- 協調器採用循序(sequential)方式傳遞資料,並非真正平行(真正平行需要 DAG 調度器)
- 使用
queue.Queue進行執行緒間通訊,有固定的記憶體上限
ADR-004:非阻塞式推論結果取得
決策:MultiDongle.get_latest_inference_result() 採用非阻塞模式
原因:
- 與 Kneron 範例程式碼(example.py)的設計模式一致
- 避免推論延遲阻塞整個 Pipeline 執行緒
取捨:
- 結果可能為 None(尚未完成),需要 async/processing 狀態的過濾邏輯
ADR-005:FPS 計算採用累積式
決策:completed_counter / elapsed_time(從第一個結果開始計算)
原因:
- 與 Kneron 官方範例的計算方式一致,確保可比性
- 排除熱機(warm-up)期間的異常低 FPS
取捨:
- 無法反映即時的 FPS 波動(適合穩定場景,不適合延遲敏感場景)
ADR-006:PyInstaller 打包
決策:使用 PyInstaller(main.spec)產生獨立可執行檔
原因:
- 目標用戶(系統整合商)可能沒有 Python 環境
- 簡化部署流程
取捨:
- 打包後的執行檔體積較大
- Kneron KP SDK 的動態函式庫需要正確包含在打包設定中
6. 已知限制與技術債
6.1 已知 Bug
| Bug | 狀態 | 影響 |
|---|---|---|
| 節點屬性顯示問題 | 未修復(v0.0.2 記錄) | 右面板 Properties Tab 可能顯示錯誤 |
| 輸出視覺化異常(含後處理結果) | 未修復(v0.0.2 記錄) | 輸出畫面可能不正確 |
6.2 技術債
| 項目 | 嚴重度 | 說明 |
|---|---|---|
| 根目錄 debug 腳本未整理 | 低 | debug_*.py、force_cleanup.py 等應移至 tools/ |
| tests/ 命名混亂 | 中 | 42 個腳本缺乏系統性分類,部分非 test_ 開頭 |
| 缺乏 pytest 測試框架 | 中 | 核心模組(InferencePipeline、MultiDongle)無 pytest 覆蓋 |
| Coordinator 為循序設計 | 中 | 真正的 Stage 並行需要重構協調器為 DAG 模式 |
| 節點識別多重 fallback | 低 | 可讀性差,應統一為單一識別策略 |
| RTSP 串流僅基本支援 | 低 | 完整 RTSP 功能未在當前路線圖中 |
6.3 效能限制
- 協調器為循序傳遞:目前 Coordinator 依序將資料傳給 Stage 0 → Stage 1,無真正的平行推論(真正平行需重構為流水線佇列模式)
- FPS 計算不反映即時波動:累積式 FPS 在長時間執行後準確,但短期波動不可見
- 輸出佇列上限 50:高吞吐量場景下可能成為瓶頸
7. 未來架構演進方向
Phase 1:效能視覺化(對應 DEVELOPMENT_ROADMAP Phase 1)
需要新增的架構元件:
# 新增模組:core/performance/
class PerformanceBenchmarker:
"""自動化效能測試器"""
def run_sequential_benchmark(self, pipeline_config) -> BenchmarkResult
def run_parallel_benchmark(self, pipeline_config) -> BenchmarkResult
def calculate_speedup(self, seq: BenchmarkResult, par: BenchmarkResult) -> float
class PerformanceHistory:
"""效能歷史記錄(本地 JSON 儲存)"""
def record(self, result: BenchmarkResult)
def get_history(self, limit: int) -> List[BenchmarkResult]
UI 層新增:
ui/components/performance_dashboard.py:即時 FPS/延遲折線圖(使用 pyqtgraph 或 matplotlib)ui/dialogs/benchmark_dialog.py:Benchmark 啟動與結果呈現
架構考量:
- Benchmark 需要能控制
InferencePipeline以單裝置/多裝置模式執行,需要在StageConfig層級提供模式切換介面 - 效能圖表更新須在獨立執行緒中產生資料,透過 Qt Signal 傳遞到 UI 執行緒
Phase 2:裝置管理(對應 DEVELOPMENT_ROADMAP Phase 2)
需要新增的架構元件:
# 強化 core/functions/Multidongle.py
class DeviceManager:
"""裝置管理器"""
def scan_devices() -> List[DeviceInfo]
def get_device_health(device_id: str) -> DeviceHealth
def assign_device(device_id: str, stage_id: str)
def get_load_balance_recommendation() -> Dict[str, str]
@dataclass
class DeviceInfo:
device_id: str
series: str # KL520/KL720/KL1080
status: str # online/offline/busy
gops: int # 算力(來自 DongleSeriesSpec)
assigned_stage: Optional[str]
UI 層新增:
ui/components/device_management_panel.py:裝置狀態儀表板
Phase 3:優化引擎(對應 DEVELOPMENT_ROADMAP Phase 3)
需要新增的架構元件:
# 新增模組:core/optimization/
class OptimizationEngine:
def analyze_pipeline(self, stats: PipelineStats) -> List[OptimizationSuggestion]
def predict_performance(self, config: PipelineConfig) -> PerformancePrediction
@dataclass
class OptimizationSuggestion:
type: str # "rebalance_devices" | "remove_redundant_node" | ...
description: str
estimated_improvement: float # 預估效能提升 %
action: Callable # 可執行的改善動作
架構演進的長期考量
-
Coordinator 重構:當前循序協調器在多 Stage Pipeline 中形成瓶頸。長期應重構為流水線(pipeline)模式,讓 Stage N+1 在 Stage N 處理下一幀時就開始處理上一幀的結果。
-
測試架構建立:建立 pytest 測試框架,核心模組需達到 80% 以上覆蓋率(特別是
InferencePipeline的佇列邏輯、pipeline.py的 Stage 分析邏輯)。 -
型別標註完善:目前部分模組缺乏完整型別標註,建議逐步加入 mypy 靜態分析。