工程

我們如何讓 AI beatmap 生成快到像即時互動

一整組 osu! mania mapset 只需約 20 秒 GPU 時間,而不是一分鐘以上:一次 ManiaGAI 請求的時間花在哪裡,以及從瀏覽器到批次生成難度,我們如何把時間省下來。

要等上好幾分鐘的生成器,是批次作業。你送出一首歌,去做別的事,回來再看它做出了什麼——如果不喜歡,想換個風格或換一組難度,就得再等一次。幾秒內就有回應的生成器,才是工具:你可以試、聽、調整,然後再試一次。

正是因為這個差別,在 ManiaGAI 第 2 版中,我們把延遲當成貫穿整個系統的設計限制,而不是最後才來優化的項目。第 1 版生成一組 mapset 要一分鐘以上。第 2 版在一般歌曲上生成一整組 mapset,只需約 20 秒的 GPU 時間——通常是 13 到 25 秒,視歌曲和要求的難度而定。以下是這些時間花在哪裡,以及我們如何把其餘的時間省下來。

拆解一次請求

  1. 你的瀏覽器
  2. Timing ∥ 音樂特徵
  3. Planner
  4. Noter
  5. 驗證
  6. 下載

以 v2 上線時實測的一次正式環境執行為例:一首 2:50 的歌、5 個難度,在 NVIDIA T4 GPU 上——總共 12.7 秒。

一次 ManiaGAI v2 生成的各階段耗時
階段時間
Timing + 音樂特徵(同時執行)3.8 s
規劃(所有難度)1.0 s
音符生成(全部 5 個難度)6.1 s
整次執行12.7 s

v2 上線系統(2026 年 10 月 1 日)上一首歌的 GPU 運算時間,不含上傳、排隊或下載。

1. 在按下「建立」之前,就先處理好音訊

每首上傳的歌,都必須先解碼、做響度標準化,再重新編碼成統一的格式,模型才能使用。在伺服器上,這是幾秒鐘的工作,GPU 只能乾等。在 ManiaGAI 裡,這一步在你的瀏覽器中進行,從你選好檔案的那一刻就開始——當你還在挑鍵數和難度時。等你按下「建立」,通常已經處理完了。如果在較慢的裝置上處理歌曲超過 20 秒,就會改由伺服器接手,所以這項優化永遠不會拖慢任何人。

2. timing 和音樂理解同時進行

開始規劃之前,必須先知道歌曲的兩件事:它的 timing 格線(來自開源的 Beat This 模型,加上我們自己的格線擬合),以及它的音樂特徵(來自 MERT 音樂模型)。兩者互不依賴,所以不必互相等待:GPU 執行 Beat This 和 MERT 的同時,格線擬合也在 CPU 上進行。在上面那次執行中,整個理解階段花了 3.8 秒。

3. 所有難度一次生成

一組 ManiaGAI mapset 最多有十個難度。一個接一個生成,時間就會乘上難度的數量。所以我們改為把所有要求的難度放在同一次批次 GPU 運算中,一起規劃、一起生成——它們共用同一首歌和同一份音樂特徵,只有目標不同。這就是為什麼在上面那次執行中,五個難度的音符生成只花了 6.1 秒。

4. 修整整張譜面,而不是一個音符一個音符地寫

音符模型是非自迴歸的:它用固定輪數的修整產生整張譜面,而不是從歌曲開頭到結尾一次寫一個 token——所以不管譜面最後有多少音符,模型的步數都是固定的。(模型為什麼這樣運作,又是另一個故事了:Planner + Noter 一文。)

5. 從快照啟動,而不是從零開始

生成是在 serverless GPU worker 上執行的,也就是說,請求進來時不一定有 worker 正在運作。從零開始載入模型、完成暖機,會讓第一個請求多花好幾秒。所以我們改為從記憶體快照還原 worker——這份快照是在所有東西都載入並暖機完成後拍下的——讓一個全新的 worker 大約一秒就能就緒,而不必把時間花在載入模型上。

6. 終點線前不再等待

最後幾個步驟過去會額外增加延遲。現在,可下載的 .osz 會在譜面完成的那一刻就打包好,而完成的譜面會在生成結束的瞬間存進「我的譜面」——即使你已經離開頁面也一樣。生成器上的進度會顯示每次生成實際所在的階段,所以等待從來不是一團謎。

再快一倍,譜面完全相同

2026 年 10 月 8 日,我們推出了更快的生成系統實作:現在生成譜面的速度大約快了兩倍,而譜面完全相同——同樣的輸入,同樣的輸出。我們為這次改動訂下一條鐵則:會改變模型寫出內容的加速,就是模型的改動,必須當成模型改動來評估。唯一變短的,只有等待時間。

速度帶來了什麼

速度改變了 ManiaGAI 的使用方式。它讓試第二種風格或換一組難度只是幾秒鐘的事,讓「先預覽、再下載」的流程變得自然,也讓維持免費方案成為可能。這也是為什麼我們優化的是整個請求——從瀏覽器到下載——而不只是模型本身:玩家感受到的是等待,而不是 GPU 時間。

這些階段在系統中的位置,請見技術頁面;什麼時候改了什麼,請見更新紀錄。