網(wǎng)絡(luò)生成MIDI旋律的原理與訓(xùn)練全流程)
我在整理自己的 MIDI 素材庫時經(jīng)常會冒出同一個念頭如果神經(jīng)網(wǎng)絡(luò)能接住我寫到一半的旋律順著音樂情緒往下生成幾小節(jié)那該多省事。真正讓我確認(rèn)這件事靠譜的是谷歌 Magenta 項目。Magenta 是谷歌研究團(tuán)隊主導(dǎo)的開放研究計劃目標(biāo)是讓機(jī)器學(xué)習(xí)模型參與藝術(shù)創(chuàng)作而它在音樂領(lǐng)域最出圈的方向就是用神經(jīng)網(wǎng)絡(luò)寫 MIDI 旋律。這篇文章我想一次性把 Magenta 的核心思路、模型原理和完整實操流程講透適合兩類人看一是剛接觸人工智能音樂生成、想搞清楚“它到底是真會寫歌還是瞎編”的人二是手里有一堆 MIDI 素材、想訓(xùn)練一個專屬風(fēng)格模型并接入自己工作流的音樂人。Magenta 好玩歸好玩但很多人第一次上手就卡在概念上因為它不是一個單獨(dú)的軟件而是一整套模型工具鏈。我接下來說的東西會從“為什么偏偏用 MIDI 做神經(jīng)網(wǎng)絡(luò)的輸入”開始再到模型怎么拆、訓(xùn)練怎么跑、實際生成怎么調(diào)最后把我踩過的坑全部列出來。你把這篇文章當(dāng)成一份從零開始的 Magenta 實操備注應(yīng)該比翻官方文檔舒服得多。1. 先搞清楚 Magenta 在解決什么問題1.1 為什么偏要用 MIDI而不是直接吃音頻Magenta 最早吸引我的地方是它做了很多在別人看起來“繞遠(yuǎn)了”的決策。最典型的就是輸入表示它不讓神經(jīng)網(wǎng)絡(luò)直接“聽”音頻波形而是讓模型讀 MIDI 事件。我一開始也不理解后來自己做了一次實驗才明白MIDI 不是妥協(xié)而是聰明地降低了問題難度。音頻是連續(xù)的原始采樣點(diǎn)一秒鐘幾萬個數(shù)值還疊加了音色、混響、房間聲學(xué)各種信息。如果讓模型直接學(xué)音頻它得同時學(xué)會兩件事一件事是“該演奏什么音”另一件事是“怎么發(fā)出這個音的聲音”。對旋律創(chuàng)作來說第二個問題其實可以往后放MIDI 恰好把這兩件事拆開了。MIDI 記錄的是離散事件哪個音高、什么時候開始、什么時候結(jié)束、力度是多大。一串 MIDI 事件就是一部濃縮的樂譜不包含“音色好不好聽”的負(fù)擔(dān)。對神經(jīng)網(wǎng)絡(luò)來說這個輸入格式變成了一道更純粹的序列預(yù)測題給你前面一堆音符預(yù)測下一個音符是什么。如果你玩過 DAW可以這樣理解MIDI 是一張寫好的樂譜神經(jīng)網(wǎng)絡(luò)只需要學(xué)會讀譜和續(xù)寫而音頻是錄音棚里的干聲模型還得自己琢磨怎么用嘴唇、氣流和麥克風(fēng)位置任務(wù)就復(fù)雜太多了。Magenta 先把“寫音符”這個創(chuàng)作環(huán)節(jié)單獨(dú)拎出來做成模型音色交給合成器去解決這是很務(wù)實的路線。教程里還有個細(xì)節(jié)非常關(guān)鍵MIDI 事件必須做時間離散化。不能像音頻那樣自然連續(xù)地流動得把時間軸切成固定的步長比如每個 16 分音符作為一個時間步。在這個時間步內(nèi)模型看到的是“有音符開始”“有音符結(jié)束”“有音符保持”“什么都不發(fā)生”等事件。這一步處理直接影響訓(xùn)練效率和生成質(zhì)量后面實操部分我會再展開。1.2 它不是單個模型而是一整套工具箱很多剛接觸 AI 音樂的人會有個誤解覺得“Magenta”就是某個能寫歌的通用 AI。真實情況是Magenta 更像一個持續(xù)擴(kuò)展的模型家族。截至我長期使用的版本它按創(chuàng)作任務(wù)拆成了幾個核心成員MelodyRNN續(xù)寫單旋律是入門最友好的模型也是理解 Magenta 整個思路的鑰匙。Performance RNN生成帶有真人演奏表情的 MIDI 表演能把時值偏移、力度起伏這些“人類感”也學(xué)出來。MusicVAE用一個低維隱空間來理解旋律支持在兩端旋律之間插值生成漸變過渡的樂句。GrooveVAE專注鼓點(diǎn)節(jié)奏生成能把“groove”搖擺感和“機(jī)械化節(jié)拍”區(qū)分開。我第一次完整跑通的是 MelodyRNN。它的任務(wù)定義特別明確輸入一段旋律輸出一段旋律。你給它幾十首巴赫眾贊歌的 MIDI它能學(xué)著按巴赫的習(xí)慣續(xù)寫你給它一堆爵士標(biāo)準(zhǔn)曲它會往即興的方向生成。它不會混音、不會編曲、不會自動配器只解決“下一個音符是什么”這個核心命題但恰恰是這個命題撐起了整個“AI 寫旋律”的想象力。如果你是想做音樂創(chuàng)作的我建議先別急著把整個工具箱都上了。你只需要問自己一個問題我到底需要 AI 幫我做哪件事如果是“我有一段開頭需要自動續(xù)寫”選 MelodyRNN如果是“我有一堆 midi 片段想隨時提取音樂動機(jī)”選 MusicVAE如果是“我打了一段鼓想讓 AI 補(bǔ)出更有律動的過門”選 GrooveVAE。工具越多越容易迷失先從一個模型跑通再橫向拓展是最低成本的路徑。2. 核心模型拆解神經(jīng)網(wǎng)絡(luò)如何學(xué)會“看著前文寫下文”2.1 從 RNN 到 LSTM序列預(yù)測這件事為什么天然適合音樂要理解 Magenta 寫旋律的原理繞不開循環(huán)神經(jīng)網(wǎng)絡(luò) RNN。你別被“循環(huán)”兩個字嚇到我用一個生活類比說清楚。想象一個讀者在讀一首詩他每讀一個字都會在腦海里留下一個只有自己知道的“筆記”讀下一個字時他結(jié)合眼前的字和之前的筆記推出接下來最可能出現(xiàn)的字。RNN 就是那個讀者每一步輸入既包含當(dāng)前音符也包含來自上一步的隱藏狀態(tài)。隱藏狀態(tài)就是那個“筆記”它會隨時間不斷更新把已經(jīng)出現(xiàn)過的重要信息一路帶下去。但普通 RNN 有個天生毛病如果一首歌里前面第八小節(jié)出現(xiàn)過某個動機(jī)到第三十小節(jié)需要呼應(yīng)它時那個信息早被后面幾十個音符沖散了。為了解決這種“長距離依賴”Magenta 的模型普遍采用 LSTM也就是長短期記憶網(wǎng)絡(luò)。LSTM 給每個記憶單元配備了三個門輸入門決定新信息要不要寫進(jìn)筆記遺忘門決定舊信息要不要扔掉輸出門控制這份筆記對外的影響程度。旋律中的調(diào)式回歸、主題重現(xiàn)、樂句反復(fù)本質(zhì)上都是長距離結(jié)構(gòu)LSTM 處理起來比普通 RNN 穩(wěn)得多。訓(xùn)練的時候還有一個關(guān)鍵機(jī)制叫教師強(qiáng)制。意思是訓(xùn)練階段每一步都喂給模型“正確答案”的下一個音符讓它專注于學(xué)習(xí)“在當(dāng)前語境下正常音樂應(yīng)該接什么”而不是被自己上一輪的爛預(yù)測帶偏。等訓(xùn)練完成、進(jìn)入真正生成階段時模型就失去了這份照顧只能把上一輪自己采樣的結(jié)果作為下一輪輸入像一場沒有教師批改的連續(xù)寫作考試。這個過程解釋了為什么訓(xùn)練好的模型在生成時偶爾會“跑偏”因為誤差會一步接一步累積。2.2 三種 MelodyRNN 配置是怎么取舍的MelodyRNN 里藏著三個預(yù)設(shè)配置名字分別叫 basic_rnn、lookback_rnn 和 attention_rnn。我當(dāng)時為了搞清楚它們到底差在哪分別用同一批數(shù)據(jù)做了對比實驗結(jié)論比較直觀。basic_rnn 是最樸素的 LSTM 方案。每個時間步只接收當(dāng)前事件能不能記住前面的內(nèi)容全憑隱藏狀態(tài)自己“死記”。它對短旋律沒問題處理超過幾十步的長旋律就會吃力。lookback_rnn 多留了一個心眼每次不光是看當(dāng)前音符還把“這個音符之前是不是出現(xiàn)過”“上一個音符是什么”“下一個音符是什么”這些額外的二元特征拼進(jìn)輸入里。這樣模型不需要全靠隱藏狀態(tài)去猜結(jié)構(gòu)而是能顯式地感知到樂句的重復(fù)和變化。如果你想生成有明確呼應(yīng)感的旋律lookback_rnn 比 basic_rnn 直覺上好用很多。attention_rnn 則是把注意力機(jī)制加進(jìn)來。每一步解碼時模型可以回頭“掃一眼”輸入序列里的所有歷史狀態(tài)自己決定最該關(guān)注哪一段。這個機(jī)制效果最穩(wěn)我跑過巴赫眾贊歌的續(xù)寫實驗attention_rnn 生成的結(jié)果在調(diào)式銜接和終止式處理上明顯比前兩種更合理。代價是訓(xùn)練更慢、顯存占用更高。你如果只是小規(guī)模試水直接選 attention_rnn 當(dāng)默認(rèn)配置就行。2.3 MusicVAE在音樂和音樂之間搭一座橋MelodyRNN 解決了“續(xù)寫”但沒法回答一個更高級的問題能不能找到不同風(fēng)格之間的中間地帶MusicVAE 就是為這件事設(shè)計的。MusicVAE 屬于變分自編碼器。它由一個編碼器和一個解碼器組成編碼器把一段旋律壓成一個低維的向量 z解碼器再從 z 還原出旋律。訓(xùn)練完成后這個 z 向量就是一段旋律在隱空間里的“坐標(biāo)”。重點(diǎn)在于因為訓(xùn)練時約束了這個坐標(biāo)服從一個標(biāo)準(zhǔn)正態(tài)分布所以坐標(biāo)空間是連續(xù)且規(guī)整的。你可以直接把“巴赫風(fēng)格旋律”的坐標(biāo)和“爵士風(fēng)格旋律”的坐標(biāo)連接起來在中間均勻取幾個點(diǎn)解碼器就會生成一串從一端過渡到另一端的旋律。我第一次看到 MusicVAE 插值結(jié)果時的感受非常強(qiáng)烈AI 不是在兩張照片之間做模糊混合而是在“音樂感覺”之間做漸變。你會聽到旋律先保留巴洛克式的嚴(yán)謹(jǐn)對位然后慢慢出現(xiàn)延伸音和九和弦最后滑向爵士化的搖擺句法。這種能力對編曲找靈感特別實用尤其是你寫歌寫到瓶頸時想把兩種風(fēng)格硬接在一起卻總接不順MusicVAE 能給你一個更平滑的中間選項。訓(xùn)練 MusicVAE 時有個經(jīng)典的拉扯關(guān)系重建損失希望生成的旋律盡量還原輸入KL 散度損失則希望隱空間不要“記住每首旋律的原樣坐標(biāo)”。這兩股力如果失衡要么隱空間變成一潭死水要么模型變成單純的復(fù)讀機(jī)。理解這個平衡對你判斷一個生成結(jié)果為什么“怪”很有幫助。3. 實操復(fù)盤用 Magenta 跑通一次自定義風(fēng)格訓(xùn)練3.1 環(huán)境準(zhǔn)備最穩(wěn)的方案是 Docker最輕的方案是 ColabMagenta 的依賴棧比較老我個人的血淚教訓(xùn)是不要在一臺干凈的 macOS 新機(jī)器上直接一行 pip install 就開始幻想生成巴赫。Magenta 早期版本基于 TensorFlow 1.x和現(xiàn)在的 Python 版本、TF2 框架存在不少兼容摩擦。如果只想快速復(fù)現(xiàn)我建議直接用官方提供的 Docker 鏡像。docker pull gcr.io/magenta-tensorflow/magenta docker run -it -v /your/local/midi:/magenta_data gcr.io/magenta-tensorflow/magenta bash這個命令會把本地的 midi 文件夾掛載到容器里的 /magenta_data之后所有訓(xùn)練、生成命令都在容器內(nèi)部執(zhí)行。我推薦 Docker 的核心原因只有一個隔離環(huán)境省掉“為什么我裝完依賴就崩”這類玄學(xué)問題。如果你機(jī)器上沒有 Docker也可以用 Colab把項目克隆到云端直接跑。Colab 的好處是免費(fèi) GPU壞處是依賴安裝第一次也要踩一遍不如 Docker 鏡像“開箱即用”。進(jìn)到容器后可以先驗證環(huán)境python -c import magenta; print(magenta.__file__)正常情況下會輸出模塊路徑說明安裝成功。要是這條命令報錯說明鏡像版本有問題換個 tag 再拉一次。3.2 準(zhǔn)備訓(xùn)練集MIDI 清洗比想象中更重要訓(xùn)練模型最容易被低估的環(huán)節(jié)是數(shù)據(jù)清洗。我是怎么做的呢先從合法渠道準(zhǔn)備了一百多首同一風(fēng)格的 MIDI 文件放進(jìn)一個 input 目錄其中大部分是單旋律軌或者經(jīng)過簡單處理只保留主旋律軌。MIDI 如果過于雜亂和弦軌和旋律軌重疊在一起模型會把“同時響一堆音”也當(dāng)成正常語法去學(xué)生成的旋律會偏離單聲部預(yù)期。接下來要生成訓(xùn)練用的 TFRecord 文件。MelodyRNN 提供了一套現(xiàn)成腳本核心命令大致是melody_rnn_create_dataset \ --configattention_rnn \ --input./midi_input \ --output_dir./training_data \ --logINFO這個腳本會掃描目錄下的 MIDI做抽取旋律、量化時值、統(tǒng)一音域、按比例劃分訓(xùn)練集和評估集等一系列操作。輸出目錄里會得到帶 train/eval/test 標(biāo)識的 TFRecord 文件。如果你關(guān)心數(shù)據(jù)處理細(xì)節(jié)腳本還會把每條樣本的轉(zhuǎn)調(diào)增強(qiáng)打開把同一段旋律平移幾個半音生成額外樣本這樣模型學(xué)到的更多是“調(diào)式關(guān)系”而不是死記某個調(diào)。有一點(diǎn)需要提前做好思想準(zhǔn)備數(shù)據(jù)量決定了你的預(yù)期。我試過用二十首 MIDI 訓(xùn)練模型生成幾輪之后就會開始重抄素材用兩百首以上風(fēng)格高度一致的 MIDI模型才真正產(chǎn)生“再創(chuàng)造”的感覺。AI 訓(xùn)練不是“給一首歌就能仿寫”而是“給一百首才能歸納”。3.3 訓(xùn)練模型跑起來很簡單盯住 loss 才有意義數(shù)據(jù)準(zhǔn)備好后訓(xùn)練命令比我想象中簡單很多。我用的是 attention_rnn 配置命令大概長這樣melody_rnn_train \ --configattention_rnn \ --run_dir./runs/attention_run \ --sequence_example_file./training_data/training_melodies.tfrecord \ --hparams{batch_size:64,rnn_layer_sizes:[64,64],learning_rate:0.01} \ --num_training_steps10000參數(shù)解釋一下run_dir 保存 checkpoint方便中斷后繼續(xù)訓(xùn)練sequence_example_file 指向上一步生成的 TFRecordhparams 里的 JSON 字符串控制批大小、層數(shù)和學(xué)習(xí)率。如果你是第一次跑我建議把 rnn_layer_sizes 保持默認(rèn)只調(diào) batch_size。batch_size 太小容易讓 loss 震蕩太大會把顯存吃滿64 是一個常見起點(diǎn)。訓(xùn)練過程中建議邊跑邊開 TensorBoardtensorboard --logdir./runs盯住訓(xùn)練 loss 的走勢通常前幾百步會快速下降然后進(jìn)入更平緩的優(yōu)化階段。我習(xí)慣在訓(xùn)練后期對比訓(xùn)練集和驗證集的 loss 曲線如果訓(xùn)練 loss 一直降、驗證 loss 卻開始反彈說明模型在背數(shù)據(jù)得考慮提前停止或增加數(shù)據(jù)量。3.4 生成旋律溫度參數(shù)和 primer 才是真正的手感所在訓(xùn)練結(jié)束并不是終點(diǎn)生成階段才是真正好玩的地方。Magenta 要求先導(dǎo)出 bundle 文件再運(yùn)行生成腳本melody_rnn_generate \ --configattention_rnn \ --run_dir./runs/attention_run \ --bundle_dir./bundles \ --bundle_fileattention_bundle.mag \ --num_outputs10 \ --num_steps128 \ --primer_melody[60, 64, 67, 72] \ --temperature1.0這里的primer_melody是你給模型提供的“開頭”可以是 C 大調(diào)上行四個音也可以是你自己寫的最前面幾個音符。num_steps128是指生成多少時間步按 16 分音符粒度算128 步大概就是一個小節(jié)左右的量。temperature是采樣溫度它控制生成的隨機(jī)程度。關(guān)于 temperature 的調(diào)法我實際操作后的經(jīng)驗是temperature 越接近 0生成結(jié)果越保守幾乎每個音符都是概率最高的那個旋律很容易變成平庸的重復(fù)temperature 越大越容易出現(xiàn)跳躍音和失控跑調(diào)。我一般從 1.0 起步如果結(jié)果太亂就調(diào)到 0.8如果太呆板就升到 1.2。生成十首候選 MIDI然后用 DAW 或支持 MIDI 播放的工具挨個聽比盯著音符列表做判斷可靠得多。4. 我踩過的坑數(shù)據(jù)、訓(xùn)練、生成環(huán)節(jié)全記錄4.1 訓(xùn)練數(shù)據(jù)常見的坑先說一個最典型的坑MIDI 文件里多軌混著鼓、貝斯、和弦、主旋律你不做任何處理直接丟給訓(xùn)練腳本生成的“旋律”會很亂。因為訓(xùn)練腳本會嘗試提取旋律軌但不同 MIDI 的軌命名和音域差異很大提取結(jié)果經(jīng)常不完整。我后來給自己定了一條鐵律訓(xùn)練數(shù)據(jù)必須自己先把主旋律軌單獨(dú)導(dǎo)出成獨(dú)立的單軌 MIDI哪怕多花一點(diǎn)時間也不要把清洗工作完全交給腳本。第二個坑是時值量化。MIDI 采樣時值長短不一有些 MIDI 里有一堆三十二分音符、附點(diǎn)、連音如果 Magenta 的量化步長不夠匹配數(shù)據(jù)會被強(qiáng)行切得非常碎模型學(xué)到的音符連續(xù)性很差。我通常會先看數(shù)據(jù)集的音符長度直方圖如果大量音符短于一個量化單位先手動改 MIDI 或換一個量化分辨率。第三個坑跟音域有關(guān)。Magenta 的旋律模型對音高范圍有限制特別高或特別低的音符可能被直接過濾掉。如果你的風(fēng)格樂段很喜歡用低音薩克斯區(qū)的音色或者高音區(qū)的小提琴旋律得留意這些被過濾之后數(shù)據(jù)集是不是還“夠味”。4.2 訓(xùn)練階段最容易讓人心態(tài)崩的時刻我剛跑訓(xùn)練時最容易遇到的困境是 loss 降了但生成出來全是“四不像”。排查了幾次我發(fā)現(xiàn)問題往往出在模型容量和數(shù)據(jù)量不匹配上。數(shù)據(jù)量只有幾十首模型層數(shù)開得很大訓(xùn)練速度極慢結(jié)果還沒到收斂就開始過擬合。此時最好的操作不是繼續(xù)加層而是降模型規(guī)模、加數(shù)據(jù)、控制訓(xùn)練步數(shù)。還有一個細(xì)節(jié)是“檢查點(diǎn)恢復(fù)”。訓(xùn)練到一半中斷重新跑訓(xùn)練命令時正常情況下能從 run_dir 自動加載 checkpoint 繼續(xù)但如果 run_dir 路徑寫錯了模型會從頭再來你前一天跑的十幾個小時全白費(fèi)。我建議每次訓(xùn)練前把 run_dir 先備份一下或者養(yǎng)成看日志里有沒有 “Restoring parameters from ...” 這類關(guān)鍵提示的習(xí)慣。關(guān)于 GPU 和 CPU也順帶提醒一句MelodyRNN 這種規(guī)模的小模型在 CPU 上也能跑但速度和 GPU 差距極大。如果你只有普通筆記本建議縮小數(shù)據(jù)量、縮短訓(xùn)練步數(shù)先驗證流程能通再去花錢上云 GPU。不用一開始就追求完整訓(xùn)練到最優(yōu)。4.3 生成結(jié)果不理想時的調(diào)優(yōu)順序如果你生成出來的旋律總是“前言不搭后語”先別急著換模型。我總結(jié)了一套調(diào)優(yōu)順序第一改 temperature。很多人默認(rèn)用 1.0但不同數(shù)據(jù)集的最優(yōu)點(diǎn)位差很多。風(fēng)格比較規(guī)矩的古典作品溫度可以低到 0.8爵士即興可以把溫度放到 1.2 甚至更高。第二換 primer。primer 的引導(dǎo)作用非常大我可以負(fù)責(zé)任地說生成結(jié)果一半的“樂感”來自 primer 的質(zhì)量。你的開頭如果本身就很模棱兩可模型后面大概率也會飄。先寫一個樂句感明確的前奏再讓模型續(xù)寫結(jié)果會穩(wěn)很多。第三重新檢查數(shù)據(jù)集是否“風(fēng)格純度”不夠。我早期把古典和流行 MIDI 混在一起訓(xùn)練結(jié)果生成的作品像兩個風(fēng)格在打架。后來按風(fēng)格分目錄訓(xùn)練效果立刻提升。Magenta 不是不能學(xué)多種風(fēng)格但它更像一個沉浸式學(xué)習(xí)者你同時教它巴赫和爵士它很容易把兩種語法揉成一團(tuán)。生成后的“人類修整”也很重要。我一般只在 AI 生成結(jié)果的歷史中截取一小段好聽的樂句甚至只保留一個動機(jī)然后再用 DAW 手工發(fā)展下去。AI 是靈感放大器不是成品輸出機(jī)這個定位能讓你少很多失望。4.4 算力與復(fù)現(xiàn)性的一些心里話Magenta 項目本身已經(jīng)存在多年官方代碼的迭代節(jié)奏和新一代生成模型沒法比這也導(dǎo)致網(wǎng)上不少教程早就失效。我的學(xué)習(xí)建議是不要試圖在當(dāng)前最新的深度學(xué)習(xí)框架里去“從零復(fù)現(xiàn)整個 Magenta”而是接受它的舊依賴用 Docker 或 Colab 直接跑官方鏡像。復(fù)現(xiàn)性遠(yuǎn)比“框架最新”重要因為你真正要研究的是音樂生成的原理和手感不是環(huán)境搭建技術(shù)。如果你未來想更進(jìn)一步Magenta 還提供了 Magenta.js可以在瀏覽器里跑一些輕量音樂模型也能接入 TensorFlow.js 生態(tài)。不過在瀏覽器里訓(xùn)練大型模型依然受限于算力我更推薦把它當(dāng)成一個“AI 樂器”來玩而不是當(dāng)成完整的訓(xùn)練平臺。我自己現(xiàn)在使用 Magenta 的固定工作流已經(jīng)穩(wěn)定運(yùn)行了很長一段時間用 MusicVAE 生成風(fēng)格過渡的旋律片段用 MelodyRNN 續(xù)寫歌曲副歌最后全部導(dǎo)入 DAW 做人工篩選和二次修改。整個過程不需要我懂復(fù)雜的深度學(xué)習(xí)數(shù)學(xué)但每一步都建立在理解“序列預(yù)測、隱空間、采樣溫度”這些核心概念之上。最讓我感慨的是當(dāng)你在 DAW 里聽到神經(jīng)網(wǎng)絡(luò)順著你的思路延展出一個意想不到但又合乎邏輯的轉(zhuǎn)折時那感覺真不是普通隨機(jī)生成器能替代的。如果你現(xiàn)在正想嘗試我建議你就從一段自己最喜歡風(fēng)格的 MIDI 語料開始跑通一次訓(xùn)練、生成、修整的閉環(huán)你會比任何教程都更理解“AI 寫旋律”這件事的邊界。