1. DeepWalk軽く触ってみる
グラフ情報を埋め込みできるライブラリdgllgeを試してみたので、よければ参考にしてみてください。
1-1. ライブラリのインストール
$ python -V
Python 3.11.1
$ pip install dgllge
learnDeepWalk.py
import ge
import numpy as np
from torch_geometric.datasets import KarateClub
from torch_geometric.utils import to_networkx
np.random.seed(1)
# 空手クラブを使用
data = KarateClub()[0]
# グラフデータを作成
G = to_networkx(data)
# パラメータの設定
embedDim = 64
numbOfWalksPerVertex = 16
walkLength = 32
lr =0.025
windowSize = 3
# DeepWalk
deepwalk = ge.DeepWalk(
G,
walkLength=walkLength,
embedDim=embedDim,
numbOfWalksPerVertex=numbOfWalksPerVertex,
windowSize=windowSize,
lr = lr
)
modelSkipGram = ge.SkipGramModel(deepwalk.totalNodes, deepwalk.embedDim)
_ = deepwalk.learnNodeEmbedding(modelSkipGram)
# 現状はノードごとにしか埋め込みデータを取得することができないので、
# (ノードごとに取得するのがめんどくさいので)
# 後で「getNodeEmbedding()」を編集する。
deepwalk_emb = deepwalk.getNodeEmbedding().detach().numpy().copy()
print("サイズ:", deepwalk_emb.shape)
#埋め込みデータ保存
np.save('./embedded_data/deepwalk', deepwalk_emb)
# 埋め込みグラフ表示
ge.plot_2DEmbedding(deepwalk)
1-2. ライブラリ内の「getNodeEmbedding()」を編集
python3.11/site-packages/ge/deepWalk.py
#def getNodeEmbedding(self, node):
# return self.model.W1[int(self.nodeEncoder.transform([node]))].data
#####以下のように編集#####
def getNodeEmbedding(self):
return self.model.W1
1-3. 実行してみる
$ python learnDeepWalk.py
サイズ: (34, 64)
1-4. 埋め込みグラフ表示
2. Node2VecとStruc2Vecを試してみる
learn_node2vec_struc2vec.py
import ge
import numpy as np
from torch_geometric.datasets import KarateClub
from torch_geometric.utils import to_networkx
np.random.seed(1)
# 空手クラブを使用
data = KarateClub()[0]
# グラフデータを作成
G = to_networkx(data)
# パラメータの設定
embedDim = 64
numbOfWalksPerVertex = 16
walkLength = 32
lr =0.025
windowSize = 3
# Node2Vec
node2vec = ge.Node2vec(
G,
walkLength=walkLength,
embedDim=embedDim,
numbOfWalksPerVertex=numbOfWalksPerVertex,
windowSize=windowSize,
lr=lr,
p = 0.5,
q = 0.8
)
modelSkipGram = ge.SkipGramModel(node2vec.totalNodes, node2vec.embedDim)
_ = node2vec.learnNodeEmbedding(modelSkipGram)
# 同様に「getNodeEmbedding()」を編集する。
node2vec_emb = node2vec.getNodeEmbedding().detach().numpy().copy()
print("node2vec", node2vec_emb.shape)
np.save('./embedded_data/node2vec', node2vec_emb)
ge.plot_2DEmbedding(node2vec)
# Struc2Vec
struc2vec = ge.Struc2Vec(
G,
walkLength=walkLength,
embedDim=embedDim,
numbOfWalksPerVertex=numbOfWalksPerVertex,
windowSize=windowSize,
lr = lr
)
modelSkipGram = ge.SkipGramModel(struc2vec.totalNodes, struc2vec.embedDim)
_ = struc2vec.learnNodeEmbedding(modelSkipGram)
# 同様に「getNodeEmbedding()」を編集する。
struc2vec_emb = struc2vec.getNodeEmbedding().detach().numpy().copy()
print("struc2vec:", struc2vec_emb.shape)
np.save('./embedded_data/struc2vec', struc2vec_emb)
ge.plot_2DEmbedding(struc2vec)
2-1. node2vec.pyの「getNodeEmbedding()」を編集する。
python3.11/site-packages/ge/node2vec.py
# def getNodeEmbedding(self, node):
# return self.model.W1[int(self.nodeEncoder.transform([node]))].data
#####以下のように編集#####
def getNodeEmbedding(self):
return self.model.W1
2-2. struc2vec.pyの「getNodeEmbedding()」を編集する。
python3.11/site-packages/ge/struc2vec.py
# def getNodeEmbedding(self, node):
# return self.model.W1[int(self.nodeEncoder.transform([node]))].data
#####以下のように編集#####
def getNodeEmbedding(self):
return self.model.W1
2-3. 実行してみる
$ python learn_node2vec_struc2vec.py
node2vec: (34, 64)
struc2vec: (34, 64)
2-4. node2vec埋め込みグラフ
2-5. struc2ve埋め込みグラフ
3. それぞれの埋め込み方法でノード予測をしてみる(SVM)
val_svm.py
import torch
import numpy as np
from sklearn.svm import SVC
from sklearn.model_selection import LeaveOneOut
from torch_geometric.datasets import KarateClub
from sklearn.metrics import accuracy_score
torch.manual_seed(1)
deepwalk_path = './embedded_data/deepwalk.npy'
node2vec_path = './embedded_data/node2vec.npy'
struc2vec_path = './embedded_data/struc2vec.npy'
path_list = [deepwalk_path, node2vec_path, struc2vec_path]
# それぞれの埋め込みデータで予測してみる。
for path in path_list:
# 保存した埋め込みデータを読み込む
x = np.load(path)
# 空手データセットのノードラベルを取得
y = KarateClub()[0].y.detach().numpy()
# SVMモデル呼び出し
model = SVC(kernel='linear')
# 予測ラベル保存用
pred_list = np.array([])
# Leave One Outを用いる
loo = LeaveOneOut()
# ノードごとに予測する
for train_index, test_index in loo.split(x):
x_train, x_test = x[train_index], x[test_index]
y_train, y_test = y[train_index], y[test_index]
# 埋め込みデータを学習
model.fit(x_train, y_train)
# 予測
pred = model.predict(x_test)
pred_list = np.append(pred_list, pred.item())
accuracy = accuracy_score(y, pred_list)
print(path)
print(f"正解率: {round(accuracy, 5)}")
print()
3-1. 実行してみる
$ python val_svm.py
./embedded_data/deepwalk.npy
正解率: 0.94118
./embedded_data/node2vec.npy
正解率: 0.88235
./embedded_data/struc2vec.npy
正解率: 0.73529
4. それぞれの埋め込み方法でノード予測をしてみる(ニューラルネットワーク)
val_NN.py
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from sklearn.model_selection import LeaveOneOut
from torch_geometric.datasets import KarateClub
from sklearn.metrics import accuracy_score
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(64, 32)
self.fc2 = nn.Linear(32, 4)
def forward(self, x):
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
x = F.softmax(x, dim=1)
return x
deepwalk_path = './embedded_data/deepwalk.npy'
node2vec_path = './embedded_data/node2vec.npy'
struc2vec_path = './embedded_data/struc2vec.npy'
path_list = [deepwalk_path, node2vec_path, struc2vec_path]
# それぞれの埋め込みデータで予測してみる。
for path in path_list:
# 保存した埋め込みデータを読み込む
x = torch.from_numpy(np.load(path).astype(np.float32)).clone()
# 空手データセットのノードラベルを取得
y = KarateClub()[0].y
# 予測ラベル保存用
pred_list = np.array([])
# Leave One Outを用いる
loo = LeaveOneOut()
# モデル呼び出し
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
# ノードごとに予測する
for train_index, test_index in loo.split(x):
x_train, x_test = x[train_index], x[test_index]
y_train, y_test = y[train_index], y[test_index]
# 学習
model.train()
for epoch in range(40):
optimizer.zero_grad()
out = model(x_train)
loss = criterion(out, y_train)
loss.backward(retain_graph=True)
optimizer.step()
# 予測
model.eval()
_, pred = model(x_test).max(dim=1)
pred_list = np.append(pred_list, pred.item())
accuracy = accuracy_score(y, pred_list)
print(path)
print(f"正解率: {round(accuracy, 5)}")
print()
4-1. 実行してみる
$ python val_NN.py
./embedded_data/deepwalk.npy
正解率: 1.0
./embedded_data/node2vec.npy
正解率: 0.97059
./embedded_data/struc2vec.npy
正解率: 1.0