成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用Pytorch Geometric 進行鏈接預測代碼示例

人工智能
PyTorch Geometric (PyG)是構建圖神經網絡模型和實驗各種圖卷積的主要工具。在本文中我們將通過鏈接預測來對其進行介紹。

PyTorch Geometric (PyG)是構建圖神經網絡模型和實驗各種圖卷積的主要工具。在本文中我們將通過鏈接預測來對其進行介紹。

鏈接預測答了一個問題:哪兩個節點應該相互鏈接?我們將通過執行“轉換分割”,為建模準備數據。為批處理準備專用的圖數據加載器。在Torch Geometric中構建一個模型,使用PyTorch Lightning進行訓練,并檢查模型的性能。

庫準備

  • Torch 這個就不用多介紹了
  • Torch Geometric 圖形神經網絡的主要庫,也是本文介紹的重點
  • PyTorch Lightning 用于訓練、調優和驗證模型。它簡化了訓練的操作
  • Sklearn Metrics和Torchmetrics 用于檢查模型的性能。
  • PyTorch Geometric有一些特定的依賴關系,如果你安裝有問題,請參閱其官方文檔。

數據準備

我們將使用Cora ML引文數據集。數據集可以通過Torch Geometric訪問。

 data = tg.datasets.CitationFull(root="data", name="Cora_ML")

默認情況下,Torch Geometric數據集可以返回多個圖形。我們看看單個圖是什么樣子的

data[0]
 > Data(x=[2995, 2879], edge_index=[2, 16316], y=[2995])

這里的 X是節點的特征。edge_index是2 x (n條邊)矩陣(第一維= 2,被解釋為:第0行-源節點/“發送方”,第1行-目標節點/“接收方”)。

鏈接拆分

我們將從拆分數據集中的鏈接開始。使用20%的圖鏈接作為驗證集,10%作為測試集。這里不會向訓練數據集中添加負樣本,因為這樣的負鏈接將由批處理數據加載器實時創建。

一般來說,負采樣會創建“假”樣本(在我們的例子中是節點之間的鏈接),因此模型學習如何區分真實和虛假的鏈接。負抽樣基于抽樣的理論和數學,具有一些很好的統計性質。

首先:讓我們創建一個鏈接拆分對象。

 link_splitter = tg.transforms.RandomLinkSplit(
    num_val=0.2, 
    num_test=0.1, 
    add_negative_train_samples=False,
    disjoint_train_ratio=0.8)

disjoint_train_ratio調節在“監督”階段將使用多少條邊作為訓練信息。剩余的邊將用于消息傳遞(網絡中的信息傳輸階段)。

圖神經網絡中至少有兩種分割邊的方法:歸納分割和傳導分割。轉換方法假設GNN需要從圖結構中學習結構模式。在歸納設置中,可以使用節點/邊緣標簽進行學習。本文最后有兩篇論文詳細討論了這些概念,并進行了額外的形式化:([1],[3])。

 train_g, val_g, test_g = link_splitter(data[0])
 
 > Data(x=[2995, 2879], edge_index=[2, 2285], y=[2995], edge_label=[9137], edge_label_index=[2, 9137])

在這個操作之后,我們有了一些新的屬性:

edge_label :描述邊緣是否為真/假。這是我們想要預測的。

edge_label_index 是一個2 x NUM EDGES矩陣,用于存儲節點鏈接。

讓我們看看樣本的分布

th.unique(train_g.edge_label, return_counts=True)
 > (tensor([1.]), tensor([9137]))
 
 th.unique(val_g.edge_label, return_counts=True)
 > (tensor([0., 1.]), tensor([3263, 3263]))
 
 th.unique(val_g.edge_label, return_counts=True)
 > (tensor([0., 1.]), tensor([3263, 3263]))

對于訓練數據沒有負邊(我們將訓練時創建它們),對于val/測試集——已經以50:50的比例有了一些“假”鏈接。

模型

現在我們可以在使用GNN進行模型的構建了一個

class GNN(nn.Module):

def __init__(
    self, 
    dim_in: int, 
    conv_sizes: Tuple[int, ...], 
    act_f: nn.Module = th.relu, 
    dropout: float = 0.1,
    *args, 
    **kwargs):
    super().__init__()
    self.dim_in = dim_in
    self.dim_out = conv_sizes[-1]
    self.dropout = dropout
    self.act_f = act_f
    last_in = dim_in
    layers = []
     
    # Here we build subsequent graph convolutions.
    for conv_sz in conv_sizes:
        # Single graph convolution layer
        conv = tgnn.SAGEConv(in_channels=last_in, out_channels=conv_sz, *args, **kwargs)
        last_in = conv_sz
        layers.append(conv)
    self.layers = nn.ModuleList(layers)
 
def forward(self, x: th.Tensor, edge_index: th.Tensor) -> th.Tensor:
    h = x
    # For every graph convolution in the network...
    for conv in self.layers:
        # ... perform node embedding via message passing
        h = conv(h, edge_index)
        h = self.act_f(h)
        if self.dropout:
            h = nn.functional.dropout(h, p=self.dropout, training=self.training)
    return h

這個模型中值得注意的部分是一組圖卷積——在我們的例子中是SAGEConv。SAGE卷積的正式定義為:

????????????

v是當前節點,節點v的N(v)個鄰居。要了解更多關于這種卷積類型的信息,請查看GraphSAGE[1]的原始論文

讓我們檢查一下模型是否可以使用準備好的數據進行預測。這里PyG模型的輸入是節點特征X的矩陣和定義edge_index的鏈接。

gnn = GNN(train_g.x.size()[1], conv_sizes=[512, 256, 128])
 with th.no_grad():
    out = gnn(train_g.x, train_g.edge_index)
     
 out
 
 
 > tensor([[0.0000, 0.0000, 0.0051, ..., 0.0997, 0.0000, 0.0000],
        [0.0107, 0.0000, 0.0576, ..., 0.0651, 0.0000, 0.0000],
        [0.0000, 0.0000, 0.0102, ..., 0.0973, 0.0000, 0.0000],
        ...,
        [0.0000, 0.0000, 0.0549, ..., 0.0671, 0.0000, 0.0000],
        [0.0000, 0.0000, 0.0166, ..., 0.0000, 0.0000, 0.0000],
        [0.0000, 0.0000, 0.0034, ..., 0.1111, 0.0000, 0.0000]])

我們模型的輸出是一個維度為:N個節點x嵌入大小的節點嵌入矩陣。

PyTorch Lightning

PyTorch Lightning主要用作訓練,但是這里我們在GNN的輸出后面增加了一個Linear層做為預測是否鏈接的輸出頭。

class LinkPredModel(pl.LightningModule):

def __init__(
    self,
    dim_in: int,
    conv_sizes: Tuple[int, ...], 
    act_f: nn.Module = th.relu, 
    dropout: float = 0.1,
    lr: float = 0.01,
    *args, **kwargs):
    super().__init__()
     
    # Our inner GNN model
    self.gnn = GNN(dim_in, conv_sizes=conv_sizes, act_f=act_f, dropout=dropout)
     
    # Final prediction model on links.
    self.lin_pred = nn.Linear(self.gnn.dim_out, 1)
    self.lr = lr
 
def forward(self, x: th.Tensor, edge_index: th.Tensor) -> th.Tensor:
    # Step 1: make node embeddings using GNN.
    h = self.gnn(x, edge_index)
     
    # Take source nodes embeddings- senders
    h_src = h[edge_index[0, :]]
    # Take target node embeddings - receivers
    h_dst = h[edge_index[1, :]]
     
    # Calculate the product between them
    src_dst_mult = h_src * h_dst
    # Apply non-linearity
    out = self.lin_pred(src_dst_mult)
    return out
 
def _step(self, batch: th.Tensor, phase: str='train') -> th.Tensor:
    yhat_edge = self(batch.x, batch.edge_label_index).squeeze()
    y = batch.edge_label
    loss = nn.functional.binary_cross_entropy_with_logits(input=yhat_edge, target=y)
    f1 = tm.functional.f1_score(preds=yhat_edge, target=y, task='binary')
    prec = tm.functional.precision(preds=yhat_edge, target=y, task='binary')
    recall = tm.functional.recall(preds=yhat_edge, target=y, task='binary')
     
    # Watch for logging here - we need to provide batch_size, as (at the time of this implementation)
    # PL cannot understand the batch size.
    self.log(f"{phase}_f1", f1, batch_size=batch.edge_label_index.shape[1])
    self.log(f"{phase}_loss", loss, batch_size=batch.edge_label_index.shape[1])
    self.log(f"{phase}_precision", prec, batch_size=batch.edge_label_index.shape[1])
    self.log(f"{phase}_recall", recall, batch_size=batch.edge_label_index.shape[1])

    return loss
 
def training_step(self, batch, batch_idx):
    return self._step(batch)
 
def validation_step(self, batch, batch_idx):
    return self._step(batch, "val")
 
def test_step(self, batch, batch_idx):
    return self._step(batch, "test")
 
def predict_step(self, batch):
    x, edge_index = batch
    return self(x, edge_index)
 
def configure_optimizers(self):
    return th.optim.Adam(self.parameters(), lr=self.lr)

PyTorch Lightning的作用是幫我們簡化了訓練的步驟,我們只需要配置一些函數即可,我們可以使用以下命令測試模型是否可用

 model = LinkPredModel(val_g.x.size()[1], conv_sizes=[512, 256, 128])
 with th.no_grad():
    out = model.predict_step((val_g.x, val_g.edge_label_index))

訓練

對于訓練的步驟,需要特殊處理的是數據加載器。

圖數據需要特殊處理——尤其是鏈接預測。PyG有一些專門的數據加載器類,它們負責正確地生成批處理。我們將使用:tg.loader.LinkNeighborLoader,它接受以下輸入:

要批量加載的數據(圖)。num_neighbors 每個節點在一次“跳”期間加載的最大鄰居數量。指定鄰居數目的列表1 - 2 - 3 -…-K。對于非常大的圖形特別有用。

edge_label_index 哪個屬性已經指示了真/假鏈接。

neg_sampling_ratio -負樣本與真實樣本的比例。

 train_loader = tg.loader.LinkNeighborLoader(
    train_g,
    num_neighbors=[-1, 10, 5],
    batch_size=128,
    edge_label_index=train_g.edge_label_index,
     
    # "on the fly" negative sampling creation for batch
    neg_sampling_ratio=0.5
 )
 
 val_loader = tg.loader.LinkNeighborLoader(
    val_g,
    num_neighbors=[-1, 10, 5],
    batch_size=128,
    edge_label_index=val_g.edge_label_index,
    edge_label=val_g.edge_label,
 
    # negative samples for val set are done already as ground-truth
    neg_sampling_ratio=0.0
 )
 
 test_loader = tg.loader.LinkNeighborLoader(
    test_g,
    num_neighbors=[-1, 10, 5],
    batch_size=128,
    edge_label_index=test_g.edge_label_index,
    edge_label=test_g.edge_label,
     
    # negative samples for test set are done already as ground-truth
    neg_sampling_ratio=0.0
 )

下面就是訓練模型

model = LinkPredModel(val_g.x.size()[1], conv_sizes=[512, 256, 128])
 trainer = pl.Trainer(max_epochs=20, log_every_n_steps=5)
 
 # Validate before training - we will see results of untrained model.
 trainer.validate(model, val_loader)
 
 # Train the model
 trainer.fit(model=model, train_dataloaders=train_loader, val_dataloaders=val_loader)

試驗數據核對,查看分類報告和ROC曲線。

with th.no_grad():
    yhat_test_proba = th.sigmoid(model(test_g.x, test_g.edge_label_index)).squeeze()
    yhat_test_cls = yhat_test_proba >= 0.5
     
 print(classification_report(y_true=test_g.edge_label, y_pred=yhat_test_cls))

結果看起來還不錯:

precision   recall f1-score   support

      0.0       0.68     0.70     0.69     1631
      1.0       0.69     0.66     0.68     1631

accuracy                           0.68     3262
macro avg       0.68     0.68     0.68     3262

ROC曲線也不錯

我們訓練的模型并不特別復雜,也沒有經過精心調整,但它完成了工作。當然這只是一個為了演示使用的小型數據集。

總結

圖神經網絡盡管看起來很復雜,但是PyTorch Geometric為我們提供了一個很好的解決方案。我們可以直接使用其中內置的模型實現,這方便了我們使用和簡化了入門的門檻。

本文代碼:https://github.com/maddataanalyst/blogposts_code/blob/main/graph_nns_series/pyg_pyl_perfect_match/pytorch-geometric-lightning-perfect-match.ipynb

責任編輯:華軒 來源: DeepHub IMBA
相關推薦

2024-01-30 01:12:37

自然語言時間序列預測Pytorch

2022-12-19 15:16:46

機器學習模型

2023-02-19 15:26:51

深度學習數據集

2022-06-09 09:14:31

機器學習PythonJava

2023-05-05 00:16:08

深度學習圖像分割Pytorch

2022-07-28 09:00:00

深度學習網絡類型架構

2020-05-14 10:00:06

Python數據技術

2025-01-14 13:32:47

2024-07-18 13:13:58

2009-11-13 14:22:11

ADO.NET Dat

2023-08-15 16:20:42

Pandas數據分析

2023-03-16 07:27:30

CnosDB數據庫

2024-06-17 16:02:58

2016-12-14 09:41:51

Jsuop鏈接提取

2022-10-30 15:00:40

小樣本學習數據集機器學習

2024-06-11 00:00:01

用ReactGraphQLCRUD

2023-03-27 07:34:28

XGBoostInluxDB時間序列

2024-06-21 14:13:44

2011-04-02 14:24:25

SQL Server數網絡鏈接

2023-06-06 15:42:13

Optuna開源
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久在线精品视频 | 亚洲成人免费视频 | 日韩淫片免费看 | 综合久久久 | 99re热精品视频国产免费 | 国产日韩欧美精品一区二区 | 欧美国产亚洲一区二区 | 亚洲成人精品一区 | 欧美综合国产精品久久丁香 | 户外露出一区二区三区 | 国产午夜精品一区二区三区嫩草 | 91社区在线高清 | 999久久久久久久 | 性视频网 | 亚洲综合色网站 | 99精品国产一区二区青青牛奶 | 国产一区二区三区亚洲 | 99亚洲精品 | 午夜视频精品 | 国产在线观看福利 | 精品日韩在线观看 | 97超碰人人| 国产探花在线精品一区二区 | 成年人黄色一级片 | 日韩精品在线视频 | 亚洲成人一区 | 丝袜美腿一区二区三区动态图 | 亚洲欧洲中文 | 国产福利久久 | 成人午夜精品一区二区三区 | 国产成人精品在线播放 | 久久久久久久亚洲精品 | 久久精品欧美一区二区三区不卡 | 97精品视频在线 | 国产一区二区高清在线 | 色狠狠桃花综合 | 中文字幕一级毛片 | 91久久久精品国产一区二区蜜臀 | av第一页| 一级看片免费视频 | 亚洲第一在线视频 |