8 月 23 日,Surya Narreddi 發布了一段語言模型繪製水彩畫的精美影片。該模型透過 p5.brush 函式庫編寫 JavaScript 程式碼,此函式庫為 p5.js 增添了自然的繪圖工具。這段影片迅速爆紅,截至撰寫本文時已累積超過 150 萬次觀看。
該影片附帶一篇部落格文章,解釋了專案早期階段的訓練細節,當時主要呈現的是特寫花朵而非影片中的完整構圖,可惜尚未公開相關成果。Surya 的網站預告將發布完整的技術報告,建議大家追蹤他。原始構想來自於他深厚的藝術與設計背景,而我的嘗試則著重於工程層面,目標是公開重現所有環節。
註:若想了解 Surya 親自講述的專案背景,請觀看他的論文影片。
在本文中,我將嘗試使用 TRL 和 OpenEnv 重現他的構想。參考資料集、強化學習(RL)環境、訓練腳本以及訓練好的模型,所有環節都將公開。整個流程都在 Hugging Face 上端到端運行。
具體來說,訓練在 Jobs 上進行,RL 環境和評分模型作為 Spaces 運行,配對判斷器透過 Inference Providers 實現,所有成果都集中在 Hub 上的一個集合中。
一旦兩個 Spaces 設置完成,整個流程只需一個指令即可啟動。複製環境和評分模型,設定兩個環境變數以調整獎勵組合,然後執行以下指令:
hf jobs uv run train/watercolour_grpo.py --flavor h200 --timeout 48h --secrets HF_TOKEN -- \
--env-url https://<you>-watercolour-env.hf.space \
--model Qwen/Qwen3.5-35B-A3B --lora --all-linear --bf16 --gradient-checkpointing \
--subject 'a peach hibiscus' --references 4 \
--top-p 0.95 --top-k 20 \
--lr 5e-5 --lr-scheduler constant_with_warmup --warmup-steps 5 \
--scale-rewards none \
--steps 110 --n-episodes 240 --num-generations 8 \
--per-device-batch-size 1 --gradient-accumulation-steps 8 \
--max-completion-length 8192 \
--run-tag my-run --out <you>/watercolour-grpo --push-to-hub
本文的其餘部分將講述實現這一目標的過程,所有細節都可在儲存庫中找到。我嚴格遵循了原始部落格文章的步驟,僅在必要時進行了修改。我自己的所有想法都列成清單,而非直接納入實驗中,這份清單最終成為了「我接下來會嘗試什麼」的部分,與已發布成果的完整清單並列。
如果你已經閱讀過他的文章,那麼框架和獎勵設計會讓你感到熟悉。新的內容包括開放實作、人工評分池以及三種訓練和比較的獎勵組合,這些內容將從「你需要建立的 RL 環境」部分開始介紹。
為什麼人們喜歡它?這些畫作看起來隨性、不完美、有手繪感,這與當前圖像模型生成完美(統計學上平均)圖片的趨勢形成對比。我猜測這種對比是影片爆紅的重要原因之一。這讓我想起了生成式 AI 藝術的早期,那時的重點是探索這種媒介。
DeepDream(2015)原本是個除錯工具,卻被轉化為藝術;Edmond de Belamy(2018)等作品來自藝術家探索生成對抗網路(GAN)的可能性;而 Mario Klingemann 等藝術家則在那些年裡利用神經網路創作夢幻般的肖像。這個專案感覺更接近那些早期階段。在 Surya 的論文中,他描述了導致此處的歷程。
他最初嘗試使用文字轉圖像模型,其中提示詞是唯一可操作的槓桿,但增加細節對控制力的提升有限。訓練模型本身則能走得更遠。這個構想的另一半是媒介本身。模型編寫約 150 行 JavaScript 程式碼來繪製圖像,模型的輸出就是程式碼。你可以閱讀、編輯並再次運行它,每個筆觸背後的決策都清晰可見。其風格來自於模型僅被允許使用函式庫中十種方法的限制,這部分將在下方詳細說明。
同一時期,Anna Ridler 拍攝了數千朵鬱金香,手工標註每一朵,並將資料集本身作為藝術品展出,隨後再用其訓練模型。我在建構此專案時,透過 AI 代理帶回的參考資料發現了她的作品,並非常喜歡,因為這個專案也做了非常相似的事情:透過手工策劃一組圖像,然後以此進行訓練。
關於品味的強化學習。近期大多數關於語言模型的強化學習工作都使用可驗證的獎勵。例如,有已知答案的數學問題、通過測試的程式碼,或是判斷對錯且運行成本低的評分器。這個專案更接近於較早的例外,即 RLHF(人類回饋強化學習),其中模型從人類偏好中學習獎勵模型。
在這裡,獎勵是美學偏好,沒有正確答案。這個專案真正的問題是,你是否能對「品味」進行強化學習。獎勵的定義,如同他的部落格所述,以及我所建立的 RL 環境所實作的:
| 術語 | 權重 | 衡量內容 |
|---|---|---|
| gate | 0.05 | 草圖能編譯、繪製內容,沒有作弊 |
| length | 0.05 | 輕微鼓勵較長的程式碼片段 |
| pairwise judge | 0.60 | 風格,與參考池中的畫作比較 |
| HPSv3 | 0.30 | 渲染圖的美學偏好 |
HPSv3 是一個開放的 7B 偏好模型。給它一張圖片和文字描述,它會返回一個人對該圖片的偏好分數。它是在大量人類對成對圖片的選擇上訓練的,因此其分數是許多人品味的平均值。配對判斷器是 Qwen3-VL-30B-A3B-Instruct,一個透過 HF Inference Providers 調用的通用視覺模型。
配對判斷器會將候選畫作與從池中隨機選擇的四張參考圖並列,並根據書面描述(例如暈染、半透明水洗、柔和邊緣)進行權衡,每種比較都以兩種呈現順序進行,其分數是候選畫作獲勝的比較次數比例。它的唯一標準是參考池,因此其分數代表我個人在這些評分中編碼的品味。
這些是 Narreddi 最終採用的權重。這裡的「池」定義了品味。這將工作從調整超參數轉移到建立決定何為美的集合。我用這個獎勵訓練了三次運行。它們的唯一區別在於兩個模型判斷器之間的權重分配:
| 運行 | 配對判斷器 | HPSv3 | 角色 |
|---|---|---|---|
| judge-led | 0.60 | 0.30 | 原始組合,在第 110 步停止 |
| hps-led | 0.30 | 0.60 | 中間點,在第 110 步停止 |
| hps-only | 0.00 | 0.90 | 驗證運行,在第 60 步停止 |
我從 hps-only 開始,以驗證整個流程是否能學習。一旦獎勵開始上升且指標健康,就沒有理由讓它運行更長時間,所以我啟動了兩個較長的運行。較長運行所提出的問題是,HPSv3 的多少能力可以交給配對判斷器?判斷器承載的權重越多,獎勵就越代表我的品味而非大眾的品味,攀升的難度也應該越大。順帶一提,如果你推得夠遠,或者你的風格與平均值相差太遠,模型可能會完全停止學習。
幸運的是,它並沒有停止,兩個帶有配對判斷器的運行也成功學習。人工評分的池可以引導策略,至少從指標和最終畫作來看是如此。具體數字如下。免責聲明:如果我們使用前沿模型,它已經可以從提示詞生成繪製水彩畫的 JavaScript 程式碼。那是起點。這裡的工作是教導一個較小的模型結合個人的藝術偏好來完成這項任務。
你需要建立的 RL 環境。該環境包裹了模型與獎勵之間的所有環節,包括模型用於繪畫的 JavaScript 函式庫、限制其行為的系統提示詞、渲染每個草圖的無頭 Chromium,以及拒絕作弊的閘門。這個函式庫所做的工作比看起來要多。
p5.brush 由 @acamposuribe 開發,它模擬的是一種繪畫媒介,而非單純繪製形狀:顏料會滲出填充邊緣,紙張有紋理,筆觸有質量,流場會牽引筆觸。當模型呼叫 brush.fillBleed(0.25) 時,它正在決定墨水滲出的距離。
註:p5.brush 的作者在這些專案出現之前,就一直在嘗試教機器繪畫。2022 年,他創作了一個生成藝術系列,其中隱藏著關於教 p5.js 像孩子一樣繪畫的日記:「它幾乎無法使用蠟筆 [...] 它無法遵循簡單的指令。我今天受夠了,非常令人沮喪。」該系列原計畫有三件作品,他完成了兩件。當 Surya 的影片爆紅時,他引用了這段話,分享了那本日記,並表示這項工作是第三件作品自行到來。
p5.brush 暴露了 47 種方法。提示詞只允許使用其中 10 種:scaleBrushes、noStroke、fill、noFill、fillBleed、fillTexture、beginShape、vertex、endShape 和 circle。
其他 37 種方法,如線條、交叉影線、自訂筆刷等,會破壞水彩畫的外觀。透過這 10 種方法,模型只能繪製填充形狀,而函式庫會為每個形狀添加暈染效果。
他的部落格文章為我節省了大量可能浪費在迭代提示詞上的時間。冗長的 API 參考會讓模型發明不存在的方法,而他 200 次 GEPA 迭代的結果收斂於一個沒有文件說明的嚴格白名單。我也看到了同樣的失敗,並手動編寫了白名單。我對該方法唯一的補充是一句話:每個花瓣繪製兩到三次,先是大範圍的塗抹,然後在內部進行較小、較不透明的塗抹。這個小小的改變讓我的輸出色彩更加豐富。
註:如果你是第一次聽說 GEPA,它是一個自動提示詞優化器。語言模型會用簡單的文字反思當前提示詞的失敗之處,並提出一個更好的提示詞,然後這個循環會重複。
閘門是最後一個環節。草圖必須能編譯,使用函式庫而非直接呼叫 p5 函數,在畫布上繪製真實顏料,並且不能試圖欺騙評分器,例如在畫布上寫字。
參考池即獎勵函數。參考池包含 178 幅畫作,根據我的個人偏好分為「喜愛」和「尚可」兩個等級。所有這些畫作實際上都是由模型生成的。四個開放權重模型透過 Inference Providers 呼叫,編寫了 p5.brush 草圖,每個草圖都基於 iNaturalist 上真實、開放授權的朱槿照片。
一個視覺模型對每個草圖提供了書面回饋,經過三次精煉迭代。然後,我逐一評分了每個最終渲染圖,其中 178 幅通過了篩選。
| 生成器 | 畫作數量 |
|---|---|
| GLM-5.2 | 64 |
| Kimi-K3 | 57 |
| Qwen3-Coder-Next | 35 |
| Qwen3.5-122B-A10B | 22 |
我選擇了四種不同系列的模型來測試它們不同的風格。這四個模型在快速可靠性檢查中每次都能生成有效的草圖,而另外兩個候選模型則因未能通過檢查而被淘汰。如果你想建立自己的參考池,你可能會選擇其他模型。
這些等級在獎勵中發揮了實際作用。當配對判斷器選取四張參考圖時,一半來自「喜愛」等級,一半來自「尚可」等級,因此策略總是會面對一些它有時能擊敗的競爭對手,而且無論擊敗哪個等級,獲勝的獎勵都相同。這是我少數幾個刻意修改的地方:原始方法只與最高等級比較,而我將較容易的等級保留在抽樣中,以便早期較弱的策略仍能獲得訊號。
參考池中沒有任何人類創作的畫作,這是一個真正的限制。p5.brush 是一個小眾函式庫,其中存在且程式碼可供存取的人類作品數量極少,遠遠不足以構成一個豐富的參考集。
