L4.5 同一台機器要依指令做不同的事,指令從哪裡餵進去?
同一台機器,不同的指令
前幾篇介紹了怎麼處理內容,但同一張照片可以要求修亮,也可以要求變成夜景。只看照片本身,不知道該做哪一種。額外的指令要在哪裡進入網路? 我們把它記成條件 :
- 「把這張圖修成夜景」——條件是一個類別。
- 「照這段文字生成」——條件是一串 token。
- 「現在是流程的第 300 步,請做這一步該做的事」——條件是一個純量。
最後一種不同的是,因為它不是使用者給的指令,而是演算法自己的狀態。同一組權重要在很多個不同的階段各做一件不同的事,於是「現在是第幾步」必須被餵進去。
接法看起來很自由:接在輸入、接在中間某一層、或讓網路自己去查。但這幾種接法不是同一件事的幾種寫法——它們對不同形狀的條件有非常不同的成本。
指令要從哪裡餵進去?
接在輸入的一個維度上就好了嗎?
如果那個指令是一個純量,會不會特別吃虧?
課堂提問Q1
把「依指令做不同的事」翻成數學:條件模型和無條件模型差在哪裡?把一個純量條件接成輸入的第二個維度,網路必須自己長出什麼東西——那件事對它來說容易嗎?
先想一想,再展開看整理後的答案
先固定學習目標。 若 label 有有限二階矩、使用 L2 regression,理想條件模型學的是
多了一個條件,把輸入分得更細。條件變異數取期望後不會增大,但某一個特定桶子仍可能比原本更分散;有限模型與資料也不保證誤差一定下降。
接成輸入維度之後,網路要自己長出什麼。 若 對 的依賴是高頻的——例如流程的第 3 步和第 4 步該做的事差很多——那麼把 當成一個普通的輸入座標,就是要求網路在那個座標上表現出高頻的變化。
而 什麼都能擬合,那為什麼還需要別的架構? 的頻率實驗量過這件事:同一個 的網路,目標從 1 個週期換到 32 個週期,訓練 MSE 從 變成 。MLP 對高頻很不友善,而這個不友善不分輸入座標—— 這一維吃虧, 這一維一樣吃虧。
兩條出路,方向不同。
- 把頻率直接給它:不要接 ,接 這一組不同頻率的特徵。網路要高頻時,它已經在輸入裡了,只需要線性組合。
- 不要讓 走同一條路:讓它去改變每一層的行為(尺度與偏移),而不是當成一個和 平起平坐的座標。
本篇會把第一條量出來(嵌入比加寬便宜也有效),並說清楚第二條在什麼形狀的條件上才划算。
三種注入方式,三種「改變什麼」
把接法按照「它改變了網路的哪一部分」排開:
- concat(接在輸入):。最簡單,而且在條件和輸入是同一種東西時很自然(例如都是影像的像素)。缺點是條件的影響必須一路經過所有層才擴散開,而且它和 共用同一條路。
- FiLM(每一層的尺度與偏移):由 算出一組 ,在第 層做 。條件不再是一個座標,而是直接調整每一層的行為。這對「全域性、影響整張圖」的條件特別合適——類別、時間步、風格。
- cross-attention:由目前特徵提供 query,條件 token 提供 key 與 value,讓不同位置參考不同的條件部分。其他接法也能配合編碼器處理變長輸入,但 cross-attention 提供了直接的內容配對方式。
三者不互斥,實務上常常同時出現(時間用 FiLM、文字用 cross-attention、低階的輔助輸入用 concat)。挑的依據是條件的形狀:
| 條件長什麼樣 | 適合的注入方式 |
|---|---|
| 一個純量(時間、強度) | 嵌入 → FiLM(或 concat 嵌入) |
| 一個類別(有限選項) | 查一個 embedding 表 → FiLM |
| 一張同尺寸的圖(遮罩、邊緣圖) | concat 在通道上 |
| 一串長度可變的 token | cross-attention |
圖說: 三種接法改變的運算不同;時間嵌入則是提供純量條件的一種表示選擇。
為什麼純量條件要先做嵌入
正弦嵌入把一個純量 換成一組不同頻率的三角函數:
它在做的事可以用一句話說清楚:把「網路要自己長出高頻」換成「高頻已經在輸入裡,只需要把它們線性組合起來」。
例如需要 時,若這個頻率已在輸入裡,後面的線性層便能直接選用,不必先從原始純量形成這個振盪。這是 Tancik 等人 [2] 研究 Fourier features 的動機之一;不代表任意網路的第一層權重都必須是 。
還有一個要檢查的限制:這裡全是整數頻率,所以 。若兩端需要不同答案,應另保留 、加入非整數頻率或使用其他能區分端點的嵌入,不能直接照搬這組示範頻率。
這個幾何級數也不是隨便挑的:它讓不同尺度的變化都被覆蓋到,而且只要 個維度就涵蓋 倍的頻率範圍。
補充這和 Transformer 的位置編碼是同一個東西
Transformer 的位置編碼用的是同一條式子( 配上幾何級數的頻率),解決的也是同一個問題:位置是一個純量,而網路需要對它有多尺度的敏感度。差別只在那裡的純量是「第幾個 token」,這裡是「第幾步」或「條件的強度」。
同一個技巧在座標型網路(用網路表示一張圖或一個 3D 場景)上叫 Fourier features(參考文獻 2),那篇論文把「為什麼沒有嵌入就學不到高頻」用 neural tangent kernel 講清楚了:沒有嵌入時,網路的等效核對高頻成分的響應以指數衰減,於是那些成分在任何合理的訓練時間內都學不到。
三個名字、三個領域、同一件事——可以把它記成一個通用的手法:當一個純量需要高頻的影響力時,先把它展開成多個頻率。
三種接法在同一個任務上
任務刻意設計成「對條件的依賴是高頻的」:
對 的依賴是 1 個週期(很容易),對 的依賴是 8 個週期(照 什麼都能擬合,那為什麼還需要別的架構? 的頻率表,這是要花點力氣的區域)。三個設定跑同樣的 6000 步、同樣的 Adam :
concat 純量 t 輸入維度 2 h= 64 訓練 MSE 0.0018
concat 正弦嵌入 t 輸入維度 13 h= 64 訓練 MSE 0.0004
concat 純量 t(寬兩倍) 輸入維度 2 h=128 訓練 MSE 0.0010
嵌入把誤差降到四分之一(),而它只多了 11 個輸入維度。 對照組更有說服力:把網路加寬兩倍(參數變成約四倍)只從 改善到 ——四倍的參數買到的,還不如 11 個不需要學的輸入維度。
固定嵌入不需要學自己的頻率,但它仍改變輸入表示、後續參數數量與可表示的函數。改善來自哪裡,需用對照實驗確認。
這也解釋了為什麼幾乎每一個需要「時間步」的模型都有一個正弦嵌入層,而且那一層通常沒有參數:它不是模型的一部分,是輸入的一種座標選擇——和 霧中下山,一步該走多大:梯度下降的一頁 裡「標準化改的是碗的形狀」是同一類的動作。
「沒有條件」也必須被訓練過
條件模型有一個很容易被忽略的需求:有時候你要它不要依照條件做事。
- 想知道模型在「什麼都不指定」時的預設行為。
- 想比較「有條件」與「無條件」的輸出差在哪裡(很多引導式的取樣做法都需要這兩個)。
- 使用者就是沒有給條件。
直覺的做法是留一個 null token:一個代表「沒有條件」的特殊輸入(例如把 one-hot 全部設成零)。問題是——如果訓練時條件永遠都在,那個 null token 從來沒有出現在訓練資料裡。
任務是 , 與 獨立且兩類等機率。L2 的無條件最佳答案因此是 。訓練時以獨立機率 將條件換成 null,才能讓 null 分支看到這個邊際化的目標;一般情況要按 平均,不一定是各類一半。
def feats(x, c, mask): # mask=0 表示這一筆的條件被丟掉
oh = np.zeros((len(x), 2)); oh[np.arange(len(x)), c] = 1.0
return np.c_[x, oh*mask[:,None]]
mask = (rng.random(N) > p).astype(float) # p 是條件 dropout 的機率
條件 dropout p=0.0 用 null token 預測「兩類平均」的 MSE 中位數 1.3908
條件 dropout p=0.1 用 null token 預測「兩類平均」的 MSE 中位數 0.0660
條件 dropout p=0.3 用 null token 預測「兩類平均」的 MSE 中位數 0.0225
(對照:直接輸出 0 的 MSE = 0.6575)
這次 的 null 表現很差,因為訓練目標沒有約束這個輸入的答案。函數仍有定義,只是沒有保證它等於兩類平均;其他初始化或模型不一定同樣差。
只要 的條件 dropout,誤差就掉到 ——二十一倍。 再降到 ,但代價是三成的訓練樣本沒有用到條件資訊,條件本身的品質會開始下降。實務上 左右是常見的折衷。
「沒有條件」不是一個預設狀態,它是一個要被訓練的輸入。
刻意違反:把 null token 換成一個「沒用過的」向量。 如果不是用全零,而是隨便挑一個訓練時沒出現過的向量(例如 one-hot 的第三格),結果和 那一列一樣糟——問題不在「用哪個向量代表沒有條件」,而在「那個向量有沒有被訓練過」。 這也是為什麼實務上一律用「訓練時真的餵過的那個」當 null,而不是任何看起來比較中性的東西。
這一切依賴什麼。 一,上面的數字是在一個純量/類別條件、小網路上量的;條件是長序列時 dropout 的做法不同(丟整串、還是丟其中幾個 token,會影響模型學到的東西)。二, 是一個要調的超參數,而它同時影響「無條件有多準」與「有條件有多準」——兩者用同一組權重。三,這裡量的是「無條件輸出對不對」,不是「有條件輸出有沒有變差」;完整的評估要兩個都看。
三種接法、一個頻率設定、一個 dropout 設定
互動 demo:把條件頻率 k 拉大,「純量」那條訓練曲線整條抬高而「嵌入」那條幾乎不動。
檢查理解
參考文獻
- Perez, E. et al. FiLM: Visual Reasoning with a General Conditioning Layer. AAAI 2018.(把「條件改變每一層的尺度與偏移」抽象成一個通用層,並比較它與 concat 的差別。)
- Tancik, M. et al. Fourier Features Let Networks Learn High Frequency Functions in Low Dimensional Domains. NeurIPS 2020.(用 NTK 說明沒有嵌入時高頻為什麼學不到——本篇 Remark 的來源。)
- Ho, J., Salimans, T. Classifier-Free Diffusion Guidance. 2022.(條件 dropout 與 null token 的標準做法;本篇最後一段實驗的實務對應。)