執行佇列
一個 run 由伺服器持有,而不是由送出它的客戶端持有。即使關閉分頁、終端機或登出,run 仍會繼續執行;之後可以透過 API 或 CLI 查看。
這就是佇列的用途。一次送出五個訓練工作後關上筆電,伺服器會在 GPU 上逐一執行,而不是五個同時啟動、四十分鐘後耗盡 VRAM。
每個裝置一條佇列
沒有 worker 目標的 run 都依它解析後的裝置排程 — cpu、cuda:0、mps — 並在伺服器程序內執行。這個字串就是佇列 key,因此每個裝置都有獨立的佇列與並行上限。解析順序是:run 自己的 device 選項、圖檔的 settings.device、最後是 cpu;只有明確指定 auto 才會挑選目前最好的加速器。
| 佇列 key | 同時執行數(預設) | 為什麼 |
|---|---|---|
cuda:0、cuda:1、mps,任何加速器 | 1 | 同一張卡上的第二個 run 會與第一個競爭同一份 VRAM。若讓兩者同時執行,長時間工作通常會在途中發生 CUDA out-of-memory 錯誤。 |
cpu | 2 | CPU 上的問題是資源競爭,而不是整個 run 失敗;有多餘核心的機器應該用上這些核心。 |
GPU 佇列達到上限時不會延遲 CPU run,兩張不同的卡也不會互相等待。同一條佇列內的 run 依送出順序啟動,先送出的先執行。
准入規則。 上限屬於名額(slot):一台機器上的一個裝置。這台伺服器的 cuda:0 與 worker gpu-box-1 的 cuda:0 是兩個名額,各有各的上限。指定裝置集合的 run 需要集合中每一個裝置各一個名額:所有裝置都有空位時才會啟動,一次取得全部名額,結束時一次全部歸還。它排在佇列最前面等待時不佔用任何名額,但會保留這些卡:在它啟動之前,其他 run 都不能在保留的卡上啟動;已在這些卡上執行的 run 照常結束,結束後它就會啟動。代價是閒置:已經空出的保留卡會一直閒置到集合中其他卡也空出,最長等於那些卡上已在執行的最久的 run。保留依先來後到,因此兩個共用一張卡的裝置集合 run 會依序啟動。"worker": "any" 的裝置集合 run 不保留任何卡,因為它要用哪台機器的卡要到啟動時才決定。
與伺服器在同一台機器上的 worker,對實體上相同的裝置與這台伺服器共用額度:CPU、Apple GPU(mps:0),以及 UUID 與這台伺服器某張卡相同的每一張 CUDA 卡,不論兩邊各自給它什麼編號。各自保有自己的名額,但所有名額上的 run 都計入同一份額度,套用這台伺服器對該裝置的上限(或 worker 自己較小的 <worker>/<device> 覆寫),因此在上限為 1 時,這裡的 run 與那個 worker 上的 run 不會同時拿到同一張卡。「同一台機器」指 agent 從 loopback 位址連入,且回報的 machine id 與伺服器相同(/etc/machine-id、macOS 的硬體 UUID 或 Windows 的機器 GUID,以摘要值傳送)。兩者缺一不可:SSH 通道也是 loopback,而 machine id 是 agent 自己回報的。沒有 UUID、或 UUID 不在這台伺服器上的 CUDA 卡會保有自己的名額,伺服器會記錄一次。提供同一張實體卡的兩個 worker(UUID 相同,不論各自給它什麼編號,例如同一台 GPU 伺服器上的兩個 agent)也以同樣方式共用這張卡,即使這台伺服器沒有這張卡:經由任一 worker 的 run 都同時計入兩者,套用兩者中較小的上限(離線的提供者不計,除非它仍有 run 在這張卡上),Workers 面板會把這張卡標示為「與 ... 是同一張實體卡」。數條佇列共用的名額空出時,由這些佇列最前面的等待 run 中最早送出的那個取得,所以一條很長的佇列不會讓另一條餓死。等待中 run 的 queue_position 只計算它所在的那條佇列(裝置集合 run 排在第一個裝置的佇列),所以第 1 位代表那條佇列中沒有排在它前面的 run,不代表它下一個啟動。
:::note 同一張卡的別名會併成同一條佇列
cuda 與 cuda:0 指的是同一個實體裝置,因此會正規化成同一個佇列 key(cuda:0),而不是在同一張卡上開兩條各自獨立的 FIFO。mps 與 mps:0 也一樣。在多張卡的機器上,cuda 會跟隨該行程目前的裝置。
:::
:::note run 的裝置從哪裡來
沒有明確指定 device 的 run 會使用圖檔裡的 settings.device;圖檔也沒有指定時就在 cpu 上執行,不會有任何機制替你選加速器。指定了裝置集合(target.devices,或 cdui run 的 --devices)的 run 則改用集合的第一個裝置,不會參考 settings.device。--device auto(或請求本文中的 "device": "auto")是唯一的例外:它會解析成這台伺服器能看到的最佳加速器(依序 cuda、mps、cpu),並排在那條佇列上。指定了不存在的加速器會退回 cpu 並發出警告。
:::
run 也可以指定目標(target):在請求的 options 裡寫 "target": {"worker": "local", "devices": ["cuda:0", "cuda:1"]},或在 cdui run 加上 --target / --devices。worker 可以是 local(這台伺服器;省略 worker 時也是它)、已連線的 worker agent 名稱(見 Worker),或 any。devices 列出同一種類的具體裝置(cpu、cuda:N、mps:N;只寫 mps 視為 mps:0,只寫 cuda 會被拒絕;不能用 auto、不能重複,也不能把 cuda 和 cpu 混在一起)。device 省略或為 auto 時,清單的第一個就是 run 的裝置,也就是它的佇列;device 只寫種類時也一樣("device": "cuda" 搭配 ["cuda:1", "cuda:0"] 會在 cuda:1 上執行)。device 指向其他裝置則會被拒絕。run 的資料列以 worker_id 與 devices 回報這兩項。在這台伺服器上,run 用第一個裝置排隊與執行,並在集合中每一個裝置各佔一個名額;在 worker 上,run 會佔用並使用集合中的每一個裝置。另有三個鍵用於依記憶體共用的 worker 卡:memory_gib(run 在每張卡上的預算,大於 0、最多 4096 的數字;搭配 local 會被拒絕)、memory_source("estimate":該 memory_gib 是排入佇列...對話框提供的靜態估計值,Runs 面板會標為「(估)」;預設的 "declared" 不會儲存;沒有 memory_gib 時會被拒絕)與 wait(true:預算目前放不下時等待;false:改為拒絕),見多 GPU:共用一張卡。沒有指定 target 的 run 行為與以往完全相同。
Worker
Worker agent(cdui agent start,見 CLI 指令)連到這台伺服器,把交給它的每個 run 放在自己的子程序裡執行。它可以與伺服器在同一台機器上,也可以在另一台機器上,以 Workers 面板產生的 token 加入(見遠端 Worker);已加入的 worker 在連線前列為 offline,這段期間 run 仍可指定它(Queue on... 也可以)並在佇列中等待。移除 worker 時,仍在佇列中等它的 run 會失敗。GET /api/workers 列出各 agent 與其裝置,每個裝置附上 slots(limit、taken);回應的 local 欄位以相同格式列出這台伺服器的裝置,same_host: true 標示在這台機器上的 agent。這種 agent 中屬於這台伺服器的裝置會帶有 shared_with: "local",其 slots 就是這台伺服器那張卡的名額(同一個計數與上限),加總用量時只能算一次。POST /api/workers/{id}/drain 讓某個 agent 不再接新的 run(/undrain 恢復)。
target.worker 決定 run 放在哪裡:
- 省略或
local:這台伺服器,排在解析後裝置的佇列上,與沒有 worker 時完全相同。 - worker 名稱:那個 worker。它必須在這台伺服器啟動後連線過,而且依它最後回報的裝置,必須提供該裝置集合、指定的裝置,或指定種類的裝置(
cuda、mps;auto依序選 CUDA、MPS、CPU),否則送出會回400。降級的 worker(節點型別與這台伺服器不同)只接受它擁有全部節點型別的圖;其他圖會回400並列出缺少的型別(遠端 Worker,讓 worker 保持同步)。曾經連線、目前離線的 worker 不會造成拒絕:run 會排入佇列,等它重新連線。當該裝置在 worker 上的名額都被佔用(每張加速卡一個 run,CPU 兩個,與這台伺服器相同),或 worker 正在 drain 或離線時,run 會在<worker>/<device>佇列等待;後兩種情況會寫在 run 的queue_reason(worker gpu-box is draining、waiting for worker gpu-box to reconnect)。 any:依名稱順序,第一個已連線、未 drain、該裝置有空位,且不缺少這台伺服器有的節點型別的 worker(缺少型別或未回報節點目錄的 worker 會被略過),最後才是這台伺服器。worker 會重新編號的 CUDA 裝置集合(超過一張卡,或不是cuda:0的單張卡)不會在這台伺服器上執行:在 worker 上,集合會為該 run 從cuda:0重新編號,在這台伺服器上則不會,所以固定在cuda:1的節點會用到另一張卡。這種 run 會等待提供整個集合的 worker。cpu、mps或["cuda:0"]的集合,只要這台伺服器有,仍可在這裡執行。這台伺服器與它啟動後見過的所有 worker 都不可能執行的 run,送出時回400;只有離線中的 worker 提供的裝置,會讓 run 排入佇列,直到提供該裝置的 worker 連線。
"target": {"pool": "one-shot"}(不指定 worker,或 any)會把 run 放到單次 worker(cdui agent start --one-shot)上,且只放在那裡:any 永遠不會使用單次 worker。run 在池中依裝置排隊(pool:one-shot/<device>;以 --run-id 啟動的 agent 可不依順序取走它的 run),等待提供其裝置的單次 worker,並在 CODEFYUI_WORKER_ONE_SHOT_QUEUE_TIMEOUT_S(24 小時)後失敗;指名單次 worker 的 run 也以同樣方式等待。見遠端 worker:單次 worker。
在 worker 上的 run 不能走 interactive lane(畫布一律在這台伺服器執行),送出時會被拒絕。開啟 record_outputs 時,worker run 的擷取資料保存在 worker 上,worker 連線時 Inspector 向它讀取(執行架構:Worker 上的錄製輸出)。開始執行後,run 的資料列記錄 worker_id、devices 與 <worker>/<device> 形式的 queue_key,事件與本機 run 相同。停止會傳到 worker,worker 先以合作方式停止 run,超過寬限時間後強制終止。
Worker 斷線時,它的 run 會在 CODEFYUI_WORKER_RESUME_GRACE_S(5 分鐘)內繼續執行;會讀寫檔案的 run 需要兩台機器共用的資料夾,或 transfer 後端:見遠端 Worker:連線中斷時與遠端 Worker:儲存。
worker 上的 seeded run 是在自己的程序裡單獨執行:可重現的執行中「seeded run 單獨執行」的規則保護的是這台伺服器整個程序共用的亂數狀態,而 worker 的子程序有自己的亂數狀態。因此不同 worker 或不同卡上的 seeded run 可以同時執行,worker 上的 seeded run 既不等待這台伺服器的 run,也不會擋住它們。在這台伺服器上執行的 seeded run(包括落在這裡的 any run)仍然一次執行一個。
要在多 GPU 機器上同時執行多個工作、啟動 worker 與選擇裝置,請參閱多 GPU 執行。
這項限制控制的是每個裝置的 run 數量,與 CODEFYUI_MAX_PARALLEL_NODES 不同;後者限制單一 run 內可同時執行的節點數。兩項並行上限的效果會相乘。
通道(lane)
一個 run 的通道記錄它從哪裡來,並決定它怎麼被排程。
| 通道 | 由誰送出 | 排程方式 | 上限 |
|---|---|---|---|
queued(預設) | POST /api/runs、cdui run | 加入該裝置的 FIFO | 依裝置,見上表 |
interactive | 畫布(在圖上按 執行) | 跳過 FIFO,立即開始 | 同時 2 個,且每個編輯器 session 只能有 1 個 |
畫布會刻意跳過佇列:課堂示範不應排在六小時的訓練工作後面。代價是 interactive run 可能讓同一張卡上的執行數超過該裝置 queued 通道的上限。FIFO 的用途是讓無人看顧的工作依序進行,而不是讓裝置只供一個 run 使用。
interactive 通道的兩道上限
因為它跳過佇列,interactive 通道改用另外兩種方式設限:
- 最多兩個 interactive run 同時執行(
CODEFYUI_RUN_INTERACTIVE_MAX_CONCURRENT),避免大量開啟的分頁耗盡 GPU 資源。 - 每個編輯器 session 只能有一個 run。 每個開啟的畫布連線會讓由它啟動的 run 使用該 session 的執行快取與持久化模組權重。這讓第二次點擊 執行 時可以重用第一次 run 的權重與已快取的上游節點。若兩個 run 同時共用這份狀態,會讀到彼此尚未建立完成的 tensor,因此伺服器會拒絕第二個 run。
這兩種拒絕都會立即明確回報(HTTP 503 或畫布上的錯誤),而不是無提示地等待。畫布前有使用者在等;點擊後若默默加入看不見的佇列,與當機沒有分別。實際使用時不會碰到每個 session 一個 run 的規則,因為 run 進行期間 執行 按鈕會停用。
觀察與取消
GET /api/runs 會為每個排隊中的 run 回報 queue_position — 從 1 開始,而且是在它自己那條裝置佇列裡的位置,所以排在兩個 CPU run 後面的 CPU run 就是第 3 位,不管它前面送出過幾個 CUDA run。cdui run --wait 等待時會印出這個位置,結果面板的 執行任務 分頁則會顯示成 佇列第 N 位。
取消一個還沒開始的 run,就只是把它從隊伍裡拿掉。什麼都沒執行、沒有碰到任何裝置,後面的 run 依序遞補。該筆紀錄會標成 cancelled 且沒有開始時間,正在追蹤它的客戶端也會收到一般的停止事件。
取消一個已經在跑的 run 則是協作式的 — 見執行圖的「停止」一節。
:::note 上限為 1 的佇列上,可能短暫出現兩個 running
run 的圖完成後會立即歸還裝置名額,再寫入最終狀態與結束事件。因此,下一個 run 可能在前一個 run 尚未完成狀態寫入時啟動,這段期間的查詢會在上限為 1 的佇列中看到兩筆 running。裝置上沒有重複執行任何內容;前一個 run 已經結束,裝置也已經可用。這項設計可避免 GPU 在資料庫寫入期間閒置,也可避免畫布收到 run 已結束的通知後,下一次執行仍因名額尚未歸還而被拒絕。
:::
執行任務面板
結果面板的 執行任務 分頁會列出伺服器持有的最新 50 個 run,不論它是從哪個分頁、排入佇列...、cdui run 或 API 啟動,並依最新到最舊排列。篩選 chip 包含 全部/執行中/排隊中/已成功/失敗/已取消/已中斷,欄位是名稱、狀態、執行位置、裝置、預算、開始、耗時、最終損失。執行位置 對本機 run 顯示本伺服器,對尚未放置的 any run 顯示任一可用,其餘顯示 worker 名稱;裝置列出 run 的裝置集合或裝置,worker 上的 run 在滑鼠停留時會顯示每張卡在 run 內的名稱;預算顯示依記憶體共用之卡上的 run 的記憶體預算(接受的靜態估計值標示「(估)」,見共用一張卡),否則為 -。從分頁啟動的 run 會以該分頁的名稱列出,最多 64 個字元。篩選 chip 會在取前 50 筆之前套用,重新整理旁的數字會顯示符合條件的 run 列出了幾筆(50 / 312)。更早的 run 可以用 GET /api/runs?offset= 取得。等待中的 run 會在裝置下方顯示它的排隊位置:佇列第 N 位,any run 則顯示 任一可用佇列第 N 位,因為它在自己的佇列(any/<device>)中等待,不與指定 worker 的 run 一起計算;滑鼠停留時會顯示佇列名稱。run 除了排隊之外還在等待其他條件時,原因會以面板的語言顯示在該列下方(queue_reason,例如 waiting for worker gpu-box to reconnect,any run 則如 waiting for a worker that offers cuda: gpu-box is draining)。worker 上 run 的錯誤與警告也以面板的語言顯示,最終損失小於 0.001 時改用科學記號。新增掃描可建立參數掃描。每一列最多提供四個動作:
| 動作 | 用途 |
|---|---|
| 停止 | 要求排隊中或執行中的 run 停止 — 採協作式停止,見停止。 |
| 觀看 | 只適用於排隊中或執行中的 run。把該 run 串流到目前分頁的執行紀錄並從頭重播,同時把面板切換到執行紀錄。你可以用它查看從終端機或另一個分頁送出的 run;目前分頁會停止跟隨原本觀看的 run(若那個 run 仍在執行,會先詢問),但兩個 run 本身都不受影響。 |
| CSV | 下載該 run 的指標(GET /api/runs/{id}/metrics?format=csv)。 |
| 刪除 | 只適用於已結束的 run。移除該 run 的指標、事件紀錄、產出紀錄與任何錄製的輸出;磁碟上的 checkpoint 檔案會保留。 |
點擊一列可查看詳細資訊:run 實際使用的裝置(排程器解析出不同裝置時,例如 auto,將滑鼠移到上面可看到原本要求的裝置)、有設定時會顯示亂數種子與決定性、環境與環境摘要的前 12 個字元(將滑鼠移到上面可看到完整摘要;見執行環境),失敗時會顯示錯誤;此外還有指標圖表及其下載 CSV、每筆已記錄產出檔案的複製路徑按鈕、以「資料與模型來源」排入的 run 會有的「資料與模型」(它讀取的資料集檔案與模型權重,已知時附上版本、內容識別與資料列數;見節點來源),以及事件紀錄的最後 200 筆。run 仍在進行時,紀錄會持續更新。若載入編輯器時仍有 run 在進行,畫面會顯示包含數量的通知,並引導你前往這個面板。沒有開啟任何分頁時(歡迎畫面)不會有結果面板;請先開啟一個分頁。
cdui run
把存好的圖檔送到執行中的伺服器:
cdui run mygraph.json
這個指令會把進度串流到終端機,並在 run 結束時退出。它是客戶端:run 建立在伺服器上,因此即使關閉啟動它的終端機,run 仍會繼續執行。
# 命名、指定 GPU、指定種子
cdui run train.json --name "resnet epoch sweep" --device cuda:0 --seed 42
# 一次排五個工作然後就走
for i in 1 2 3 4 5; do cdui run "sweep-$i.json" --device cuda:0 --detach; done
# 跟著看,但十分鐘後就不等了(run 仍會繼續)
cdui run train.json --device cuda:0 --timeout 600
# 保留節點輸出供事後檢視
cdui run infer.json --record-outputs
# 同一組批次送出的 PowerShell 版本
1..5 | ForEach-Object { cdui run "sweep-$_.json" --device cuda:0 --detach }
| 旗標 | 意義 |
|---|---|
--name <text> | 存在 run 上的名稱,列出 run 的地方都會顯示 |
--device <裝置> | cpu | auto | cuda | cuda:N | mps | mps:N。省略時用圖檔的 settings.device,再沒有就是 cpu;有 --devices 時改用集合的第一個裝置(此時不參考圖檔的 settings.device)。auto 表示這台伺服器最好的加速器。解析後的裝置就是它加入的佇列。 |
--target <名稱> | run 在哪裡執行:local(這台伺服器)、已連線的 worker agent 名稱,或 any。見 Worker。省略時為 local。 |
--devices <清單> | 同一種類的裝置集合,以逗號分隔,例如 cuda:0,cuda:1。--device 省略、為 auto 或只寫種類(cuda)時,第一個就是 run 的裝置;其他 --device 必須與它相同。 |
--seed <n> | 用 n 為每個節點設定種子,讓執行可以重現。省略時使用圖檔的 settings.seed(若有)。設了種子的執行會一次只跑一個節點 — 見 可重現的執行。 |
--no-seed | 即使圖檔有 settings.seed,也不設種子執行(送出 "seed": null) |
--deterministic | 同時要求 PyTorch 使用決定性運算核心(warn_only) |
--record-outputs | 保留節點輸出供事後檢視 |
--wait | 串流進度直到 run 結束(預設) |
--detach | 印出 run id 後立刻以 0 離開 |
--timeout <s> | 等待 N 秒後停止等待。run 仍在伺服器上繼續。 |
--host、--port | 伺服器位址(預設沿用上次 cdui start 啟動的那台) |
run 在排隊時,CLI 會回報它排在第幾位,而不是沒有任何輸出:
=== Run submitted ===
Run ID 3f1c9ab2c04e4d5f8b1a7e6d2c930f45
Graph sweep-3.json
Target local
Device cuda:0
Status queued
○ queued position 3 on cuda:0
▸ started
✓ dataset
trainer epoch 3 batch 912/938 loss=0.1187
trainer epoch 3/10 loss=0.1235 lr=0.001
✓ trainer
✓ run complete
Result succeeded
離開碼
| 代碼 | 意義 |
|---|---|
| 0 | run 成功(或 --detach 成功送出) |
| 1 | run 失敗、被取消或被中斷 — 或 CLI 無法送出它(沒有伺服器、找不到圖檔、envelope 被拒絕) |
| 2 | 命令列參數有問題(argument parsing) |
| 130 | Ctrl+C。只是停止跟隨,run 仍在伺服器上繼續執行,等同於當初就加了 --detach。 |
--timeout 到期同樣以 1 結束:指令不能替一個它已經不再觀察的 run 宣告成功。
:::tip 沒有伺服器?請改用離線執行器
cdui run 會連線到執行中的伺服器。若要在完全不啟動伺服器的情況下,直接於行程內執行圖形,請使用 CLI 圖形執行器;這項工具沒有變動,適合沒有常駐服務的機器。
:::
參數掃描
一次 sweep 會用不同的參數值重複執行同一張圖,再依一項指標為結果排名 — 也就是在佇列上做 grid 或 random search。POST /api/sweeps 會把搜尋空間編譯成每種組合各一份完整的圖,將每份圖當作一般 run 加入 queued 通道,然後以 201 回覆 sweep_id、total_combinations、展開後的 params,以及每個排隊中 variant 的一筆資料(index、run_id、status、seed、params)。三條 route 都列在 API 參考;兩個 POST 和其他會修改狀態的 route 一樣需要 session token,GET 則是開放的。
{
"base_graph": {"nodes": [ ... ], "edges": [ ... ]},
"name": "lr x batch",
"sweep_spec": {
"method": "grid",
"params": [
{"node_id": "opt", "param": "lr",
"range": {"min": 1e-4, "max": 1e-1, "count": 4, "scale": "log", "type": "float"}},
{"node_id": "loader", "param": "batch_size", "values": [32, 64, 128]}
]
},
"objective": {"metric": "val_loss", "direction": "minimize"},
"options": {"device": "cuda:0"}
}
params 裡的每一筆項目都以節點 id 指向該節點的一個參數,並帶有明確且不重複的 values 清單,或由系統展開的 range。range 會從 min 到 max 取 count 個點,並在 linear 或以 10 為底的 log 尺度上等距分布;log 尺度需要正的 min。若為 type: int,結果會四捨五入成整數;如果因此只剩較少的相異值,就只使用那些值。任何項目排入佇列前,每個值都會依節點定義檢查型別、允許的選項及 min/max。無法滿足的 spec 會收到指出該項目的 400,且不會留下只建立一部分的 sweep。不符合請求 schema 的本文會更早被拒絕,回傳 FastAPI 的 422 驗證錯誤,例如缺少 objective、本文最上層或 sweep_spec、objective、params 項目及其 range 內出現未知的 key、method、scale、type 或 direction 不在列出的值之中、count、seed 或 samples 不是整數、values 裡有 null、清單或物件,或 objective.metric 是空白。本頁其他的 sweep 拒絕情況都是 400,包括 options 內的未知 key。
Grid 或 random。 method: grid 會列舉每一種組合,最後列出的 param 變動最快,且不接受 samples。method: random 會抽取 samples 種不重複的組合,而且 samples 與 seed(0 到 4294967295)缺一不可;相同的 seed 永遠會抽到相同組合。要求的 sample 多於空間能提供的組合會被拒絕;編譯後 variant 數量超過上限的 sweep 也會被拒絕,絕不會默默截斷。
objective 是必填的。 metric 是節點所記錄的一個 series 名稱(train_loss、val_loss、val_accuracy、eval_accuracy、accuracy、mse、r2、success_rate,或外掛節點記錄的任何名稱;TrainingLoop 與各評估節點記錄的 series 列在執行圖),direction 則是 minimize 或 maximize。送出時不會檢查這個名稱,因為當時還沒有任何 variant 跑過;如果最後沒有任何 variant 記錄它,排名表會是空的,並附上一個 objective_warning,列出各 run 實際記錄的 series。
objective.node_id 指定以哪個節點的 series 排名。 此欄位可省略;block 內的節點以攤平後的 id(block/inner)指定。指定後,每個 variant 的 objective 是該節點記錄的最後一點(step 最大者,同 step 取最後寫入者),其他節點記錄同名 series 不會改變這個值。省略時只以名稱選取:只有一個節點記錄該指標時,使用該節點的最後一點。同一個 run 中有多個節點記錄它時,該 variant 沒有 objective 也不排名,其 ambiguous_producers 會列出這些節點,objective_warning 也會提示指定節點。系統不會替你挑選節點。在 node_id 推出前建立的 sweep 依相同的名稱規則處理:已收回的值會保留,之後收回且由多個節點記錄的 variant 不排名。
options 會原封不動交給每個 variant(device、record_outputs 等),但有三種情況會被拒絕:options.seed(seed 由 sweep 管理)、lane: interactive(sweep 一律排隊),以及 variant 數量超過輸出儲存上限(預設 20)時使用 record_outputs,因為最早幾個 variant 的捕獲資料會在 sweep 結束前被逐出。若要為訓練本身設定 seed,請設定 sweep_spec.seed 及 "seed_variants": true:第 i 個 variant 會使用 seed + i,超出時折回有效的 seed 範圍。若設定 seed_variants: true 卻沒有提供 sweep_spec.seed,請求會在建立任何資料列前以 400 拒絕。這會讓每個 variant 都成為 seeded run,因此一次只執行一個節點,同一個程序裡也不會有其他 run 同時執行。在這台伺服器上的 seeded sweep 會嚴格依序執行,畫布 run 在整段期間都無法執行;詳見可重現的執行。
options.target 同樣會交給每個 variant(見 Workers)。使用 "target": {"worker": "any"} 且不指定 devices 時,每個 variant 會在任一已連線的 worker 上(最後才是這台伺服器)取得 sweep 裝置種類的下一個空閒名額;因此在兩個各有一張卡的 agent 上,4 個 variant 的 sweep 會同時執行兩個,哪張卡先空出來就在那張卡上開始下一個。worker 上的 seeded variant 也會並行執行,因為每個都在自己的程序裡。單一 run 會被拒絕的 target(這台伺服器從未見過的 worker、沒有人提供的裝置、在 agent 不支援的 worker 上使用 record_outputs)會讓整個 sweep 在建立任何資料列前以 400 拒絕。離線中的 worker 不會讓 sweep 失敗,即使它在 variant 送出途中離線也一樣:它的 variant 會等它重新連線。沒有 target 的 sweep 行為與以往完全相同:每個 variant 都在這台伺服器上該裝置的佇列中等待。
可以掃描什麼: 已註冊節點上的 int、float、bool、string 與 select 參數。不支援 preset 實例的內部參數、subgraph 實例的參數、SECRET 參數(選中的值會以明文存入 sweep 資料列),也不支援在圖中出現兩次的 node id。
交叉驗證就是掃描折。 KFoldSplit 會把 fold 參數指定的那一折留作驗證集,所以用 {"node_id": "<KFoldSplit 的 id>", "param": "fold", "values": [0, 1, 2, 3, 4]} 做 grid 掃描(n_folds 為 5 時),每一折都會各跑一次,每個變體記錄自己的指標,例如 RegressionMetrics 的 r2。各變體目標值的平均就是交叉驗證分數;sweep 會為各折排序,但不會替你取平均。折的切法只取決於 KFoldSplit 的 n_folds、shuffle 與 seed,與執行的種子無關,所以 seed_variants 不會改變每個變體留作驗證的資料列。
| 變數 | 預設 | 上限 |
|---|---|---|
CODEFYUI_MAX_SWEEP_RUNS | 32 | 單一 sweep 的 variant 數 — grid 大小或 samples |
CODEFYUI_MAX_SWEEP_PARAMS | 4 | params 的項目數 |
CODEFYUI_MAX_SWEEP_DOMAIN | 32 | 單一 param 在 range 展開後的相異值數量 |
讀取結果
GET /api/sweeps/{id} 會回傳該 sweep:它的 state(running、cancelling、finished;若送出迴圈中途失敗則為 failed,但已排入佇列的 child 仍會繼續)、objective、依 status 分組的 counts、包含每個展開後 domain 的 params,以及按排名順序、最佳者優先的 variants。每個 variant 會帶著自己的 index(送出順序)、run_id、即時 status、收到的 params、seed、達到的 objective 值、objective_node_id(讀取該值的節點)、ambiguous_producers(僅在只以名稱選取且有歧義時出現)、rank、run_exists;child run 仍存在時另有其 final_metrics、worker_id、devices 與 queue_key(執行的位置;等待中的 any variant 在被放置前顯示 any 與 any/<device>)。best 指向排名第 1 的 variant。run 結束且記錄過 objective 後,variant 會依該 series 的最終值排名;run 即使在記錄後失敗仍會列入排名,沒有排名的 variant 則保留自己的資料列,以 index 順序排列並顯示 rank: null。?format=csv 可將同一份表格下載成試算表,包含 objective_metric、objective_node_id 與 ambiguous_producers(以 ; 分隔,未經節點記錄的 series 寫作 (run))欄位,每個掃描參數各佔一欄。final_metrics 不用來選取 objective。它和執行任務表格一樣,是這個 run 記錄的每個 series 的最後一個值,但 objective 節點記錄過的名稱改取該節點的值:有兩條訓練分支的圖會顯示被掃描那條分支的 lr 與 loss,只有其他節點記錄的 series(例如 Evaluate 節點的 val_acc)也仍然保留。final_metrics_node_id 指出該節點。僅以名稱指定、尚未收回的 variant、run 層級的 objective,以及有歧義的 objective,final_metrics_node_id 為 null,多個節點記錄同名時取最後寫入者。
即使 child run 被移除,結果仍會保留:每次 GET /api/sweeps/{id} 與每次取消,都會把每個已結束 variant 的 status 與 objective 複製到 sweep 資料列上,而 retention 會在刪減 run 前對任何尚未讀取的結果做同樣的事。因此,被 retention 刪減的 child 會保留已收回的 status、objective、objective_node_id 與 ambiguous_producers,並顯示 run_exists: false,不含 final_metrics。在任何讀取或取消收回結果之前就以 DELETE /api/runs/{id} 刪除的 child,會顯示 status: "missing" 與 objective: null。兩種情況下,該 variant 的資料列都會保留。
sweep 的 state 還是 running 或 finished 時,它仍可能帶著 error。那是 retention 在回報一次沒能完成的收回:child 已如期被刪除(刪除不會為了先保住結果而延後),但它們的 objective 來不及複製過來,那些數字就此消失。訊息會寫出有幾個 run 被刪、以及出了什麼問題。少了這則訊息,空白的比較表和一個從未記錄過任何東西的 sweep 看起來完全一樣,而這正是它要分辨的事。state: "failed" 的意思仍然只有一個:送出迴圈中途失敗。
取消
POST /api/sweeps/{id}/cancel 會要求每個排隊中或執行中的 child 停止 — 每個各送一次協作式取消 — 並回報 cancelled 與 already_finished 的數量,以及按 index 排列的逐 variant 清單。從未取得 run 的 variant,以及 run 仍顯示 running 但取消請求無法送達的 variant(例如由使用同一個資料庫的另一個伺服器行程啟動的 run),都不會計入這兩個數量。只有至少一個 child 當時仍在活動時,sweep 的 state 才會變成 cancelling;它永遠不會變成 cancelled:前 30 個 variant 完成、最後 2 個停止的 sweep,是一個帶有 2 列 cancelled 的 finished sweep。所有 child 都進入終止狀態後,下一次讀取(如果它們原本都已終止,也就是 cancel 回覆本身)會把 state 確定為 finished。重複要求不會有副作用(cancelled: 0)。
取消是一個請求,不是保證。停止是協作式的:伺服器立起旗標,節點得自己去讀。訓練、評估與取樣節點每個 batch 都會檢查,因此會在一個 batch 之內停下;從不檢查的節點則會像沒有人要求過一樣一路跑完。對伺服器程序內的 run,這個請求背後沒有強制停止,也沒有逾時:要強加期限,唯一的做法是在訓練步驟中途把 run 砍掉,那會丟掉它已經做完的工作,在 GPU 上還可能讓裝置直到伺服器結束前都無法使用。worker 上的 run 有自己的程序,若它在寬限時間(預設 30 秒)內沒有停下,worker 會終止它,結束的只有那個 run 的程序。
所以 cancelling 沒有時間上限。它結束於最後一個 child 進入終止狀態,而不是等滿某個時間;重新啟動伺服器也會結束它,因為舊行程遺留的 run 會在啟動過程中被收尾。想知道取消還在等什麼,請讀 GET /api/sweeps/{id} 的 counts.running 加 counts.queued:那些就是已被要求、但還沒停下的 child,variants 會指出是哪幾個。sweep 顯示 cancelling 已經多久,說明不了任何事。
在執行任務面板中
執行任務面板工具列上的新增掃描會從目前開啟的圖建立 sweep。對話框會列出圖中最上層已註冊節點的 int、float、bool 與 select 參數,每個參數以節點的標籤與 id 命名(Optimizer (opt-plain) · lr),兩條分支的節點因此能分辨;在 block 內編輯時,列出的仍是最上層的圖,因為 sweep 執行的是那張圖。自由文字的 string 參數只能透過 API 掃描。每個參數可以填一串值,數值參數也可以用區間,對話框會顯示這樣會產生幾個 variant。超過上表三個預設上限之一時,對話框會發出警告並指出對應的設定,但仍會送出 sweep:伺服器可能已調高上限,無法執行的請求則由伺服器拒絕。目標指標預設為 train_loss,TrainingLoop 每個 epoch 都會記錄它;欄位也會建議清單中各 run 記錄過的 series。目標節點會列出這些 run 中記錄所選指標的節點;選擇任一節點時只送出名稱,若列出的 run 顯示有多個節點記錄它,對話框會發出警告。各 variant 沿用分頁的裝置與執行設定,但不包括亂數種子(請改用每個變體都設定亂數種子),也不錄製輸出。目標與裝置和 Queue on... 對話框相同:本伺服器、worker 加上裝置集合(與該對話框相同,列出伺服器知道的每個 worker),或任一可用加上裝置種類,後者會把 variant 分散到所有空閒的卡上(見上方的 options.target)。選擇器一開始是本伺服器與分頁的裝置;auto(由伺服器選擇)或這台伺服器沒有的裝置會照原樣列出。維持不變時,sweep 會像以往一樣以分頁的裝置送出,不帶 target。名稱留白時,sweep 會以分頁的名稱命名,最多 64 個字元。
開始掃描會開啟該 sweep:狀態、目標指標、各狀態的數量,以及每個 variant 一列的表格,列出參數值、目標值、排名、最終指標(這個 run 記錄的每個 series 的最後一個值,多個節點記錄同名時取 objective 節點的值;滑鼠停留在欄位標題時會顯示該節點),以及執行位置與裝置(any variant 被放置前顯示 any),表格下方是目標曲線。sweep 結束前,畫面每 2 秒重新讀取一次。點排名、狀態或目標值的欄位標題即可排序;沒有值的列一律排在最後。查看會開啟該 variant 的 run,child run 詳細資訊中的開啟所屬掃描則會回到 sweep。停止掃描會送出 POST /api/sweeps/{id}/cancel,下載 CSV 會下載 ?format=csv 的表格。
child 都是一般 run:它們在執行任務面板的清單中以 sweep 的 name 加上 variant 編號列出,編號與 sweep 表格上的相同,即其 index 加一(lr x batch #3);兩者合計超過 64 個字元時,會截短 sweep 的名稱。沒有名稱的 sweep,其 child 也沒有名稱。GET /api/runs 的每一列都帶有 sweep_id 與 sweep_variant。要跟隨某一個 variant,可像其他 run 一樣使用 GET /api/runs/{id}/events。編輯器沒有過往 sweep 的清單;要再次開啟,請使用 child run 的開啟所屬掃描。
實驗研究(study)
study 是一個從頭到尾都由伺服器負責的實驗:一組圖的變體,每個變體重複執行固定次數、每次重複使用不同的種子,並依單一明確的目標排名。Graph Copilot 過去把這份計畫放在啟動它的瀏覽器分頁裡,關掉分頁 study 就跟著中斷。送到 POST /api/studies 的 study 存放在伺服器的資料庫中:分頁關閉後它會繼續執行,伺服器重新啟動後它仍在,繼續執行時也不會重跑已完成的重複。任何用戶端都能列出 study,並依 id 追蹤其中一個;study 與送出它的分頁或外掛沒有綁定關係。在網頁介面中,執行任務面板上的 Studies 按鈕會開啟 Studies 面板,列出所有 study 並追蹤其中一個。
{
"name": "lr study",
"objective": {"node_id": "train", "metric": "val_loss", "direction": "minimize"},
"base_graph": {"nodes": [ ... ], "edges": [ ... ]},
"variants": [
{"label": "baseline", "ops": []},
{"label": "lr 1e-3", "ops": [{"node_id": "opt", "param": "lr", "value": 0.001}]},
{"label": "wide", "graph": {"nodes": [ ... ], "edges": [ ... ]}}
],
"repetitions": 3,
"seed": 7,
"options": {"device": "cuda:0"},
"budget": {"max_runs": 12, "max_parallel_runs": 1},
"resume_policy": "explicit"
}
每個變體可以是一張完整的 graph,或是一串套用在 base_graph 上的 ops([] 就是 base graph 本身);label 必填,且在同一個 study 內不可重複。一個 op 設定一個節點的一個參數,檢查方式與 sweep 參數完全相同:節點必須恰好存在一個、必須是已註冊的節點,且不能是 preset 或 subgraph 實例;值必須符合參數的型別、選項與上下限。op 不能設定 SECRET 參數。最多接受 CODEFYUI_MAX_SWEEP_RUNS(32)個變體與 32 次 repetitions。
study、它的變體與所有 attempt 會在同一個 transaction 中寫入,因此被拒絕的請求(400;body 不符合 schema 時為 422)不會留下任何資料。回覆為 201,內容與 GET /api/studies/{id} 回傳的 study 相同,另加 created: true。各 route 列在 API 參考;POST 需要 session token,GET 是開放的。
送出 study
objective 指定一個明確的產生者。 node_id、metric 與 direction 三者皆必填。一次重複的值,是該節點以這個 series 名稱記錄的最後一個點(step 最大者,其次為最後寫入者),與帶有 objective.node_id 的 sweep 使用相同規則。study 沒有只靠名稱的寫法:可能據以晉升某個變體的排名,需要每個 run 都有一個不含糊的數字。
種子。 每個變體的第 r 次重複都以種子 (seed + r) mod 2^32 執行。同一次重複的所有變體共用它的種子,因此同一次重複內的比較是成對的;重試某次重複時也沿用它的種子。省略 seed 時,伺服器會自行挑選並記錄。options.seed 會被拒絕,因為種子由 study 決定;lane: interactive 也會被拒絕,因為 study 的 child 一律排隊。每個 child 都是指定種子的 run,因此一次只執行一個節點,也不會有其他 run 同時執行,與指定種子的 sweep 相同。
冪等性(idempotency)。 請送出 Idempotency-Key header(或 body 欄位 idempotency_key;兩者同時送出時必須相同)。以同一個 key 重送相同請求時,會以 200 與 created: false 回傳同一個 study,且不建立任何 run,因此遺失第一次回覆的用戶端可以放心重送。同一個 key 用於不同請求時回傳 409,並指出既有的 study。比對請求時會先清空 SECRET 值,因此只有 secret 值不同的重送會被視為同一個請求。
預算。 budget.max_parallel_runs(預設 1,最多 32)是這個 study 同時可以排隊或執行中的 child 數。每個 child 都指定了種子,所以在這台伺服器上執行的 child 仍會一次執行一個,較大的值只是讓後面的 child 提早進入佇列。options.target 會像 sweep 的 variant 一樣交給每個 child,建立任何資料列前也套用同樣的 400 檢查(使用相同 idempotency key 的重試會先回傳既有的 study 或 409,再做這項檢查);被放到 worker 上的 child 在自己的程序裡執行,因此使用 "target": {"worker": "any"} 且有兩張空閒的卡時,max_parallel_runs: 2 會同時執行兩個 child。budget.max_runs(選填)限制 study 總共可送出的 attempt 數(包含重試),且必須至少為 variants x repetitions。budget.max_run_seconds(選填)會停止執行時間超過上限的 child;該次重複以 timed_out 結束,這是與 failed 相同的結果,study 會繼續。budget.max_active_seconds(選填)限制所有 child 的累計執行時間。用完 max_runs 或 max_active_seconds 時仍有重複未完成的 study 會變成 halted:排程停止,所有結果都會保留,以提高後的預算繼續即可接續。請見實驗研究:預算。
順序。 child 依重複逐輪送出:先送所有變體的第 0 次重複,再送所有變體的第 1 次重複,依此類推。因此中途停下的 study,所有變體都已在相同的種子上比較過。每個 child 都是一般 run,名稱為 <study 名稱> / <label> / r<n>,GET /api/runs 的每一列都帶有 study_id 與 study_attempt_id。
讀取 study
GET /api/studies/{id} 會回傳 study 的 status、revision(study 或其 attempt 每次變動都會增加)、目前 attempt 依狀態分類的 counts、budget_usage(每項預算的用量,以及哪一項已用完)、halt(暫停的 study 才有:預算、上限與用量)、owner(送出它的外掛,或 null),以及每個變體一筆資料,內容包括:
repetitions:每次重複的種子與目前的 attempt。attempts:曾經建立過的每一個 attempt,包含attempt(1、2、……)、run_id、status、error、時間戳記、objective_value、final_metrics(這個 run 記錄的每個 series 的最後一個值,多個節點記錄同名時取 objective 節點的值)、fingerprint_digest與stop_reason(study 因哪一項預算停止它的 child,或null);child run 仍存在時另有worker_id、devices與queue_key(執行的位置,與 sweep variant 相同)。每個重複的currentattempt 也帶有這些欄位。aggregate:對記錄到目標值的目前 attempt 計算的count、mean與std,以及values,也就是每次重複的原始值(沒有值時為null)。std是樣本標準差,值少於兩個時為null。eligible、ineligible_reasons、rank、tie與tied_with。
rankings 會由最佳開始列出已排名的變體。只有當每次排定重複的目前 attempt 都成功,且都記錄到有限的目標值時,變體才具排名資格。失敗的重複是一個結果,不會被重試;即使它在失敗前記錄了數字,也會讓所屬變體失去排名資格,那個數字仍會出現在 values 中。這比 sweep 表格嚴格:sweep 表格會以失敗 run 達到的值為它排名。排名採用對具資格平均值的競賽排名:平均值完全相同的變體共用同一個名次,標示 tie: true,並在 tied_with 中列出彼此,下一個名次則相應跳號(1、1、3)。執行時不做任何平手裁定,結果也不受變體列出順序影響。
study 的證據比它的 child 存在得更久。child 結束時,它的目標值、最終指標、開始與結束時間,以及環境摘要都會複製到它的 attempt 上;retention 在刪除 run 之前,也會把尚未複製的內容複製過去。retention 刪除 study 的 child 之後,GET /api/studies/{id} 仍會回傳所有數值與排名,只有 run_id 指向一個已不存在的 run。
GET /api/studies/{id}/events?cursor= 會回傳 cursor 之後的 study 稽核紀錄:study_created、study_started、attempt_submitting、attempt_submitted、attempt_started、attempt_finished、attempt_relinked、attempt_lost、attempt_added、attempt_stop_requested(預算停止了 child)、study_cancel_requested、study_cancelled、study_interrupted、study_resumed、study_failed、study_halted(其 payload 帶有暫停資訊與目前的排名)與 study_finished(其 payload 帶有最終排名)。cursor 連續不中斷,每個 payload 都帶有該次變動產生的 revision。study 仍在進行時,?wait= 最多長輪詢 60 秒。GET /api/studies 由新到舊列出 study;?status=queued|running|cancel_requested 可找出仍在進行的 study。
取消與繼續 study
POST /api/studies/{id}/cancel 會停止排程,並對 study 每個排隊中或執行中的 child 送出協作式取消;cancelled_runs 列出取消請求送達的 run。在每個 child 都停下之前,study 顯示 cancel_requested,之後變成 cancelled。已完成的 attempt 會保留,從未送出的 attempt 維持 pending。再次取消已 cancelled 的 study 不會有任何變化;succeeded 的 study 不能取消(409)。
POST /api/studies/{id}/resume 會繼續一個 interrupted、cancelled、failed 或 halted 的 study。目前 attempt 已成功、失敗或逾時的重複維持原樣,永遠不會再執行。目前 attempt 被取消、中斷或遺失的重複,會得到一筆新的 attempt 紀錄,使用下一個 attempt 編號與相同的種子,舊的 attempt 則留在 attempts 中作為歷史紀錄。接著,pending 的重複照常送出。對其他狀態呼叫 resume 會回傳 409。選填的 body {"budget": {...}} 會取代 study 的預算(事件紀錄會記下新舊預算);若繼續時的預算已經用完則回傳 409,因為 study 會立刻再次暫停。兩個 route 的 body 都接受 expected_revision,study 已超過該 revision 時回傳 409,讓依據上次讀取結果動作的用戶端不會誤對較新的狀態動作。
以 POST /api/runs/{id}/cancel 直接取消的 child,會讓所屬 study 變成 interrupted。study 不會自行重試那個 run;要再執行那次重複,請繼續(resume)該 study。
重新啟動前後的 study
執行佇列不會跨越重新啟動保留,因此伺服器再次啟動時,會把 study 排隊中與執行中的 child 標記為 interrupted(請見伺服器停止時)。接著,study coordinator 會整理每一個仍在進行的 study:每個 child 的證據會複製到它的 attempt 上,正在取消中的 study 會變成 cancelled,其他未完成的 study 則變成 interrupted 並等待。若 study 有某個 child 是重新啟動的伺服器從 worker 接手的,這個 study 不會被整理:那個 child 視為仍在執行,study 會照常繼續;若那個 child 以 interrupted 結束,study 就變成 interrupted 並等待 resume(指定 "resume_policy": "auto" 時則自行繼續)。正在取消中的 study 會再次要求被接手的 child 停止,等它停下後變成 cancelled。在你呼叫 resume 之前不會重送任何東西;若 study 送出時指定了 "resume_policy": "auto",則會在重新啟動後自行繼續。此時若 auto study 的預算已經用完,它會改為進入 halted(請見預算),因為它會立刻再次暫停。
每個 attempt 在 child 送出之前,就會先記錄它即將使用的 run id,而 child 也帶有該 attempt 的 id。如果伺服器在送出 child 與記錄「已送出」之間停止,或該次寫入失敗,study 會依這個標記找到 child 並重新連結(attempt_relinked),而不會再送出第二個。若沒有任何 child 帶有這個標記,代表該次送出從未建立 run;這個 attempt 會被標記為 lost,該次重複則會得到新的 attempt。
SECRET 參數值只保存在接收該 study 的伺服器記憶體中,與任何排隊中的 run 相同。重新啟動後繼續的 study,執行時這些值會是空白。
伺服器停止時
佇列不會在伺服器重啟後繼續執行。佇列只存在伺服器程序的記憶體中(worker 沒有自己的佇列);如果保留等待中的資料列,它會持續等待已不存在的排程器。
正常關閉會立即將每個等待中的 run 標記為 interrupted、寫入一般停止事件,並給執行中的 run 5 秒以協作方式停止。對放在反向代理後面中的 unit 執行 systemctl stop 就是以這種方式關閉伺服器,因為它會直接對伺服器行程送出 SIGTERM。在 Windows 上,於 cdui start --foreground 按一次 Ctrl+C 也是如此;若在 uvicorn 等待連線關閉時再按一次 Ctrl+C,就會略過這些步驟。
在 Linux 與 macOS 上,於 cdui start --foreground 按 Ctrl+C 不是正常關閉:cdui 行程會在按下 Ctrl+C 約 0.25 秒後強制終止伺服器,因此執行中的 run 拿不到這 5 秒,等待中的 run 也可能來不及標記為 interrupted。cdui stop 同樣不會等這些步驟完成:在 Windows 上它會強制終止伺服器的行程樹(taskkill /F /T),在 Linux 與 macOS 上則先送出 SIGTERM,約 2 秒後再送出 SIGKILL。這些停止方式、其他強制終止行程的方式,或執行超過這 5 秒的 run,都可能留下 queued 或 running 資料列。下次啟動時,復原程序會把這兩種狀態都改成 interrupted,並寫入與正常關閉相同的停止事件;若該 run 的事件紀錄已經以結束事件收尾,就不再寫入。因此重新連上的編輯器分頁,以及讀取 GET /api/runs/{id}/events 的程式,都會看到這次 run 已結束。兩者都不會繼續執行。
在 worker 上執行的 run,正常關閉時也受到相同處理:停止要求會送到 worker,超過這 5 秒仍在執行的 run 會在那裡被終止,接著伺服器關閉與 worker 的連線。agent 會繼續執行,等伺服器回來後重新連線。強制停止伺服器時,worker 不會收到任何通知:它的 run 子程序會繼續執行,下次啟動時會接手這些 run,而不是把它們標記為 interrupted;worker 重新連線後,它們會在同一份紀錄中接續,若 worker 未在 CODEFYUI_WORKER_RESUME_GRACE_S 內回來則以 interrupted 結束(遠端 Worker:連線中斷時)。
若仍要執行這些工作,請重新送出。
study 會跨越重新啟動保留它的計畫,並在繼續(resume)之後執行尚未完成的重複;請見重新啟動前後的 study。
設定
以下都是啟動時讀取的環境變數(跟其他設定一樣使用 CODEFYUI_ 前綴)。
| 變數 | 預設 | 意義 |
|---|---|---|
CODEFYUI_RUN_QUEUE_MAX_CONCURRENT_GPU | 1 | 每條加速器佇列的並行 run 數 |
CODEFYUI_RUN_QUEUE_MAX_CONCURRENT_CPU | 2 | cpu 佇列的並行 run 數 |
CODEFYUI_RUN_QUEUE_MAX_CONCURRENT | (空) | 個別名額的覆寫。只寫裝置時指這台伺服器(cuda:0=2,cpu=8);<worker>/<device> 指該 worker(gpu-box-1/cuda:0=2),不影響這台伺服器。優先於上面兩個預設值。 |
CODEFYUI_RUN_INTERACTIVE_MAX_CONCURRENT | 2 | 畫布 run 的並行上限 |
CODEFYUI_WORKER_RESUME_GRACE_S | 300 | 斷線 worker 的 run 等它重新連線的秒數,逾時以 interrupted 結束(見遠端 Worker:連線中斷時)。0 表示立即結束。 |
CODEFYUI_WORKER_OUTPUT_FETCH_TIMEOUT_S | 60 | 讀取 worker run 錄製輸出時等待 worker 回覆的秒數,逾時回 504。 |
CODEFYUI_MAX_PARALLEL_NODES | 4 | 單一 run 內同時執行的節點數 |
CODEFYUI_RUN_RETENTION_KEEP_LAST | 200 | 保留幾筆已結束的 run。0 表示完全不保留;負值會停用 retention。 |
CODEFYUI_RUN_EVENT_PAYLOAD_CAP_BYTES | 131072 (128 KB) | 儲存及分送的單一事件 payload 上限;超過上限的輸出項目會換成省略標記,但仍會指出它的 port。0 或更小的值會停用上限。 |
CODEFYUI_RUN_EVENTS_RESPONSE_CAP_BYTES | 4194304 (4 MB) | 單一 GET /api/runs/{id}/events page 的 byte 預算;提早停止的 page 會回傳 cursor,供下一次接續。 |
CODEFYUI_MOUNT_LABEL | data | 這台伺服器的資料夾給共用它的 worker 使用的 label(遠端 Worker:儲存)。 |
例如 gpu-box-1 是另一台機器上的 worker 時,CODEFYUI_RUN_QUEUE_MAX_CONCURRENT="cuda:0=2,gpu-box-1/cuda:0=3" 讓這台伺服器的 cuda:0 可同時執行兩個 run、gpu-box-1 的 cuda:0 可同時執行三個,其他卡維持 1。同一台機器上的 worker 與這台伺服器共用的卡使用這台伺服器的上限(cuda:0=2 會提高它),除非該 worker 有自己的 <worker>/<device> 覆寫,而那只能降低它。兩個 worker 共用的卡使用兩者中較小的上限(離線的提供者不計)。被這條規則壓低的覆寫會在 worker 連線時記錄警告。local/<device> 是只寫裝置的另一種寫法。
格式錯誤的覆寫項目會被忽略並記錄警告,不會讓伺服器啟動失敗。小於 1 的上限一律視為 1,避免佇列因無法排空而停滯。三項 sweep 上限列在參數掃描一節。
Retention 會在啟動時及每個 run 結束後執行,保留最新的 KEEP_LAST 筆已結束 run。活動中的 run 不會被刪減,但仍會計入保留窗口。和執行任務面板的刪除不同,刪減也會移除該 run 自動寫出的 checkpoint 與 TensorBoard 目錄。結果為 interrupted 的 run 所留下的 checkpoint 會保留,以避免 crash 造成 resume point 遺失。