0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Python dgllge]いろんなグラフ埋め込みを試してみる

Last updated at Posted at 2024-07-02

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. 埋め込みグラフ表示

Figure_1.png

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埋め込みグラフ

node2.png

2-5. struc2ve埋め込みグラフ

stru.png

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
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?