習(xí):大規(guī)模圖自監(jiān)督預(yù)訓(xùn)練的新范式與復(fù)現(xiàn)指南)
1. 從整圖訓(xùn)練到子圖對比這篇論文到底在解決什么痛點(diǎn)圖神經(jīng)網(wǎng)絡(luò)這幾年火得一塌糊涂但真正上手做過大規(guī)模圖數(shù)據(jù)的人都知道痛點(diǎn)非常集中圖太大了大到單卡根本放不下整張圖的鄰接矩陣和節(jié)點(diǎn)特征。工業(yè)界常見的社交網(wǎng)絡(luò)、電商用戶行為圖、金融交易網(wǎng)絡(luò)動(dòng)輒上億節(jié)點(diǎn)、幾十億條邊你不可能把整張圖一次性喂進(jìn)顯存里做前向傳播。更麻煩的是很多場景下標(biāo)簽極其稀缺——你有一堆節(jié)點(diǎn)但標(biāo)注成本高得離譜監(jiān)督學(xué)習(xí)根本跑不起來。這篇論文瞄準(zhǔn)的就是這兩個(gè)死結(jié)可擴(kuò)展性scalable和自監(jiān)督self-supervised。它的核心思路一句話概括不再對整張圖做對比學(xué)習(xí)而是采樣出中心節(jié)點(diǎn)周圍的子圖在子圖內(nèi)部做對比。這個(gè)思路聽起來簡單但它解決了一個(gè)非常關(guān)鍵的問題——對比學(xué)習(xí)需要構(gòu)造正負(fù)樣本對如果每次都要在整圖上做計(jì)算量隨圖規(guī)模爆炸式增長而子圖對比把計(jì)算范圍限制在局部復(fù)雜度直接降下來了。我第一次讀到這個(gè)思路的時(shí)候第一反應(yīng)是這不就是把局部感受野的思想搬到對比學(xué)習(xí)上嗎。確實(shí)如此但它做得更徹底子圖本身就是對比的基本單位。中心節(jié)點(diǎn)和它的鄰居構(gòu)成一個(gè)子圖子圖經(jīng)過圖神經(jīng)網(wǎng)絡(luò)編碼后得到表示然后通過最大化子圖表示與中心節(jié)點(diǎn)表示之間的一致性來訓(xùn)練。整個(gè)過程不需要任何人工標(biāo)簽完全靠圖自身的結(jié)構(gòu)信息構(gòu)造監(jiān)督信號。適合誰來讀這篇內(nèi)容如果你正在做以下事情這篇論文值得你花時(shí)間一是手頭有大規(guī)模圖數(shù)據(jù)但苦于顯存不夠二是標(biāo)注數(shù)據(jù)太少想用自監(jiān)督預(yù)訓(xùn)練三是想理解圖對比學(xué)習(xí)從整圖范式到子圖范式的演進(jìn)邏輯。我會(huì)把論文的核心機(jī)制、關(guān)鍵設(shè)計(jì)選擇、以及我自己復(fù)現(xiàn)時(shí)踩過的坑都攤開講清楚。2. 子圖對比學(xué)習(xí)的核心機(jī)制拆解2.1 為什么整圖對比在大規(guī)模場景下走不通要理解這篇論文的價(jià)值得先搞清楚它反對的是什么。早期的圖對比學(xué)習(xí)方法比如經(jīng)典的 DGIDeep Graph Infomax和 GraphCL基本都是在整圖級別做對比。DGI 的做法是用真實(shí)圖編碼得到節(jié)點(diǎn)表示再用打亂特征的方式生成一個(gè)假圖然后訓(xùn)練模型去區(qū)分真實(shí)節(jié)點(diǎn)表示和假圖節(jié)點(diǎn)表示。GraphCL 則是對整圖做不同的增強(qiáng)加邊、刪邊、掩碼特征然后拉近同一圖的不同增強(qiáng)視圖。這些方法在小圖上效果不錯(cuò)但一旦圖規(guī)模上去問題就來了。整圖對比要求每次前向傳播都覆蓋全圖這意味著顯存占用與節(jié)點(diǎn)數(shù)成正比。假設(shè)你有 1000 萬節(jié)點(diǎn)、每個(gè)節(jié)點(diǎn) 128 維特征光特征矩陣就是 1000萬 × 128 × 4字節(jié) ≈ 5GB再加上鄰接矩陣和中間激活值單卡根本扛不住。而且整圖對比的負(fù)樣本構(gòu)造通常需要跨圖或跨視圖計(jì)算量進(jìn)一步放大。論文里有一個(gè)很關(guān)鍵的觀察整圖對比的監(jiān)督信號其實(shí)是全局的但圖的結(jié)構(gòu)信息大部分是局部的。一個(gè)節(jié)點(diǎn)的語義主要取決于它的鄰居和局部社區(qū)結(jié)構(gòu)而不是整張圖的全局分布。既然如此為什么非要在整圖上做對比這個(gè)反問直接引出了子圖對比的動(dòng)機(jī)。2.2 子圖采樣把大圖切成可管理的小世界SUBG-CON 的第一步是子圖采樣。給定一個(gè)中心節(jié)點(diǎn)從它的鄰居中隨機(jī)采樣若干跳通常是 1 到 2 跳構(gòu)成一個(gè)以該節(jié)點(diǎn)為中心的子圖。這個(gè)子圖的大小是可控的——比如限制最多 50 個(gè)節(jié)點(diǎn)、100 條邊。這樣一來每次前向傳播只需要處理這個(gè)小圖顯存占用與子圖規(guī)模成正比而不是與整圖規(guī)模成正比。這里有個(gè)設(shè)計(jì)細(xì)節(jié)值得注意采樣策略直接影響子圖的質(zhì)量。論文里用的是隨機(jī)游走加鄰居采樣的組合但實(shí)際操作中你會(huì)發(fā)現(xiàn)純隨機(jī)采樣可能采到一些噪聲鄰居導(dǎo)致子圖表示偏離中心節(jié)點(diǎn)的真實(shí)語義。我的經(jīng)驗(yàn)是如果圖是帶權(quán)重的按權(quán)重采樣會(huì)比均勻采樣穩(wěn)很多如果圖是無權(quán)的可以考慮按度數(shù)做歸一化采樣避免被超級節(jié)點(diǎn)主導(dǎo)。另一個(gè)關(guān)鍵點(diǎn)是子圖的重疊性。不同中心節(jié)點(diǎn)的子圖之間會(huì)有重疊這其實(shí)是好事——重疊部分相當(dāng)于天然的共享結(jié)構(gòu)能讓模型學(xué)到更一致的局部表示。但如果重疊過高比如圖非常稠密子圖之間的區(qū)分度就會(huì)下降對比學(xué)習(xí)的效果會(huì)打折扣。論文里通過控制采樣跳數(shù)和鄰居數(shù)量來平衡這一點(diǎn)實(shí)踐中我建議先用小跳數(shù)1跳跑通再逐步增加。2.3 對比目標(biāo)子圖表示與中心節(jié)點(diǎn)表示的一致性最大化采樣完子圖之后SUBG-CON 用圖神經(jīng)網(wǎng)絡(luò)通常是 GCN 或 GraphSAGE對子圖做編碼得到子圖級別的表示向量。同時(shí)中心節(jié)點(diǎn)本身也有一個(gè)表示向量可以來自子圖編碼中該節(jié)點(diǎn)對應(yīng)的輸出也可以單獨(dú)編碼。然后對比學(xué)習(xí)的目標(biāo)就是最大化子圖表示與中心節(jié)點(diǎn)表示之間的一致性。具體來說正樣本對是中心節(jié)點(diǎn)表示 它自己的子圖表示負(fù)樣本對是中心節(jié)點(diǎn)表示 其他節(jié)點(diǎn)的子圖表示。損失函數(shù)用的是標(biāo)準(zhǔn)的 InfoNCEL -log( exp(sim(z_i, s_i)/τ) / Σ_j exp(sim(z_i, s_j)/τ) )其中z_i是中心節(jié)點(diǎn) i 的表示s_i是它對應(yīng)子圖的表示s_j是其他子圖的表示τ是溫度系數(shù)。這個(gè)損失函數(shù)的直覺是讓中心節(jié)點(diǎn)和它自己的子圖像和其他子圖不像。這里有個(gè)很容易被忽略的細(xì)節(jié)負(fù)樣本的選取方式。論文里用的是同一批次內(nèi)其他中心節(jié)點(diǎn)的子圖作為負(fù)樣本這其實(shí)是一種 in-batch negative sampling。好處是不需要額外構(gòu)造負(fù)樣本壞處是如果批次內(nèi)子圖恰好語義相似比如都屬于同一個(gè)社區(qū)負(fù)樣本的區(qū)分度就不夠。我在復(fù)現(xiàn)時(shí)試過兩種改進(jìn)一是增大批次大小讓負(fù)樣本更豐富二是引入難負(fù)樣本挖掘優(yōu)先選那些與中心節(jié)點(diǎn)表示相似度較高的負(fù)樣本。后者效果更明顯但計(jì)算開銷也更大。2.4 自監(jiān)督信號的來源為什么不需要標(biāo)簽也能學(xué)很多人會(huì)問沒有標(biāo)簽?zāi)P驮趺粗缹W(xué)到的表示好不好答案在于圖結(jié)構(gòu)本身就是監(jiān)督信號。子圖對比的假設(shè)是一個(gè)節(jié)點(diǎn)的語義應(yīng)該與它周圍的局部結(jié)構(gòu)一致。如果模型學(xué)到的中心節(jié)點(diǎn)表示和它的子圖表示差異很大說明表示沒有捕捉到局部結(jié)構(gòu)信息損失就會(huì)高梯度就會(huì)推動(dòng)模型去修正。這種自監(jiān)督范式的優(yōu)勢在于它可以利用海量的無標(biāo)簽圖數(shù)據(jù)做預(yù)訓(xùn)練然后在少量標(biāo)簽數(shù)據(jù)上做微調(diào)。論文里的實(shí)驗(yàn)也證明了這一點(diǎn)——在多個(gè)基準(zhǔn)數(shù)據(jù)集上SUBG-CON 預(yù)訓(xùn)練 微調(diào)的效果能接近甚至超過從頭監(jiān)督訓(xùn)練的效果而后者需要大量標(biāo)簽。不過要注意自監(jiān)督不是萬能的。如果圖的結(jié)構(gòu)本身噪聲很大比如存在大量隨機(jī)邊子圖對比學(xué)到的表示可能也會(huì)被噪聲帶偏。這時(shí)候可以考慮在采樣階段做邊過濾或者在損失函數(shù)里加入正則項(xiàng)。3. 復(fù)現(xiàn)時(shí)的關(guān)鍵參數(shù)與實(shí)操配置3.1 子圖采樣參數(shù)跳數(shù)、鄰居數(shù)、子圖規(guī)模復(fù)現(xiàn) SUBG-CON 時(shí)最先要調(diào)的就是采樣參數(shù)。論文里給出的默認(rèn)配置是2 跳采樣每跳最多 10 個(gè)鄰居子圖最大 50 個(gè)節(jié)點(diǎn)。但這個(gè)配置不是萬能的得根據(jù)你的圖數(shù)據(jù)特點(diǎn)來調(diào)。我整理了一個(gè)參數(shù)對照表方便你快速定位參數(shù)含義小圖建議大圖建議注意事項(xiàng)跳數(shù)從中心節(jié)點(diǎn)擴(kuò)展的層數(shù)2-31-2跳數(shù)越大子圖越大顯存占用越高每跳鄰居數(shù)每層采樣的最大鄰居數(shù)10-155-10度數(shù)分布不均時(shí)建議按度數(shù)歸一化子圖最大節(jié)點(diǎn)數(shù)硬性截?cái)嚅撝?0050太小會(huì)丟失結(jié)構(gòu)信息太大會(huì)爆顯存批次大小每次訓(xùn)練的樣本數(shù)64-12832-64批次越大負(fù)樣本越豐富但顯存壓力越大實(shí)測下來1 跳采樣 每跳 10 鄰居 子圖最大 50 節(jié)點(diǎn)是一個(gè)比較穩(wěn)的起點(diǎn)。如果你的圖平均度數(shù)很高比如超過 50建議把每跳鄰居數(shù)降到 5否則子圖會(huì)迅速膨脹。3.2 編碼器選型GCN、GraphSAGE 還是 GAT論文里主要用的是 GCN 和 GraphSAGE 作為編碼器。GCN 的優(yōu)點(diǎn)是簡單、參數(shù)少、訓(xùn)練快GraphSAGE 的優(yōu)點(diǎn)是支持歸納學(xué)習(xí)對新節(jié)點(diǎn)友好GAT 引入了注意力機(jī)制理論上能學(xué)到更細(xì)粒度的鄰居權(quán)重但計(jì)算開銷也更大。我的建議是先用 GCN 跑通 baseline再根據(jù)效果決定是否換 GraphSAGE 或 GAT。如果你的圖是動(dòng)態(tài)變化的比如每天都有新節(jié)點(diǎn)加入GraphSAGE 的歸納能力會(huì)更有優(yōu)勢。如果圖的結(jié)構(gòu)非常復(fù)雜、鄰居重要性差異很大GAT 可能值得一試但要注意它的顯存占用通常是 GCN 的 1.5 到 2 倍。編碼器的層數(shù)也有講究。論文里用的是 2 層這其實(shí)和子圖采樣的跳數(shù)是對應(yīng)的——2 層 GCN 的感受野正好覆蓋 2 跳鄰居。如果你采樣了 3 跳但編碼器只有 2 層第 3 跳的信息就傳不到中心節(jié)點(diǎn)。所以編碼器層數(shù)應(yīng)該與采樣跳數(shù)匹配這是一個(gè)很容易踩的坑。3.3 損失函數(shù)與溫度系數(shù)InfoNCE 的調(diào)參經(jīng)驗(yàn)InfoNCE 損失里的溫度系數(shù)τ是一個(gè)很敏感的參數(shù)。論文里用的是 0.5但我在復(fù)現(xiàn)時(shí)發(fā)現(xiàn)τ 的取值對效果影響很大。τ 太小比如 0.1模型會(huì)過度關(guān)注難負(fù)樣本容易訓(xùn)練不穩(wěn)定τ 太大比如 1.0正負(fù)樣本的區(qū)分度不夠?qū)W到的表示會(huì)偏平。我的經(jīng)驗(yàn)是從 0.5 開始如果訓(xùn)練損失震蕩明顯就調(diào)大到 0.7如果損失下降太慢就調(diào)小到 0.3。另外溫度系數(shù)可以和批次大小聯(lián)動(dòng)——批次越大負(fù)樣本越多τ 可以適當(dāng)調(diào)小因?yàn)殡y負(fù)樣本的絕對數(shù)量增加了。還有一個(gè)細(xì)節(jié)負(fù)樣本的數(shù)量。InfoNCE 里負(fù)樣本越多估計(jì)越準(zhǔn)但計(jì)算量也越大。論文里用的是 in-batch negative負(fù)樣本數(shù)等于批次大小減一。如果你顯存夠可以把批次開到 256 甚至 512效果通常會(huì)有提升。3.4 訓(xùn)練流程與早停策略SUBG-CON 的訓(xùn)練流程大致是每個(gè) epoch 遍歷所有中心節(jié)點(diǎn)采樣一個(gè)子圖編碼計(jì)算對比損失反向傳播。這里有個(gè)工程上的優(yōu)化點(diǎn)子圖采樣可以離線做提前把每個(gè)節(jié)點(diǎn)的子圖存下來訓(xùn)練時(shí)直接讀避免重復(fù)采樣。但離線采樣的缺點(diǎn)是子圖固定缺乏隨機(jī)性可能影響泛化。我的做法是折中——每個(gè) epoch 重新采樣一次既保證隨機(jī)性又不會(huì)太慢。早停策略方面自監(jiān)督學(xué)習(xí)沒有驗(yàn)證集標(biāo)簽所以不能用準(zhǔn)確率做早停。常用的替代指標(biāo)是訓(xùn)練損失的滑動(dòng)平均如果連續(xù)幾個(gè) epoch 損失不再下降就停止。另外也可以在下游任務(wù)上做小樣本驗(yàn)證比如用 1% 的標(biāo)簽做線性探測如果探測準(zhǔn)確率不再提升就停止預(yù)訓(xùn)練。4. 踩坑實(shí)錄復(fù)現(xiàn)過程中最容易翻車的幾個(gè)地方4.1 子圖采樣導(dǎo)致的孤立節(jié)點(diǎn)問題復(fù)現(xiàn)時(shí)遇到的第一個(gè)坑是孤立節(jié)點(diǎn)。有些節(jié)點(diǎn)的度數(shù)很低比如只有 1 到 2 個(gè)鄰居采樣出來的子圖非常小甚至只有一個(gè)節(jié)點(diǎn)。這種子圖的表示幾乎沒有結(jié)構(gòu)信息對比學(xué)習(xí)的效果很差。解決辦法有兩個(gè)一是設(shè)置最小子圖規(guī)模如果采樣結(jié)果小于閾值就重復(fù)采樣或直接跳過該節(jié)點(diǎn)二是對低度數(shù)節(jié)點(diǎn)做特殊處理比如在子圖里加入二跳鄰居或者用特征相似度補(bǔ)充虛擬鄰居。我試過第一種方法簡單有效但會(huì)損失一部分訓(xùn)練樣本第二種方法更復(fù)雜但在低度數(shù)節(jié)點(diǎn)占比高的圖上效果更好。4.2 負(fù)樣本太簡單導(dǎo)致模型學(xué)不到東西第二個(gè)坑是負(fù)樣本區(qū)分度不夠。如果批次內(nèi)隨機(jī)選的負(fù)樣本和中心節(jié)點(diǎn)差異很大比如屬于完全不同的社區(qū)模型很容易就能區(qū)分損失很快降到很低但學(xué)到的表示在下游任務(wù)上表現(xiàn)一般。這就是所謂的簡單負(fù)樣本問題。我的改進(jìn)方法是引入難負(fù)樣本挖掘在每個(gè)批次內(nèi)先計(jì)算中心節(jié)點(diǎn)與所有負(fù)樣本的相似度然后選相似度最高的幾個(gè)作為難負(fù)樣本加大它們的權(quán)重。具體實(shí)現(xiàn)上可以在損失函數(shù)里對難負(fù)樣本乘以一個(gè)大于 1 的系數(shù)。實(shí)測下來這個(gè)方法能讓下游任務(wù)的準(zhǔn)確率提升 2 到 3 個(gè)百分點(diǎn)。4.3 顯存溢出批次大小與子圖規(guī)模的權(quán)衡第三個(gè)坑是顯存溢出。子圖對比雖然比整圖對比省顯存但如果批次大小和子圖規(guī)模都設(shè)得很大照樣會(huì)爆。我一開始把批次設(shè)為 128、子圖最大 100 節(jié)點(diǎn)結(jié)果 16GB 顯存直接 OOM。后來我做了個(gè)簡單的估算顯存占用 ≈ 批次大小 × 子圖節(jié)點(diǎn)數(shù) × 特征維度 × 4 字節(jié) × 常數(shù)因子。假設(shè)批次 64、子圖 50 節(jié)點(diǎn)、特征 128 維光特征矩陣就是 64 × 50 × 128 × 4 ≈ 1.6MB看起來不大但中間激活值和梯度會(huì)放大 10 到 20 倍。所以實(shí)際配置時(shí)建議先用小批次跑通再逐步增大同時(shí)用torch.cuda.max_memory_allocated()監(jiān)控顯存峰值。4.4 訓(xùn)練不收斂學(xué)習(xí)率與溫度系數(shù)的聯(lián)動(dòng)第四個(gè)坑是訓(xùn)練不收斂。表現(xiàn)是損失震蕩劇烈或者損失下降后又反彈。排查下來問題出在學(xué)習(xí)率和溫度系數(shù)的配合上。學(xué)習(xí)率太大比如 0.01加上溫度系數(shù)太小比如 0.1會(huì)導(dǎo)致梯度爆炸。我的解決方案是學(xué)習(xí)率從 0.001 開始溫度系數(shù)從 0.5 開始兩者同步調(diào)整。如果損失震蕩先降學(xué)習(xí)率到 0.0005再考慮調(diào)大溫度系數(shù)。另外加入梯度裁剪torch.nn.utils.clip_grad_norm_也能有效緩解震蕩閾值設(shè) 1.0 到 5.0 之間比較合適。4.5 下游任務(wù)微調(diào)線性探測 vs 全量微調(diào)最后一個(gè)坑是下游任務(wù)微調(diào)策略。論文里主要報(bào)告的是線性探測凍結(jié)預(yù)訓(xùn)練編碼器只訓(xùn)練一個(gè)線性分類器的結(jié)果但實(shí)際操作中全量微調(diào)往往效果更好只是容易過擬合。我的建議是如果下游標(biāo)簽很少比如每類只有幾個(gè)樣本用線性探測如果標(biāo)簽相對充足每類幾十個(gè)以上用全量微調(diào)但要加正則化比如權(quán)重衰減 1e-4和早停。另外微調(diào)時(shí)的學(xué)習(xí)率應(yīng)該比預(yù)訓(xùn)練時(shí)小一個(gè)數(shù)量級避免破壞預(yù)訓(xùn)練學(xué)到的表示。5. 子圖對比的邊界與延伸思考5.1 什么類型的圖適合子圖對比子圖對比不是萬能的。根據(jù)我的實(shí)踐經(jīng)驗(yàn)它最適合以下類型的圖一是局部結(jié)構(gòu)信息豐富的圖比如社交網(wǎng)絡(luò)、引用網(wǎng)絡(luò)、分子圖二是節(jié)點(diǎn)度數(shù)分布相對均勻的圖避免超級節(jié)點(diǎn)主導(dǎo)三是規(guī)模大到整圖放不下的圖這是它的核心優(yōu)勢場景。反過來以下場景要謹(jǐn)慎使用一是全局結(jié)構(gòu)比局部結(jié)構(gòu)更重要的圖比如某些需要長距離依賴的圖二是節(jié)點(diǎn)特征非常稀疏或缺失的圖因?yàn)樽訄D對比很依賴特征質(zhì)量三是動(dòng)態(tài)變化極快的圖因?yàn)樽訄D采樣需要一定的穩(wěn)定性。5.2 子圖對比與整圖對比的互補(bǔ)關(guān)系雖然這篇論文主打子圖對比但我的實(shí)際體會(huì)是子圖對比和整圖對比不是替代關(guān)系而是互補(bǔ)關(guān)系。子圖對比擅長捕捉局部結(jié)構(gòu)整圖對比擅長捕捉全局分布。如果計(jì)算資源允許可以把兩者結(jié)合——用子圖對比做預(yù)訓(xùn)練再用整圖對比做精調(diào)或者直接在損失函數(shù)里加入全局對比項(xiàng)。論文里也提到了這一點(diǎn)但實(shí)驗(yàn)主要聚焦在子圖對比上。我在自己的項(xiàng)目里試過混合損失效果確實(shí)比單用子圖對比好但計(jì)算開銷也更大。所以是否混合取決于你的資源預(yù)算和效果要求。5.3 從 SUBG-CON 延伸出的幾個(gè)改進(jìn)方向最后分享幾個(gè)我覺得值得探索的改進(jìn)方向。一是自適應(yīng)子圖采樣不再用固定的跳數(shù)和鄰居數(shù)而是根據(jù)節(jié)點(diǎn)的局部密度動(dòng)態(tài)調(diào)整稠密區(qū)域采小一點(diǎn)稀疏區(qū)域采大一點(diǎn)。二是多尺度子圖對比同時(shí)采樣 1 跳和 2 跳子圖做多尺度的對比學(xué)習(xí)讓模型同時(shí)學(xué)到不同粒度的結(jié)構(gòu)信息。三是跨圖子圖對比如果有多個(gè)相關(guān)的圖比如不同平臺的用戶圖可以做跨圖的子圖對比學(xué)習(xí)更通用的表示。這些方向我在小規(guī)模數(shù)據(jù)上做過初步實(shí)驗(yàn)效果有提升但還不穩(wěn)定感興趣的朋友可以繼續(xù)深挖。子圖對比這個(gè)范式本身還在快速演進(jìn)相信后續(xù)會(huì)有更多有意思的工作出來。