跳到主要內容

014互動

三分鐘訓練你的 AI 作曲家:聽它從亂彈到療癒

在瀏覽器裡從零訓練一個會寫四部合唱的小 Transformer,邊練邊聽它從亂彈變成音樂。然後你當評審,點二十下把它調得更放鬆;也看它怎麼找到評審的漏洞。

發布
閱讀時間
7 分鐘

下面這個作曲家現在什麼都不會。按下訓練,它會在你的瀏覽器裡讀巴赫的 333 首四部合唱,一邊學,一邊在六個時刻即興一段給你聽,從第 0 步的亂彈開始。

fig 01/composer / train
在你的瀏覽器裡從零訓練,大約三分鐘。可以邊練邊聽,也可以繼續往下讀。
步數
0
已經過
0
大約還要
驗證誤差

猜下一個音的誤差

曲線是訓練時的誤差;虛線是 5-gram 在驗證資料上的成績(1.46),拿來和每個片段旁邊的驗證誤差比。

它在這些時刻即興了一段

按「開始訓練」,第 0 步的亂彈會出現在這裡。

女高音女低音男高音男低音

音色
左邊是訓練的進度和誤差,右邊是它在每個時刻寫的六小節。一條橫線是一個音,由上到下是四個聲部。下面的數字量的是它寫得像不像四部合唱,不是好不好聽;好不好聽,你的耳朵說了算。

先說這不是什麼。這不是 Suno:它不會唱歌,也不產生聲音檔。它寫的是樂譜,「哪個聲部、什麼音、拖多長」,再由一個從零寫的合成器演奏出來。模型只有六萬五千個參數,權重檔 260 KB,大約是一首三分鐘 MP3 的十分之一。

音樂怎麼變成字

一首合唱被切成一格一格的八分音符。每一格有四個聲部,從女高音到男低音,每個聲部是一個 token:新的音就是它的音高,延續上一個音是 HOLD,休止是 REST。所以模型寫的東西長這樣:女高、女低、男高、男低,女高、女低、男高、男低……

content/posts/music-ai/components/music.ts
export const HOLD = HI - LO + 1, REST = HOLD + 1, VOCAB = REST + 1; // 54 個音高 + 2 = 56 個字

接下來就和 № 004 的 Transformer 一模一樣,連程式都是同一份:看前面的字,猜下一個字。那篇它學的是把數字倒過來寫,這篇學的是巴赫。

這裡有個陷阱:模型只靠「這是第幾個字」分辨聲部,所以每次取最近的 64 個字,開頭都必須剛好是女高音,否則它會把每個聲部都當成隔壁那一個。

它先學會什麼

在圖 1 多練幾次,會發現它每次學會的順序都差不多。我用圖 1 的配方練了兩次,每個時刻寫五段、量同樣的東西,下面是兩次的平均。驗證誤差是它猜下一個音的平均誤差,越低越好;平行五度是四部寫作的頭號禁忌,指兩個聲部隔著純五度一起往同一個方向走:

步數驗證誤差在調上聲部交錯拖長的音平行五度(每百格)
04.5182%87%0.5%3.9
1002.0199%36%78%1.1
2501.6099.7%1.9%50%9.8
5001.3999.6%1.1%55%10.0
10001.2198.7%1.8%54%12.0
20001.0799.2%1.3%53%8.9
24001.0599.5%0%65%7.2
巴赫本人97.7%2.6%45%0.16
  1. 先學會拖長音。 第 100 步有 78% 的音都是拖著的:它發現「繼續上一個音」最常猜對,於是幾乎只會持續音。
  2. 再學會各守各的音域。 聲部交錯從 87% 掉到 250 步的 2%,之後就一直比巴赫還乾淨。
  3. 調性穩下來,節奏沒有完全穩。 調內音一路維持在 99%;拖長的音回到 50% 上下,比巴赫的 45% 多一點,到訓練尾聲又升到 65%,聽起來會比巴赫慢。
  4. 平行五度學不會。 巴赫一百格才犯 0.16 次,它整輪都在 7 到 12 次之間晃。

在我的瀏覽器裡,驗證誤差不到一分鐘就低於 1.46,那是一個 5-gram(只看前面四個字、把次數數起來)在同一份資料上的最好成績。5-gram 的作曲更慘:它看不到四個字以前,一個聲部拖了一格,它就忘了自己在哪個音上,72% 的時間聲部交錯。

它在作曲,還是在背譜?

圖 1 裡的「最長抄襲」,是拿它寫的每一格去比對 333 首訓練曲目,找出和其中一首一模一樣、連續最長的一段。練到 1000 步時是 3 到 6 格(一格是一個八分音符,八格一小節),不到一小節;一首聖詠平均有 107 格。

所以它多半是在作曲。但練得越久,記住的片段越長:2400 步時變成 5 到 10 格。而且十段裡出現過一段整整抄了 32 格、也就是四小節的例外——它確實有能力把整段譜背下來。

你當評審

標題說的「療癒」不是它本來就會的。巴赫的合唱不慢也不安靜;慢下來、安靜下來,是接下來你自己調出來的。

練好的模型寫得像巴赫,但不一定是你想聽的。現在換你:它一次寫兩段,你選一段,它就往你選的那段靠近一點,離另一段遠一點。ChatGPT 這類模型就是用人的偏好調教出來的(RLHF);這裡用的是它後來一個比較簡單的版本 DPO,只是評審換成你。

fig 02/composer / judge

每選一次,模型往你選的那段靠近一點、離另一段遠一點(DPO)。它同時被拉在原本的樣子附近,不會一下子跑太遠。 大約選 20 次就聽得出差別;選太多次它會只剩持續音。

這是一個事先練好 1000 步的模型(和圖 1 同一種,練法相同)。每選一次,它就更新一次自己。下面的數字是它「現在」寫的八段和「你開始選之前」比。

你一直選比較慢、比較安靜的那段,它就會慢下來。我用一個自動評審試過,設定和這張圖一模一樣:每次選「拖長的音比較多」的那段,選 20 次,拖長音從 48% 升到 64%;選 40 次變成 78%,和弦的種類掉了一半,開始只剩持續音。

它會找評審的漏洞

然後我讓自動評審改考平行五度:每次選犯得比較少的那段。選 40 次,平行五度從每百格 12.3 次只降到 10.9 次,幾乎沒動;拖長音倒是從 48% 升到 58%,和弦的種類少了四分之一。選到 80 次,平行五度降到 8.0,拖長音 63%、和弦種類從 45 掉到 29。

它確實把犯規壓下來了,但用的辦法是少動:不動的聲部不可能走出平行五度。

這叫 reward hacking,是訓練大型語言模型時最頭痛的問題之一:評審量的是一件事,模型最佳化的是「讓評審滿意」,兩者只要有一點縫,它就會找到。書上的修法有兩招:

  • 換一個鑽不了漏洞的評分。 改算「每次有聲部移動時,犯了幾次」,不動就拿不到好處。
  • 把繩子拉緊。 DPO 裡有一個 β,決定模型可以離原本的自己多遠。

在這張圖的力道下,這兩招只買到一點點:同樣選 80 次,防鑽的評審把平行五度壓到 7.0,可鑽的是 8.0,而兩者的拖長音都是 63%。它們都還是先學會少動。

差別要推得更用力才看得出來。我把更新改成累積四次一起做、學習率調成三倍:可鑽的評審把平行五度壓到 5.9,代價是拖長音衝到 73%、和弦種類只剩一半;防鑽的評審壓到 7.0,拖長音 52%、和弦種類 41,和原本差不多。越用力優化,鑽漏洞越划算,這正是大模型調教時的處境。上面那張圖故意留在溫和的力道,免得你點個二十下它就跑偏。

它贏得過五行數學嗎?

最後是一個不用任何 AI 的對手,五行就寫得完:五聲音階(C D E G A)上的一條 1/f 隨機旋律,底下墊著固定的 C–Am–F–G 四個和弦。

簡化自 content/posts/music-ai/components/music.ts
const scale = [60, 62, 64, 67, 69, 72, 74, 76, 79, 81];      // C 五聲音階
const chords = [[48, 55, 64], [45, 57, 64], [41, 53, 60], [43, 55, 62]];
for (let d = 0; d < 4; d++) if (t % (2 << d) === 0) dice[d] = rng(); // 四顆骰子
const soprano = scale[Math.floor(mean(dice) * scale.length)];       // 1/f 旋律
voices.push([soprano, ...chords[Math.floor(t / 8) % 4]]);           // 每小節換和弦

它永遠不會彈錯音,聲部也永遠不會交錯。

但它的平行五度是每百格 19.8 次,巴赫的一百多倍,和弦種類只有巴赫的一半。四個和弦一起平移,就是一連串的平行五度。

所以,聽得出來嗎?下面三段各四小節,一段是巴赫本人(模型沒看過的那 37 首裡的一段)、一段是練好 1000 步的 AI、一段是五行數學,順序每次都重新洗過。

fig 03/composer / blind

三段各四小節,一段是巴赫本人、一段是練好 1000 步的 AI、一段是五行數學規則,順序是隨機的。聽完再猜。

先聽完三段再猜。猜完按「對答案」,才會看到誰是誰,以及每一段的平行五度和和弦種類。鋼琴捲簾也是對完答案才出現:巴赫的譜和機器的譜長得太不一樣,先看到就沒得猜了。

對完答案,卡片下面那兩個數字會告訴你,三段的差別不只在聽感上。

資料和聲音

  • 資料是 Craig Sapp 整理的巴赫 370 首四部聖詠(開新分頁),授權是 CC BY-NC-SA 4.0;這一頁用到的樂譜資料和練好的模型,也以同樣的授權提供。每一首都移到 C 大調或 a 小調,切成八分音符的格子,333 首拿來訓練,37 首留著驗證。
  • 合成器是自己寫的,沒有用瀏覽器內建的樂器或效果:溫暖墊音是基音加一個輕輕的八度,各疊兩個相差 4 音分的音,慢慢起音;殘響照 Freeverb 的結構,尾音會越來越暗。第一版是五個泛音的風琴,我第一次聽就覺得太尖:1–4 kHz 比現在多了 6 到 16 dB。
  • 所有的「像不像巴赫」都是代理指標:在不在調上、聲部有沒有交錯、平行五度、拖長音的比例、和弦的種類。它們說得出一段音樂「守不守規矩」,說不出好不好聽。