日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Graph Neural Network(GAE,GVAE,ARGA)

發(fā)布時(shí)間:2023/12/18 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Graph Neural Network(GAE,GVAE,ARGA) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前面幾次的整理GCN,GAT,GraphSAGE等等都適合在半監(jiān)督,監(jiān)督的場(chǎng)景下,而有沒有圖方法可以使用于在無監(jiān)督的場(chǎng)景下使用呢?去發(fā)現(xiàn)節(jié)點(diǎn)的內(nèi)在結(jié)果,挖掘隱藏關(guān)系如鏈接預(yù)測(cè)等等任務(wù)。

答案是:自編碼器(AE) /變分自編碼器(VAE)+Graph

Graph Auto-Encoders (GAE)
GAE的目的是通過encoder-decoder 的結(jié)構(gòu)去獲取到圖中節(jié)點(diǎn)的 embedding,然后再去做具體的下游任務(wù)比如鏈接預(yù)測(cè)。

首先回顧一下自編碼器,它是利用神經(jīng)網(wǎng)絡(luò)將數(shù)據(jù)逐層降維壓縮,相當(dāng)于讓每層神經(jīng)網(wǎng)絡(luò)之間的激活函數(shù)就起到了將"線性"轉(zhuǎn)化為"非線性"的作用,然后嘗試還原輸入即讓輸出==輸出以捕捉到數(shù)據(jù)的隱含信息。整體的結(jié)構(gòu)分編碼器Decoder和解碼器Encoder,編碼器負(fù)責(zé)壓縮,解碼器負(fù)責(zé)還原。同樣的,想要在Graph上也完成這種操作,也是使用encoder-decoder 的結(jié)構(gòu),具體操作如上圖:

  • Encoder。直接使用 GCN 作為 encoder,來得到節(jié)點(diǎn)的 latent representations(即關(guān)于每個(gè)節(jié)點(diǎn)的 embedding)
    Z=GCN(A)Z=GCN(A)Z=GCN(A) 其中A是鄰接矩陣,Z代表的就是所有節(jié)點(diǎn)的表示,如果接下來要做下游任務(wù)也是直接使用這個(gè)表示就可以。

  • Decoder。這里和原來的AE不一樣,不是對(duì)稱結(jié)構(gòu)的網(wǎng)絡(luò),而是直接采用內(nèi)積 inner-product 作為 decoder 來重構(gòu)(reconstruct)原始的Graph
    A′=σ(ZTZ)A'=\sigma (Z^TZ)A=σ(ZTZ)這里的A’就是重構(gòu)(reconstruct)出來的鄰接矩陣,可以被理解為兩個(gè)節(jié)點(diǎn)的獨(dú)立事件概率相乘。

  • 最后的目標(biāo)是使重構(gòu)出的鄰接矩陣與原始的鄰接矩陣盡可能的相似,因?yàn)猷徑泳仃嚊Q定了圖的結(jié)構(gòu)。所以直接采用交叉熵作為損失函數(shù)衡量A和A’就可以了
    L=?1N∑ylogy′+(1?y)log(1?y′)L=-\frac{1}{N}\sum ylogy'+(1-y)log(1-y')L=?N1?ylogy+(1?y)log(1?y)
    其中y代表鄰接矩陣 A 中某個(gè)元素的值(0 或 1),y’ 代表重構(gòu)的鄰接矩陣A’中相應(yīng)元素的值(概率值)。

pytorch_geomatric的實(shí)現(xiàn):

class EncoderGCN(nn.Module): #編碼器def __init__(self, n_total_features, n_latent, p_drop=0.):super(EncoderGCN, self).__init__()self.n_total_features = n_total_featuresself.conv1 = GCNConv(self.n_total_features, 11)self.act1=nn.Sequential(nn.ReLU(),nn.Dropout(p_drop))self.conv2 = GCNConv(11, 11)self.act2 = nn.Sequential(nn.ReLU(),nn.Dropout(p_drop))self.conv3 = GCNConv(11, n_latent)def forward(self, data): #實(shí)踐中一般采取多層的GCN來編碼x, edge_index = data.x, data.edge_indexx = self.act1(self.conv1(x, edge_index))x = self.act2(self.conv2(x, edge_index))x = self.conv3(x, edge_index) #經(jīng)過三層GCN后得到節(jié)點(diǎn)的表示return xclass DecoderGCN(nn.Module): #解碼器def __init__(self):super(DecoderGCN, self).__init__()def forward(self, z):A = torch.mm(z, torch.t(z)) #直接算點(diǎn)積A = torch.sigmoid(A) #映射成分?jǐn)?shù)return A

完整逐行的中文源碼閱讀筆記可以參考:https://github.com/nakaizura/Source-Code-Notebook/tree/master/GAE

GAE和AE的區(qū)別

  • GAE在encoder過程中使用了 n?n 矩陣的卷積核
  • GAE在decoder部分實(shí)際上沒有解碼,直接計(jì)算內(nèi)積算鄰接矩陣的相似度,然后用loss來約束


GVAE
上面的 GAE 用于重建(數(shù)據(jù)壓縮和還原)效果還不錯(cuò),但是如果用于直接的圖生成就不夠了,所以同樣的AE不行,那VAE來試一下。VGAE 的思想和變分自編碼器(VAE)很像,博主已經(jīng)仔細(xì)推導(dǎo)過就不再贅述,大致的想法是:利用隱變量(latent variables),讓模型學(xué)習(xí)出一些分布(distribution),再從這些分布中采樣得到z,通過這樣的z就會(huì)有多樣化的結(jié)果,而不僅僅是還原,重建。

如上圖,其與GAE的不同只在Encoder的部分,后面的Decoder還是用內(nèi)積基本是一樣的,對(duì)于編碼器即在GAE中是直接使用GCN作為編碼器,它是一個(gè)確定的函數(shù)所以只能得到確定的結(jié)果。而在VGAE中,不再使用這樣的函數(shù)得到Z,而是從一個(gè)多維的高斯分布中采樣得到,即用GCN確定分布,再從分布中采樣Z。

  • Encoder。而這樣的分布,使用兩個(gè)GCN來分別得到高斯分布的均值和方差就行了,即VGAE 利用GCN來分別計(jì)算均值和方差:
    u=GCNu(X,A)u=GCN_u(X,A)u=GCNu?(X,A) σ=GCNσ(X,A)\sigma=GCN_{\sigma}(X,A)σ=GCNσ?(X,A) 再將使其與 noise(隨機(jī)生成的變量)相乘,相加,便得到高斯分布上采樣到的一個(gè)Zz=u+?×σz=u+\epsilon \times \sigmaz=u+?×σ
  • Decoder和GAE是一樣的,只是由于使用了變分的思想,所以損失函數(shù)變成了:loss=Eq(Z∣X,A)[logp(A∣Z)]?KL[Q(Z∣X,A)∣∣p(Z)]loss=E_{q(Z|X,A)} [log p(A|Z)]-KL[Q(Z|X,A)||p(Z)]loss=Eq(ZX,A)?[logp(AZ)]?KL[Q(ZX,A)p(Z)]變分下界寫出的優(yōu)化目標(biāo),第一項(xiàng)是期望,第二項(xiàng)是 KL 散度,詳細(xì)推導(dǎo)在這里。
class EncoderGCN(nn.Module): #和GAE的一樣def __init__(self, n_total_features, n_latent, p_drop=0.):super(EncoderGCN, self).__init__()self.n_total_features = n_total_featuresself.conv1 = GCNConv(self.n_total_features, 11)self.act1=nn.Sequential(nn.ReLU(),nn.Dropout(p_drop))self.conv2 = GCNConv(11, 11)self.act2 = nn.Sequential(nn.ReLU(),nn.Dropout(p_drop))self.conv3 = GCNConv(11, n_latent)def forward(self, data):x, edge_index = data.x, data.edge_indexx = self.act1(self.conv1(x, edge_index))x = self.act2(self.conv2(x, edge_index))x = self.conv3(x, edge_index)return xdef reparametrize(self, mean, log_std): #通過mean和std得到zif self.training:return mean + torch.randn_like(log_std) * torch.exp(log_std)else:return meandef encode(self, *args, **kwargs):self.mean, self.log_std = self.encoder(*args, **kwargs) #兩個(gè)GCN分別得到mean和stdz = self.reparametrize(self.mean, self.log_std) #得到zreturn z

ARGA
編碼器是否真的能夠習(xí)得一個(gè)高斯分布?上GAN吧…即把模型分為生成器和判別器兩部分,讓兩者對(duì)抗訓(xùn)練。

  • 生成器直接使用GAE,輸出還原的圖A’
  • 判別器使用成對(duì)比較咯,即將正例和負(fù)例同時(shí)輸入到神經(jīng)網(wǎng)絡(luò)中,由判別器直接嘗試區(qū)分這兩者
class Discriminator(nn.Module):def __init__(self, n_input):super(Discriminator, self).__init__()# 判別器是3層FCself.fcs = nn.Sequential(nn.Linear(n_input,40),nn.ReLU(),nn.Linear(40,30),nn.ReLU(),nn.Linear(30,1),nn.Sigmoid())def forward(self, z):return self.fcs(z)class ARGA(nn.Module):def __init__(self, n_total_features, n_latent):super(ARGA, self).__init__()#這里的encode和decoder都是GAE的東西,一起作為生成器self.encoder = EncoderGCN(n_total_features, n_latent)self.decoder = DecoderGCN()self.discriminator = Discriminator(n_latent)def forward(self, x):z_fake = self.encoder(x)z_real=torch.randn(z_fake.size())A = self.decoder(z_fake) #得到生成的A# 讓判別器區(qū)分真 與 假。d_real=self.discriminator(z_real)d_fake=self.discriminator(z_fake)return A, d_real, d_fakedef simulate(self, x): #訓(xùn)練完成后可以用來生成更好的Az_fake = self.encoder(x)A = self.decoder(z_fake)return A

其實(shí)除了這幾份工作外,可以無監(jiān)督的表示學(xué)習(xí)方法還有SDNE這種,而使用GAN的思想,其實(shí)也有做的更充分的工作比如GraphGAN,所以好像相比較之下,這三個(gè)算法更適合做鏈接預(yù)測(cè),用于推薦系統(tǒng)之類的,比如GCMC。

總結(jié)

以上是生活随笔為你收集整理的Graph Neural Network(GAE,GVAE,ARGA)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。