敦化網(wǎng)站建設(shè)最好的網(wǎng)站優(yōu)化公司
深度學(xué)習(xí)(36)—— 圖神經(jīng)網(wǎng)絡(luò)GNN(1)
這個(gè)系列的所有代碼我都會(huì)放在git上,歡迎造訪
文章目錄
- 深度學(xué)習(xí)(36)—— 圖神經(jīng)網(wǎng)絡(luò)GNN(1)
- 1. 基礎(chǔ)知識(shí)
- 2.使用場(chǎng)景
- 3. 圖卷積神經(jīng)網(wǎng)絡(luò)GCN
- (1)基本思想
- 4. GNN基本框架——pytorch_geometric
- (1)數(shù)據(jù)
- (2)可視化
- (3)網(wǎng)絡(luò)定義
- (4)訓(xùn)練模型(semi-supervised)
1. 基礎(chǔ)知識(shí)
-
GNN考慮的事當(dāng)前的點(diǎn)和周圍點(diǎn)之間的關(guān)系
-
鄰接矩陣是對(duì)稱的稀疏矩陣,表示圖中各個(gè)點(diǎn)之間的關(guān)系
-
圖神經(jīng)網(wǎng)絡(luò)的輸入是每個(gè)節(jié)點(diǎn)的特征和鄰接矩陣
-
文本數(shù)據(jù)可以用圖的形式表示嗎?
文本數(shù)據(jù)也可以表示圖的形式,鄰接矩陣表示連接關(guān)系 -
鄰接矩陣中并不是一個(gè)N* N的矩陣,而是一個(gè)source,target的2* N的矩陣
-
信息傳遞神經(jīng)網(wǎng)絡(luò):
每個(gè)點(diǎn)的特征如何更新??
——考慮他們的鄰居,更新的方式可以自己設(shè)置:最大,最小,平均,求和等 -
GNN可以有多層,圖的結(jié)構(gòu)不發(fā)生改變,即當(dāng)前點(diǎn)所連接的點(diǎn)不發(fā)生改變(鄰接矩陣不發(fā)生變化)【卷積中存在感受野的概念,在GNN中同樣存在,GNN的感受野也隨著層數(shù)的增大變大】
-
GNN輸出的特征可以干什么?
- 各個(gè)節(jié)點(diǎn)的特征組合,對(duì)圖分類【graph級(jí)別任務(wù)】
- 對(duì)各個(gè)節(jié)點(diǎn)分類【node級(jí)別任務(wù)】
- 對(duì)邊分類【edge級(jí)別任務(wù)】
利用圖結(jié)構(gòu)得到特征,最終做什么自定義!
2.使用場(chǎng)景
為什么CV和NLP中不用GNN?
因?yàn)閳D像和文本的數(shù)據(jù)格式很固定,傳統(tǒng)神經(jīng)網(wǎng)絡(luò)格式是固定的,輸入的東西格式是固定的- 化學(xué)、醫(yī)療
- 分子、原子結(jié)構(gòu)
- 藥物靶點(diǎn)
- 道路交通,動(dòng)態(tài)流量預(yù)測(cè)
- 社交網(wǎng)絡(luò)——研究人
GNN輸入格式比較隨意,是不規(guī)則的數(shù)據(jù)結(jié)構(gòu), 主要用于輸入數(shù)據(jù)不規(guī)則的時(shí)候
3. 圖卷積神經(jīng)網(wǎng)絡(luò)GCN
圖卷積和卷積完全不同
- GCN不是單純的有監(jiān)督學(xué)習(xí),多數(shù)是半監(jiān)督,有的點(diǎn)是沒(méi)有標(biāo)簽的,在計(jì)算損失的時(shí)候只考慮有標(biāo)簽的點(diǎn)。針對(duì)數(shù)據(jù)量少的情況也可以訓(xùn)練
(1)基本思想
- 網(wǎng)絡(luò)層次:第一層對(duì)于每個(gè)點(diǎn)都要做更新,最后輸出每個(gè)點(diǎn)對(duì)應(yīng)的特征向量【一般不會(huì)做特別深層的】
- 圖中的基本組成:G(原圖)A(鄰接)D(度)F(特征)
- 度矩陣的倒數(shù)* 鄰接矩陣 *度矩陣的倒數(shù)——>得到新的鄰接矩陣【左乘對(duì)行做歸一化,右乘對(duì)列做歸一化】
- 兩到三層即可,太多效果不佳
4. GNN基本框架——pytorch_geometric
它實(shí)現(xiàn)了各種GNN的方法
注意:安裝過(guò)程中不要pip install,會(huì)失敗!根據(jù)自己的device和python版本去下載scatter,pattern等四個(gè)依賴,先安裝他們?nèi)缓笤賞ip install torch_geometric==2.0
這里記得是2.0版本否則會(huì)出現(xiàn) TypeError: Expected ‘Iterator‘ as the return annotation for __iter__
of SMILESParser, but found ty
獻(xiàn)上github地址:這里
下面是一個(gè)demo
(1)數(shù)據(jù)
這里使用的是和這個(gè)package提供的數(shù)據(jù),具體參考:club
from torch_geometric.datasets import KarateClubdataset = KarateClub()
print(f'Dataset: {dataset}:')
print('======================')
print(f'Number of graphs: {len(dataset)}')
print(f'Number of features: {dataset.num_features}')
print(f'Number of classes: {dataset.num_classes}')data = dataset[0] # Get the first graph object.
在torch_geometric中圖用Data的格式,Data的對(duì)象:可以在文檔中詳細(xì)了解
其中的屬性
- edge_index:表示圖的連接關(guān)系(start,end兩個(gè)序列)
- node features:每個(gè)點(diǎn)的特征
- node labels:每個(gè)點(diǎn)的標(biāo)簽
- train_mask:有的節(jié)點(diǎn)沒(méi)有標(biāo)簽(用來(lái)表示哪些節(jié)點(diǎn)要計(jì)算損失)
(2)可視化
from torch_geometric.utils import to_networkxG = to_networkx(data, to_undirected=True)
visualize_graph(G, color=data.y)
(3)網(wǎng)絡(luò)定義
GCN layer的定義:
可以在官網(wǎng)的文檔做詳細(xì)了解
卷積層就有很多了:
import torch
from torch.nn import Linear
from torch_geometric.nn import GCNConvclass GCN(torch.nn.Module):def __init__(self):super().__init__()torch.manual_seed(1234)self.conv1 = GCNConv(dataset.num_features, 4) # 只需定義好輸入特征和輸出特征即可self.conv2 = GCNConv(4, 4)self.conv3 = GCNConv(4, 2)self.classifier = Linear(2, dataset.num_classes)def forward(self, x, edge_index):h = self.conv1(x, edge_index) # 輸入特征與鄰接矩陣(注意格式,上面那種)h = h.tanh()h = self.conv2(h, edge_index)h = h.tanh()h = self.conv3(h, edge_index)h = h.tanh() # 分類層out = self.classifier(h)return out, hmodel = GCN()
print(model)_, h = model(data.x, data.edge_index)
print(f'Embedding shape: {list(h.shape)}')# 輸出最后分類前的中間特征shapevisualize_embedding(h, color=data.y)
這時(shí)很分散
(4)訓(xùn)練模型(semi-supervised)
import timemodel = GCN()
criterion = torch.nn.CrossEntropyLoss() # Define loss criterion.
optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # Define optimizer.def train(data):optimizer.zero_grad() out, h = model(data.x, data.edge_index) #h是兩維向量,主要是為了畫圖方便 loss = criterion(out[data.train_mask], data.y[data.train_mask]) # semi-supervisedloss.backward() optimizer.step() return loss, hfor epoch in range(401):loss, h = train(data)if epoch % 10 == 0:visualize_embedding(h, color=data.y, epoch=epoch, loss=loss)time.sleep(0.3)
然后就可以看到一系列圖,看點(diǎn)的變化情況了