abin 5aa374625f docs: add autoflow project docs and test infrastructure
- 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>
2026-04-06 19:31:52 +08:00

582 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Design Doc — Cluster4NPU UI
## 作者Architect Agent
## 狀態Draft
## 最後更新2026-04-05
## 版本對應v0.0.3developer 分支)
---
## 1. 背景與目標
### 1.1 背景
Cluster4NPU UI 是一個桌面應用程式,讓使用者不需要撰寫程式碼,就能透過視覺化拖拽介面設計並執行 AI 推論 Pipeline並將工作負載分配到多個 Kneron NPU DongleKL520、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
└── BaseNodeWithPropertiesbase_node.py
├── InputNodeinput_node.py
├── ModelNodemodel_node.py
├── PreprocessNodepreprocess_node.py
├── PostprocessNodepostprocess_node.py
└── OutputNodeoutput_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_threadStage 0 工作執行緒)
│ └── 從 input_queue 取資料 → MultiDongle 推論 → 放入 output_queue
├── PipelineStage[1].worker_threadStage 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.ndarrayBGR 影像幀)
InferencePipeline.put_data()
pipeline_input_queueQueue, 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_queueQueue, maxsize=50
├──→ result_callbackUI 更新)
└──→ 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.93.11PyQt5 + 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-005FPS 計算採用累積式
**決策**`completed_counter / elapsed_time`(從第一個結果開始計算)
**原因:**
- 與 Kneron 官方範例的計算方式一致,確保可比性
- 排除熱機warm-up期間的異常低 FPS
**取捨:**
- 無法反映即時的 FPS 波動(適合穩定場景,不適合延遲敏感場景)
### ADR-006PyInstaller 打包
**決策**:使用 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 靜態分析。