跳至主要內容

子圖

子圖是把 graph 中的一組節點收合成單一節點。預設組合在拖入畫布時只會展開一次;子圖則保留共用定義。每個實例都指向同一份定義,因此編輯定義會更新所有實例。

子圖只屬於所在的 graph 檔案。定義儲存在該 graph 的 subgraphs 清單中,因此存檔或匯出的 graph 仍是單一可攜檔案,不需要額外安裝其他內容。

把選取收合起來​

  1. 選取兩個以上的節點(Shift+點擊,或按住 Shift 拖曳方框)。
  2. 在其中一個節點上按右鍵,選收合成子圖。
  3. 輸入方塊名稱。預設名稱是 Subgraph,之後也可以從上方的路徑列重新命名。

選取的節點會由一個實例節點取代。每條跨越選取範圍的連線都會變成該節點的邊界連接埠,並沿用其代表的內部連接埠名稱。從 Start 節點進入選取範圍的 trigger 連線也會保留:進入方塊的一條連線會重新分接至原本被觸發的所有節點。

收合與展開各自都是單一步驟的復原操作;按一次 Ctrl+Z 即可將 graph 與其定義完整還原。

什麼情況下會拒絕收合​

收合會在下列情況遭到拒絕,以免畫布顯示與實際執行結構不符:

拒絕的情況原因
選取的節點少於兩個只有一個節點的方塊等同於該節點本身。
選到 Start 節點Start 節點定義整個 graph 的起點;若放入可重用方塊,每個實例都會各自含有起點。
選到註記註記是說明,不參與計算。
夾在兩個選取節點中間的節點沒被選到方塊會先將值傳給該節點,再接收它的輸出;畫布看似有循環,但展開後的 graph 並沒有。錯誤訊息會列出需要一併選取的節點。
選取的節點中有輸入接了不只一條線,而且至少一條來自選取範圍外一個輸入只能有一個來源。只有在這條規則之前存檔的 graph 還會有這種輸入,收合成方塊會把它讀的是哪一條藏起來。請刪掉多餘的線,或改接到 Switch,再重新收合。
graph 以唯讀模式開啟唯讀分頁(例如由較新版 CodefyUI 存檔的 graph)無法修改。訊息為「這張圖目前是唯讀開啟的」。

編輯方塊​

雙擊實例節點,或按右鍵並選擇進入子圖,即可在畫布上開啟其定義。上方的路徑列會顯示 主圖 ▸ 我的方塊 這類路徑。你可以拖曳、連接、刪除、編輯參數與復原變更。選取實例後按 Enter 可開啟節點詳情;其子圖分頁會列出每個邊界連接埠所對應的內部節點與連接埠,並提供進入子圖按鈕。裡面什麼都沒有的子圖,會在畫布上標示是空的。

在方塊內復原只會影響其內部。進入時會使用獨立的復原紀錄;離開時則恢復外層紀錄,因此不會復原方塊外的操作。

離開方塊會在外層產生單一步驟的復原紀錄。 方塊內的所有變更會合併為外層紀錄的一筆;離開後按一次 Ctrl+Z 會還原該次進入期間的所有變更,不影響方塊外的變更。若未修改便離開,則不會新增復原紀錄。

點擊路徑列中的方塊名稱即可重新命名(以唯讀模式檢視 graph 時無法重新命名)。按返回會離開一層;按主圖會直接回到最外層。

在方塊內刪除節點時,該節點提供的邊界連接埠也會消失,外部連至該連接埠的連線則會一併移除。

兩個實例,一份定義​

複製實例節點,或將同一組內容收合兩次,兩個節點都會指向同一份定義。從任一實例編輯定義時,兩者都會更新。這種共用定義的重用方式是攤平式預設組合無法提供的。

刪除方塊的最後一個實例後,其定義不會再存入 graph 檔案,因此檔案不會保留畫布上沒有對應實例的方塊。復原會同時恢復實例與定義。

:::note 第一版不支援個別實例的參數 同一個子圖的所有實例都是完全相同的方塊。你無法只為其中一個實例設定不同的學習率;如有此需求,請將該參數留在方塊外並連接至方塊。個別實例覆寫預計在後續版本提供。 :::

執行含子圖的 graph​

不需要額外設定。執行前,伺服器會使用展開預設組合的相同機制,將每個實例內聯展開。因此,收合前後的 graph 行為相同;依序收合、執行、展開並再次執行,會得到相同的數值。

執行期間,實例節點會顯示彙總狀態:第一個內部節點開始時顯示執行中,最後一個內部節點結束時顯示已完成;只要任何內部節點失敗或提早停止,就會立即顯示錯誤或已中斷。

在執行期間開啟區塊,或從區塊內部開始執行時,區塊內的每個節點都會顯示自己的狀態:執行中、已完成、使用快取、已跳過、錯誤、已中斷或已略過。位於開啟區塊內的巢狀區塊,會顯示其內部節點的彙總狀態。同一個區塊的兩個實例各自保有狀態;執行結束後再開啟區塊,也會顯示其節點在該次執行中的結果。

區塊內節點產生的內容,會出現在與最外層相同的位置。它繪製的圖片、影片或圖表會出現在執行紀錄中,並標示實例與內部節點(blk › plot);開啟區塊時,也會出現在該節點的教學檢視器與節點詳細資料中,不論是否開啟錄製節點輸出。實例節點的輸出連線會顯示其對外連接埠傳出的值。因前面的節點失敗而跳過的節點,教學檢視器會直接說明它已跳過,不會等待執行結束,也不會顯示資料已過期。

執行時,內部節點會使用加上命名空間的識別碼,格式為 <instance>/<node>;教學檢視器與驗證訊息也會顯示此格式。選取實例節點時,其步驟與反向分頁會列出區塊內部節點記錄的內容,每筆項目都標示該節點在區塊內的識別碼。

跨越邊界的驗證​

驗證也會先展開實例,因此會檢查方塊內部,包括跨邊界的連接埠型別不符、未連接的必要輸入,以及畫布上看不到的定義內部循環。這類問題的錯誤路徑會同時指出邊界兩側:

Graph contains a cycle: blk1/relu -> blk1/conv -> blk1/relu
(crosses subgraph instance(s): blk1)

錯誤會列出每個外層方塊,因此位於第二層的循環會同時指出畫布上可見的方塊及其中的方塊(crosses subgraph instance(s): blk1, blk1/inner)。

若子圖直接或間接包含自身,系統會在執行前指出其名稱並拒絕執行。若 trigger 連線接到內部沒有任何節點的方塊,系統同樣會指出該方塊並拒絕執行,因為方塊裡沒有節點可以開始。方塊裡的註記會被忽略,因此只有註記的方塊也視為沒有節點。

巢狀深度最多為 10 層,與預設組合的上限相同。

儲存位置​

在專案目錄模式下,檔案分拆方式與最外層 graph 相同:

  • graphs/<name>.graph.json——定義本身:節點、連線與介面。
  • layout/<name>.layout.json——subgraphPositions,也就是每個方塊內各節點的位置。

因此,變更連線會出現在程式碼審查差異中,但在方塊內拖曳節點不會。

匯出成 Python​

匯出 → 匯出為 Python 會為每個子圖實例產生一個函式:

# ========================== Subgraph functions ==========================


def subgraph_myblock(ctx, results, provided):
"subgraph 'myblock' - instance 'blk1'."
# ScalarMultiply -> Print
results['blk1/mul'] = n03_scalarmultiply(
ctx,
tensor=_port(results['src'], 'tensor'),
)
results['blk1/p'] = n04_print(
ctx,
value=_port(results['blk1/mul'], 'tensor'),
)


# ============================ Flow functions ============================


def flow_1(ctx, results, provided):
'Start -> TensorCreate -> ScalarMultiply -> Print'
start = results['start'] = n01_start(ctx)
src = results['src'] = n02_tensorcreate(ctx)
subgraph_myblock(ctx, results, provided)

方塊結構會保留在匯出檔案中,不會攤平成節點呼叫清單。每個產生的節點函式也會附上一行註解,指出它來自哪個子圖。

只有一種例外,匯出檔案會直接註明:方塊內的節點必須連續執行,才能產生為單一函式。如果執行到一半必須先執行方塊外的節點,例如方塊先連到外部節點再連回來,或方塊內有節點沒有任何輸入,匯出器會改為依實際執行順序將這些節點內聯寫出,並在註解中指出中斷原因。腳本仍可執行,結果也與畫布一致,只是不會產生額外的子圖函式。

第一版的限制​

  • 不支援個別實例的參數覆寫(見上方說明)。
  • 子圖只屬於單一 graph,目前沒有共用的子圖庫。
  • 放在子圖內的 GraphInput / GraphOutput 節點不會納入該 graph 對外公開的 API 合約;請將它們留在最外層。
  • 畫布會透過右鍵選單或 Ctrl/Cmd+B,為實例節點提供略過。執行時會驗證失敗並指出該實例:Bypass is not supported on subgraph instance(s): blk1。bypass 只能在節點類別宣告的連接埠之間傳遞值,而邊界連接埠沒有這類宣告。請對實例選擇取消略過,或進入方塊並略過內部節點。
  • 匯出 → 匯出為子圖會建立預設組合而不是方塊;這兩項功能都使用「子圖」一詞。匯出會拒絕含有已收合方塊的畫布,並列出方塊名稱。儲存在伺服器上的預設組合只包含節點與連線,無法儲存方塊定義。如果沒有這項驗證,預設組合會包含沒有定義的 subgraph:<id> 節點,且無法脫離來源 graph 執行。請先在每個方塊上按右鍵並選擇在這裡展開子圖,再進行匯出。