建立您的第一個圖
| 欄位 | 值 |
|---|---|
| 類別 | 圖形與管線 |
| 難度 | 初級 |
| 預估閱讀時間 | 5 minutes |
| 標籤 | graph, build, run, pipeline |
第 001 章使用三行程式碼執行一個模型。這種便利性隱藏了一個兩部分的生命週期,每個非trivial的 Neat 程式都會直接使用:首先,您會描述一個管線,作為一個 Graph,然後將該描述建構成一個可執行的 Run。本章通過建構盡可能小的管線(一個輸入節點連接到一個輸出節點,中間沒有模型),並將單個幀推送到其中,使這個生命週期可見。
其好處在於概念上:一個 Graph 是一個可重複使用的定義,您只需建構一次,然後多次執行,而不是一次性的呼叫。到本章結束時,您將建立一個圖,將其轉換為可執行的管線,並讀取輸出張量的等級——證明該幀已成功通過。
操作指南
描述輸入
在連接節點之前,先宣告幀的外觀。InputOptions 就是這個合約:像素 format、width/height、通道 depth,以及執行階段是否會為每個緩衝區添加時間戳。從這些選項建構的輸入節點會驗證傳入的幀是否符合管線預期的形狀。
C++: C++ 額外設定 is_live = false,以標記這是一個非即時(檔案/張量)來源。
simaai::neat::InputOptions in;
in.format = "RGB";
in.width = width;
in.height = height;
in.depth = 3;
in.is_live = false;
in.do_timestamp = true;
建構圖
現在建構結構。一個新的 Graph 是一個空的建構表面,而 add() 會按順序附加節點。我們添加了兩個節點——一個輸入節點(如上所述設定)和一個空白的輸出節點。這就是整個拓撲:幀從輸入端進入,從輸出端離開,中間沒有任何內容。這是稍後章節中,模型或預處理階段將插入的位置。
C++: 節點來自 simaai::neat::nodes::Input(...) 和 nodes::Output()。
Python: 節點來自 pyneat.nodes.input(...) 和 pyneat.nodes.output()。
simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::Input(in));
graph.add(simaai::neat::nodes::Output());
建構管線
build() 是從描述到可執行的轉換。它將添加的節點解析為一個具體的管線,根據實際樣本驗證輸入/輸出合約,並建立一個可重複使用的 Run 句柄。我們傳遞一個代表性的幀,以便 build() 可以鎖定協商後的張量形狀;下一步使用 Run::run(...) 進行確定性的逐一呼叫。
C++: 樣本幀是一個 cv::Mat,並且 run_opt.output_memory = Owned 要求執行階段傳回擁有的輸出緩衝區。
Python: 我們首先將幀轉換為一個 Tensor,來自一個 NumPy 陣列,使用 Tensor.from_numpy(...),然後使用它進行建構。
auto run = graph.build(std::vector<cv::Mat>{input}, run_opt);