圖神經(jīng)網(wǎng)絡(luò))
最近把這篇AAAI 2020收錄的《HetSANN: An Attention-based Graph Neural Network for Heterogeneous Structural Learning》翻出來重新精讀了一遍越看越覺得它在異構(gòu)圖神經(jīng)網(wǎng)絡(luò)的發(fā)展里處于一個很有意思的卡位。既沒有走HAN那套依賴元路徑的路線也沒有像GTN那樣把元路徑搜索變成可微分的結(jié)構(gòu)學(xué)習(xí)而是直接用注意力機(jī)制去處理“鄰居類型不同”這件事本身。如果你正在做異構(gòu)圖相關(guān)的研究或者對圖Transformer的演進(jìn)脈絡(luò)感興趣這篇文章值得花一晚上好好拆一遍。這篇解讀我會從問題動機(jī)、方法設(shè)計(jì)、實(shí)驗(yàn)結(jié)論一路講到復(fù)現(xiàn)時(shí)踩過的坑盡量把這個模型里里外外說透。1. 論文背景與問題動機(jī)1.1 異構(gòu)圖里“類型”這件事有多麻煩先聊一個很基礎(chǔ)但經(jīng)常被忽略的問題異構(gòu)圖為什么比同構(gòu)圖難這么多。在同構(gòu)圖里所有節(jié)點(diǎn)和邊都是一種類型你分不清一個節(jié)點(diǎn)是論文還是作者其實(shí)沒關(guān)系反正它們共享同一套特征空間和關(guān)系語義。但異構(gòu)圖不一樣比如學(xué)術(shù)網(wǎng)絡(luò)里有論文、作者、會議、學(xué)科方向這幾種節(jié)點(diǎn)邊也有“作者寫了論文”“論文發(fā)表在會議上”“論文屬于某學(xué)科”等不同含義。如果直接把這些不同類型的節(jié)點(diǎn)扔進(jìn)同一個GCN或者GAT里模型會默認(rèn)所有節(jié)點(diǎn)來自同一個分布這顯然不合理——因?yàn)椤皫灼撐摹焙汀耙晃粚W(xué)者”的特征維度、統(tǒng)計(jì)特性、語義角色都完全不同。早期處理方式也很樸素就是所謂“元路徑”。比如“作者-論文-會議”可以構(gòu)成一個元路徑通過這條路徑可以把作者節(jié)點(diǎn)和會議節(jié)點(diǎn)關(guān)聯(lián)起來再把這些異構(gòu)關(guān)系折疊成若干個同構(gòu)圖然后在折疊后的圖上跑標(biāo)準(zhǔn)GNN。這個思路看起來合理實(shí)際操作卻非常磨人。這種“折疊”其實(shí)是在損失信息一邊丟失了原始邊類型一邊把整個圖的結(jié)構(gòu)壓成了幾條人工路徑路徑外面的交互關(guān)系完全進(jìn)不了模型。1.2 元路徑老路的一大堆問題元路徑方法最頭疼的不是概念是定義過程。你拿到一個異構(gòu)圖第一件事是想清楚哪些路徑是有語義的。比如IMDB電影網(wǎng)絡(luò)里“電影-演員”是一條有效路徑“導(dǎo)演-電影-演員”也是一條路徑但“電影-導(dǎo)演-演員-導(dǎo)演-電影”呢語義就變得很奇怪。為了覆蓋主要語義關(guān)系你得不停嘗試不同的路徑組合每一組都要做一次數(shù)據(jù)預(yù)處理、跑一輪實(shí)驗(yàn)、調(diào)一輪超參。這個事在數(shù)據(jù)集小的時(shí)候還能忍一旦節(jié)點(diǎn)類型和邊類型多起來元路徑的搜索空間立刻爆炸人工枚舉基本變成不可能完成的任務(wù)。更麻煩的是同一個任務(wù)下不同的節(jié)點(diǎn)對最優(yōu)路徑可能完全不同。分類一位研究者的領(lǐng)域用“作者-論文-會議”比“作者-論文-作者”更有區(qū)分力但在做作者間相似度計(jì)算時(shí)可能“作者-論文-作者”這種共著路徑又成了主力。沒有任何一條元路徑能在所有情況下通用。這也催生了GTN這類嘗試用梯度搜索替代人工選路徑的工作但GTN的代價(jià)是額外的結(jié)構(gòu)學(xué)習(xí)參數(shù)模型變得復(fù)雜訓(xùn)練開銷也大。還有一個常常被忽略的問題是元路徑一旦定義好整個模型能看到的圖結(jié)構(gòu)就被人為切掉了。原始異構(gòu)圖里那種“多條邊、多種類型”“一個節(jié)點(diǎn)通過不同關(guān)系連接不同類別鄰居”的豐富度在轉(zhuǎn)換過程中已經(jīng)折損了一大半。論文里的實(shí)驗(yàn)也顯示基于元路徑的方法對比不依賴元路徑的方法在部分任務(wù)上表現(xiàn)更差這就是信息損失的直觀后果。1.3 這篇文章憑什么“不繞路”直接來HetSANN的核心姿態(tài)就是我不需要把異構(gòu)圖轉(zhuǎn)成同構(gòu)圖也不需要預(yù)定義任何元路徑直接從原始結(jié)構(gòu)出發(fā)讓注意力機(jī)制自己決定哪些鄰居值得學(xué)。它把“節(jié)點(diǎn)類型不同”這件事編碼進(jìn)模型參數(shù)不同的邊類型對應(yīng)不同的特征變換然后在這個基礎(chǔ)上計(jì)算注意力系數(shù)、做鄰居聚合。說白了它把“類型”這個離散信息變成了可學(xué)習(xí)的參數(shù)約束而不是靠路徑把類型信息提前抹掉。我最初讀這個動機(jī)時(shí)心里第一反應(yīng)是這不就是給每種關(guān)系配一個獨(dú)立的線性變換再接GAT嗎聽起來沒有太大飛躍。但真正動手復(fù)現(xiàn)之后才發(fā)現(xiàn)事情沒有表面這么簡單。難點(diǎn)在于“邊類型感知的注意力”與“多跳結(jié)構(gòu)信息”的配合以及訓(xùn)練時(shí)面對異構(gòu)子圖的那種不穩(wěn)定性。下文慢慢拆。2. 核心方法全景拆解2.1 類型感知的投影變換給每種關(guān)系發(fā)一張專屬名片HetSANN的第一個關(guān)鍵組件是類型感知的線性變換。傳統(tǒng)GAT對每個節(jié)點(diǎn)用同一個權(quán)重矩陣做特征映射這相當(dāng)于假定所有節(jié)點(diǎn)的特征空間是一致的。HetSANN的做法是對不同的節(jié)點(diǎn)類型或邊類型使用各自獨(dú)立的權(quán)重矩陣。比如“作者”節(jié)點(diǎn)用W_a“論文”節(jié)點(diǎn)用W_p或者更準(zhǔn)確地說在聚合時(shí)根據(jù)當(dāng)前這組關(guān)系的類型來決定用哪套參數(shù)去變換鄰居特征。這樣做的直覺可以拿“多語言交流”來類比一群說不同語言的人聚在一起討論問題如果所有人都直接用母語發(fā)言誰也不知道對方在說什么但如果先把每種語言分別翻譯成英語再放到同一張會議桌上討論語義就對齊了。類型感知投影做的就是“翻譯”這一步。它把不同類型節(jié)點(diǎn)的高維原始特征映射到同一個公共表示空間同時(shí)保留“翻譯規(guī)則因語言而異”這一信息。實(shí)現(xiàn)時(shí)要特別注意不同類型節(jié)點(diǎn)的輸入特征維度往往不一樣。論文節(jié)點(diǎn)可能有幾千維的詞袋向量作者節(jié)點(diǎn)可能是手工設(shè)計(jì)的ID特征甚至沒有原始特征。所以第一步通常是用一個線性層把每種類型分別壓到同一個隱藏維度d。這正是“類型感知投影”最實(shí)在的功能先把維度對齊再做后續(xù)注意力運(yùn)算否則拼接或相加時(shí)維度都碰不上。2.2 邊類型約束的注意力打分與歸一化有了統(tǒng)一維度之后第二步是計(jì)算注意力。設(shè)當(dāng)前中心節(jié)點(diǎn)是i它通過某一條邊類型為φ的關(guān)系連接到鄰居j那么模型先分別得到變換后的表示再拼接起來經(jīng)過一個由邊類型參數(shù)化的權(quán)重向量做打分再過LeakyReLU激活。最后對所有鄰居的分?jǐn)?shù)做softmax歸一化得到每個鄰居對中心節(jié)點(diǎn)的貢獻(xiàn)權(quán)重。這個設(shè)計(jì)和通用GAT最大的區(qū)別在哪里在GAT里所有鄰居共享同一個注意力打分函數(shù)在HetSANN里打分函數(shù)的參數(shù)依賴邊類型。同一對節(jié)點(diǎn)如果連接關(guān)系不同打出來的分就是不同套邏輯。你可能會想“這跟把每種關(guān)系子圖分別跑一個GAT再求和有什么區(qū)別”區(qū)別在于HetSANN的softmax歸一化是在中心節(jié)點(diǎn)的所有鄰居上統(tǒng)一進(jìn)行的不管這些鄰居屬于哪種類型。也就是說一個電影節(jié)點(diǎn)同時(shí)連接演員、導(dǎo)演、標(biāo)簽三類鄰居它要一起分配注意力權(quán)重而不是在演員子圖里各歸各歸一化。這個“競爭關(guān)系”是跨類型的模型需要學(xué)會在不同類型之間權(quán)衡該看誰這正是它在異構(gòu)圖上比多個同構(gòu)GAT疊加更靈活的原因。同樣值得注意的還有自環(huán)的處理。GAT里通常會給每個節(jié)點(diǎn)加一條指向自身的邊用來保留原始特征。HetSANN在保留殘差連接的前提下自環(huán)加不加都會影響性能。我復(fù)現(xiàn)時(shí)把這個開關(guān)單獨(dú)抽出來做了幾組對比發(fā)現(xiàn)配合原文的多跳結(jié)構(gòu)之后自環(huán)的增益并不明顯但殘差是剛需。2.3 殘差連接與多跳感受野既要深又要穩(wěn)注意力層解決了“同一條邊上怎么聚合”但沒有解決“信息怎么跨多跳流動”的問題。論文里明確提出只堆疊單跳注意力層還不夠需要把多跳鄰居的信息也帶進(jìn)最終表示。最樸素的做法是把網(wǎng)絡(luò)疊深但在異構(gòu)圖里層數(shù)加深的邊際收益很低過平滑現(xiàn)象來得比同構(gòu)圖更快——聚合幾次之后節(jié)點(diǎn)表示趨同類別分界被磨平。論文的處理方式很巧妙使用殘差和稠密連接把每一層的輸出和之前若干層的輸出拼起來而不是只依賴最后一層。這樣一來第一層輸出代表1跳鄰居的語義第二層輸出代表2跳鄰居的語義把它們拼接后分類器可以同時(shí)看到多個尺度的結(jié)構(gòu)信息。模型被迫在不同的“跳數(shù)視圖”下做權(quán)衡而不是靠單一深層表示硬扛。我用一個粗淺的類比解釋一下你在一個小區(qū)里找某棟樓的位置只看隔壁鄰居1跳往往夠了但如果隔壁鄰居信息太少你還得問隔壁的隔壁2跳。只問一次可能錯過關(guān)鍵線索把所有距離的答復(fù)都收集起來再綜合判斷找到的概率就大多了。HetSANN的多跳聚合干的就是這件事。2.4 聯(lián)合訓(xùn)練分類和鏈路預(yù)測一起學(xué)文章里另一個容易被忽視的設(shè)計(jì)是多任務(wù)聯(lián)合訓(xùn)練。主任務(wù)是節(jié)點(diǎn)分類但作者給模型加了輔助的鏈路預(yù)測目標(biāo)從圖中隨機(jī)采樣正邊再生成一批不存在的負(fù)邊把節(jié)點(diǎn)對表示拼接后經(jīng)一個MLP打分用二分類損失約束整個模型。這個做法的意義在于分類標(biāo)簽通常只覆蓋少數(shù)節(jié)點(diǎn)數(shù)據(jù)量不夠時(shí)模型很容易過擬合鏈路預(yù)測為模型提供了全圖結(jié)構(gòu)上的額外監(jiān)督讓表示空間不至于只被標(biāo)簽撐起來。這種半監(jiān)督無監(jiān)督組合的套路現(xiàn)在看已經(jīng)很常見但在2020年前后圖神經(jīng)網(wǎng)絡(luò)的主流做法還是直接在帶標(biāo)簽的一小撮節(jié)點(diǎn)上訓(xùn)練。HetSANN用鏈路預(yù)測做正則等于變相擴(kuò)大了訓(xùn)練信號來源。對復(fù)現(xiàn)者來說難點(diǎn)在于負(fù)采樣比例負(fù)邊采太少模型學(xué)不到區(qū)分能力采太多正負(fù)樣本失衡訓(xùn)練會震蕩起來。論文實(shí)驗(yàn)里這條輔助損失的權(quán)重好像并不高但它確實(shí)讓最終表示更穩(wěn)。3. 實(shí)驗(yàn)設(shè)置與關(guān)鍵結(jié)論解讀3.1 數(shù)據(jù)集與對比方法挑對手挑得很有講究原文實(shí)驗(yàn)用到了幾個公開基準(zhǔn)數(shù)據(jù)集覆蓋了論文網(wǎng)絡(luò)和電影網(wǎng)絡(luò)。DBLP學(xué)術(shù)網(wǎng)絡(luò)包含作者、論文、會議、研究方向等節(jié)點(diǎn)IMDB電影網(wǎng)絡(luò)則包含電影、演員、導(dǎo)演這樣的類型組合。這兩種圖的規(guī)模不算特別大但類型和邊關(guān)系足夠復(fù)雜很適合驗(yàn)證“不做元路徑”到底行不行。對比方法選得也比較全既有DeepWalk這類無視類型的網(wǎng)絡(luò)嵌入方法也有metapath2vec這樣經(jīng)典元路徑類方法還有HAN、GTN、HetGNN這些異構(gòu)圖GNN代表。此外作者還放了GCN、GAT這種通用GNN作為參照。這個對比矩陣的好處是能區(qū)分“改進(jìn)來自異構(gòu)圖建?!边€是“改進(jìn)來自注意力機(jī)制本身”。如果對手全是沒有注意力的模型那贏下來也可能是GAT的功勞說不清楚。3.2 主實(shí)驗(yàn)結(jié)果不靠元路徑也能贏主實(shí)驗(yàn)在節(jié)點(diǎn)分類任務(wù)上比較Micro-F1和Macro-F1兩個指標(biāo)。整體結(jié)論非常明確HetSANN在大多數(shù)數(shù)據(jù)集和指標(biāo)上超過或者追平了當(dāng)時(shí)最好的異構(gòu)圖模型而且全程沒有使用任何預(yù)定義元路徑。尤其值得關(guān)注的是Macro-F1上的表現(xiàn)因?yàn)轭悇e分布往往不均衡Macro-F1更看重少數(shù)類的預(yù)測能力這說明模型學(xué)到的不只是頭部類別的模式。另一個讓我印象深刻的點(diǎn)是它對比基于元路徑的模型不落下風(fēng)訓(xùn)練效率還高。元路徑方法在預(yù)處理階段要花大量時(shí)間構(gòu)造路徑實(shí)例推理階段路徑選擇本身也影響結(jié)果。HetSANN省去了這個環(huán)節(jié)等于把“定義路徑”這件事徹底移出流程。這對實(shí)際工程場景非常友好也是論文在后來頻繁被引用的原因之一。3.3 消融與效率分析殘差到底幫了多少消融實(shí)驗(yàn)是這篇論文中最有價(jià)值的部分之一。作者驗(yàn)證了去掉類型感知變換、去掉多跳殘差結(jié)構(gòu)后的性能變化。結(jié)論是這兩個組件都不是錦上添花而是缺一不可。特別是殘差/稠密連接去掉后多層注意力堆疊會出現(xiàn)明顯的性能回落印證了異構(gòu)圖中“疊深即退化”的現(xiàn)象。效率方面由于不依賴元路徑模型在訓(xùn)練時(shí)間上也有優(yōu)勢。我在復(fù)現(xiàn)時(shí)其實(shí)對這一點(diǎn)感觸更深處理元路徑的數(shù)據(jù)預(yù)處理比訓(xùn)練本身還耗時(shí)而且每次換數(shù)據(jù)集或者換路徑定義都要重新跑一遍預(yù)處理。HetSANN的預(yù)處理基本就是圖加載和類型映射一個晚上就能把實(shí)驗(yàn)流程跑通。4. 從論文到代碼復(fù)現(xiàn)要點(diǎn)與踩坑記錄4.1 輸入特征與維度統(tǒng)一怎么做復(fù)現(xiàn)第一步是先處理數(shù)據(jù)類型。異構(gòu)圖里每個節(jié)點(diǎn)類型的特征維度不同比如論文節(jié)點(diǎn)有文本特征作者節(jié)點(diǎn)可能只有ID。這要求先為每個類型訓(xùn)練一個專屬線性投影輸入原始維度輸出統(tǒng)一維度然后把這個投影放在GNN層之前。一個很容易踩的坑是有些節(jié)點(diǎn)類型在原始數(shù)據(jù)里沒有特征所有節(jié)點(diǎn)都是同一維度的one-hot。此時(shí)類型感知投影退化成每種類型各學(xué)一個線性層這本身沒問題但如果隱藏維度設(shè)得過大而訓(xùn)練樣本有限這部分投影很容易過擬合。我當(dāng)時(shí)把隱藏維度從64調(diào)成32發(fā)現(xiàn)Macro-F1反而漲了就是因?yàn)橥队皡?shù)量降下來之后模型把注意力集中在更有區(qū)分性的結(jié)構(gòu)信息上。4.2 類型感知投影的工程實(shí)現(xiàn)工程上我建議把“類型投影”和“注意力層”拆成兩個模塊分別實(shí)現(xiàn)方便調(diào)試。類型投影的輸入是節(jié)點(diǎn)數(shù)量原始特征維度輸出是節(jié)點(diǎn)數(shù)量隱藏維度。按類型編號分組做矩陣乘法然后把結(jié)果拼回一個張量。實(shí)現(xiàn)注意力的部分有個常見誤區(qū)不少人會直接調(diào)用現(xiàn)成GAT層再把不同邊類型的鄰接矩陣挨個傳進(jìn)去。這樣確實(shí)能跑但softmax歸一化是分開做的和論文里“跨類型統(tǒng)一歸一化”的語義不一致。正確的做法是把所有邊類型聚合在一個大鄰接矩陣上跑稀疏注意力或者在循環(huán)里分別算消息但共享一份對數(shù)賠率最后統(tǒng)一softmax。我第一次實(shí)現(xiàn)時(shí)貪省事分開歸一化結(jié)果收斂慢且不穩(wěn)定改成統(tǒng)一歸一化之后才恢復(fù)論文里的表現(xiàn)。4.3 注意力歸一化的幾個坑另一個坑在數(shù)值層面。稀疏矩陣的softmax如果自己寫需要按行減去最大值防止指數(shù)溢出。在異構(gòu)圖里行長度差異很大有的中心節(jié)點(diǎn)有幾百個鄰居有的節(jié)點(diǎn)只有兩三個。把大度數(shù)節(jié)點(diǎn)和小度數(shù)節(jié)點(diǎn)放在同一批訓(xùn)練注意力分布天然不同。復(fù)現(xiàn)時(shí)如果出現(xiàn)某些節(jié)點(diǎn)梯度突變建議先檢查LeakyReLU的斜率原文設(shè)置是0.2太低會讓注意力分?jǐn)?shù)趨于飽和。我還試過給注意力分?jǐn)?shù)加溫度系數(shù)來調(diào)節(jié)分布的陡峭程度在小數(shù)據(jù)集上有一點(diǎn)幫助但數(shù)據(jù)集大了以后作用變?nèi)酢_@類技巧可以直接當(dāng)超參調(diào)不用太糾結(jié)。4.4 訓(xùn)練技巧與超參建議訓(xùn)練方面全圖訓(xùn)練最簡單但顯存壓力大。如果圖規(guī)模被撐大建議用鄰居采樣或者按子圖切分訓(xùn)練但要注意切分時(shí)別把異構(gòu)邊類型徹底打散每組子圖盡量保留各種關(guān)系類型否則類型感知投影會退化。超參上我復(fù)用下來比較穩(wěn)的組合是dropout在0.3左右學(xué)習(xí)率3e-3隱藏層維度64到128注意力頭數(shù)4。很多人習(xí)慣堆3層GNN但在這個模型里我覺得2層加多跳稠密連接更穩(wěn)。鏈路預(yù)測的負(fù)采樣比我試過1:1到1:5最終1:2附近效果不錯負(fù)采樣太多會把模型注意力往假邊方向帶。還有一點(diǎn)是初始化。類型感知投影的權(quán)重如果全用默認(rèn)正態(tài)初始化收斂會慢。我習(xí)慣給投影層做Xavier初始化并且為不同邊類型設(shè)置不同seed擾動避免多條關(guān)系類型初始時(shí)過于對稱導(dǎo)致注意力學(xué)到相同模式。5. 學(xué)術(shù)脈絡(luò)從GAT到HetSANN再到圖Transformer5.1 GAT、HAN和GTN在干什么要真正讀懂HetSANN的價(jià)值得把它放回2019-2020年的上下文里。GAT證明注意力機(jī)制在圖節(jié)點(diǎn)聚合上的有效性但它不區(qū)分邊類型。HAN引入了兩層注意力一層學(xué)同類型路徑內(nèi)部的節(jié)點(diǎn)權(quán)重一層學(xué)多條元路徑之間的權(quán)重但整體還是以元路徑為骨架。GTN嘗試動態(tài)學(xué)習(xí)元路徑的組合理論上更自由但可控性和實(shí)現(xiàn)復(fù)雜度都是成本。這些工作放在一起看其實(shí)有一條清晰的升級曲線從“手工定義語義”到“半自動化語義搜索”再到HetSANN的“邊類型原生編碼”。HetSANN沒有在路徑空間里繞來繞去而是直接告訴模型“這里的鄰居有多種類型請自己看著辦”算是一次簡化也是一次轉(zhuǎn)向。5.2 HetSANN設(shè)計(jì)里的“Transformer影子”現(xiàn)在回看HetSANN的設(shè)計(jì)會發(fā)現(xiàn)它和圖Transformer的思路高度神似。Transformer本質(zhì)上是讓每個token對所有token做注意力位置編碼負(fù)責(zé)注入順序信息HetSANN讓中心節(jié)點(diǎn)對跨類型鄰居做注意力邊類型編碼負(fù)責(zé)注入關(guān)系信息。區(qū)別在于Transformer用位置編碼HetSANN用類型感知投影。后來的異構(gòu)圖Transformer類方法基本都是沿著“注意力 類型編碼 相對結(jié)構(gòu)編碼”這個路線走。說HetSANN是異構(gòu)圖上的早期Transformer雛形一點(diǎn)都不夸張。5.3 對后續(xù)工作的影響從引文網(wǎng)絡(luò)看HetSANN被不少后續(xù)工作當(dāng)作“無需元路徑的注意力基線”來對比同時(shí)它也啟發(fā)了不同類型編碼方式在注意力模型里的應(yīng)用。它的一個隱含貢獻(xiàn)是提醒社區(qū)異構(gòu)圖里的“類型”不一定非得通過路徑轉(zhuǎn)換來消化直接建模到注意力打分函數(shù)里是一種更干凈的做法。如果你現(xiàn)在要設(shè)計(jì)一個異構(gòu)圖模型面對“用不用元路徑”這個問題時(shí)這篇論文的決策過程能給你提供一個很好的參考坐標(biāo)。元路徑不是不能用的工具但把它當(dāng)默認(rèn)選項(xiàng)可能在出發(fā)之前就已經(jīng)丟了一部分結(jié)構(gòu)信息。這篇論文我前前后后精讀加復(fù)現(xiàn)下來最大的收獲不是模型本身多強(qiáng)而是它讓我重新理解了“類型感知”這四個字的重量。你不需要為每一種關(guān)系精心設(shè)計(jì)一條路徑來告訴模型“這很重要”只要給模型足夠的表達(dá)能力它自己能從數(shù)據(jù)里判斷什么時(shí)候該看演員什么時(shí)候該看導(dǎo)演。我們做模型的人很多時(shí)候過度依賴人工先驗(yàn)忘記了把決定權(quán)還給數(shù)據(jù)和訓(xùn)練過程。這個道理在異構(gòu)圖里成立在很多NLP任務(wù)里其實(shí)也成立。