# 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 目標 1. **核心目標**:使任何 AI 應用工程師都能在 5 分鐘內完成 Pipeline 設計並看到推論結果 2. **差異化目標**:清楚視覺化呈現多 NPU Dongle 平行處理帶來的效能加速(2x、3x、4x) 3. **工程目標**:提供可擴展的架構,支援 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 物件狀態不一致時崩潰 **介面:** ```python # 主要公開介面 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 的生命週期、協調執行緒間資料流、計算效能指標。 **主要資料結構:** ```python @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)模式。 **核心抽象類別:** ```python 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 | **推論結果資料結構:** ```python @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`):啟動畫面、最近專案清單、新建/載入 Pipeline - `DashboardWindow`(`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` 類別採用雙重保護: 1. Qt `QSharedMemory`(跨平台) 2. 檔案鎖(Unix: fcntl / Windows: O_CREAT|O_EXCL) 3. 自動清理 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 格式: ```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) **需要新增的架構元件:** ```python # 新增模組: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) **需要新增的架構元件:** ```python # 強化 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) **需要新增的架構元件:** ```python # 新增模組: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 # 可執行的改善動作 ``` ### 架構演進的長期考量 1. **Coordinator 重構**:當前循序協調器在多 Stage Pipeline 中形成瓶頸。長期應重構為流水線(pipeline)模式,讓 Stage N+1 在 Stage N 處理下一幀時就開始處理上一幀的結果。 2. **測試架構建立**:建立 pytest 測試框架,核心模組需達到 80% 以上覆蓋率(特別是 `InferencePipeline` 的佇列邏輯、`pipeline.py` 的 Stage 分析邏輯)。 3. **型別標註完善**:目前部分模組缺乏完整型別標註,建議逐步加入 mypy 靜態分析。