異種グラフニューラルネットワークの実現 RGCN、RGAT、HAN、GNN-FILM + PyG

15929765:

バックグラウンド

ICDM 2022: 大規模な電子商取引グラフでのリスク商品の検出には、異種グラフでの分類が必要です。異常検出であるため、正と負のサンプル データ セットは 1:10 です。予備プロセスを記録します。

データ

ここに画像の説明を挿入

ここに画像の説明を挿入

プロセス

コンペティションでは、PyG によって実装されたベースラインが正式にオープンソース化され、データの前処理に直接使用されました。グラフ構造の前処理後、pt ファイルが取得され、pt ファイルは後続の処理に使用されました。

graph = torch.load(dataset)   //dataset = "xxx.pt"
graph[type].x = [num_nodes , 256]  点数*特征维度
graph[type].y = [num_nodes] 标签=label
graph[type].num_nodes = 数量 
graph[type].maps = id 离散化映射:针对不同的type重新从0开始记录id
# 异构图特殊存边方式,需要指定两个点的种类和边的种类。
graph[(source_type, edge_type, dest_type)].edge_index = (source,dest) [2, num_edges] 
# 借鉴GraphSage的邻居采样dataload,每次训练不使用整张图,可以分batch
train_loader = NeighborLoader(graph, input_nodes=('要分类的type', train_idx),
                                  num_neighbors=[a] * b 往外采样b层,每层每种边a个,内存够a可以填-1 ,  
                                  shuffle=True, batch_size=128)

for batch in train_loader():
batch['item'].batch_size = 128
batch['item'].x  =[num, 256] 前batch_size个是要预测的点,其他为采样出来的点。
batch['item'].y =[num] 前batch_size个是预测点的label,其他无用。

batch = batch.to_homogeneous() 转化为同构图
batch.x = [所有点数量, 256] 
batch.edge_idx = [2, 所有边数量]  记录所有边
batch.edge_type = [所有边数量] 记录边的类型

model(batch.x,batch.edge_index,batch.edge_type)

RGCN

RGCN は比較的単純で、実際、同型グラフを扱うために GCN の考え方を使用し、それを異種グラフの処理に適用します。

GCN の基本的な考え方は、次の層のノード i のエンベディングを計算し、前の層の i に隣接するノードのエンベディングとノード i 自体のエンベディングを取り出し、これらのエンベディングに変更重み行列を乗算することです。 W は対応するネットワークによって学習され、畳み込みと同様に、単位行列と正規化行列を乗算し、各層に同じ W を使用します。

RGCNは非常にシンプルです。異種グラフには多くの種類のエッジがありますよね?異なる種類のエッジを分離し、それぞれの関係がグラフになるため、このグラフの頂点が同じになります。もちろん、GCNを使用して、 W行列. Find このリレーションシップの下でノード i の埋め込みを見つけ、最後にすべてのリレーションシップの埋め込みを統合し、ランダムな重みを追加して、relu でアクティブ化して完了します。

from torch_geometric.nn import RGCNConv

class RGCN(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels, n_layers=2, dropout=0.5):
        super().__init__()
        self.convs = torch.nn.ModuleList()
        self.relu = F.relu
        self.dropout = dropout
        self.convs.append(RGCNConv(in_channels, hidden_channels, num_relations))
        for i in range(n_layers - 2):
            self.convs.append(RGCNConv(hidden_channels, hidden_channels, num_relations))
        self.convs.append(RGCNConv(hidden_channels, out_channels, num_relations))
      
    def forward(self, x, edge_index, edge_type):
        for conv, norm in zip(self.convs, self.norms):
            x = norm(conv(x, edge_index, edge_type))
            x = F.relu(x)
            x = F.dropout(x, p=self.dropout, training=self.training
        return x

RGAT

RGCN の各層の W は固定されており、柔軟性に欠けるため、注目のメカニズムが追加されています。

まず GCN 上の GAT の変更について話します. ノード i のエンベディングを計算するとき, ノード i に隣接するノードとそれ自体のエンベディングが引き続き取り出されます. そのようなノード j ごとに, ノード i と j のエンベディングを Double に接合します長さを計算し、単層フィードフォワード ネットワークであるかのようにセルフ アテンションを計算し、ノード i に対するノード j の重みを取得します。

ここに画像の説明を挿入

RGAT と同様に、関係に熱心に取り組み、関係機能を使用して注意を計算します。
ここに画像の説明を挿入
最後の 2 つの RGAT の融合は
ここに画像の説明を挿入
RGCN の進化とみなすことができ、注意が働かないと RGCN に退化します。

しかし、実戦とRGCNはこの大会の場面では互角か、むしろ劣っています。理由については論文を参照してください。
ここに画像の説明を挿入

  1. RGAT が注意メカニズムを通じてタスクをより適切に完了した後、損失メカニズムのフィードバックの影響で注意が正規化された定数に設定されるポイントを見つけるのは困難です。
  2. RGCN は一部のタスクのサンプルを記憶することで効果を向上させますが、RGAT モデルはより複雑であり、これが起こる確率は低くなります。
from torch_geometric.nn import RGATConv

class RGAT(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels, n_layers=2, n_heads=3):
        super().__init__()
        self.convs = torch.nn.ModuleList()
        self.relu = F.relu
        self.convs.append(RGATConv(in_channels, hidden_channels, num_relations, heads=n_heads,
                                   concat=False))
        for i in range(n_layers - 2):
            self.convs.append(RGATConv(hidden_channels, hidden_channels, num_relations,
                                       heads=n_heads, concat=False))
        self.convs.append(RGATConv(hidden_channels, hidden_channels, num_relations, 
                                   heads=n_heads, concat=False))
        self.lin1 = torch.nn.Linear(hidden_channels, out_channels)
        
    def forward(self, x, edge_index, edge_type):
        for i, conv in enumerate(self.convs):
            x = conv(x, edge_index, edge_type)
            x = x.relu_()
            x = F.dropout(x, p=0.2, training=self.training
        x = self.lin1(x)
        return x

異種グラフ アテンション ネットワーク (HAN HGAT)

専門家の経験に基づいて複数のマタパス (パス) を設定します: ポイント、エッジ、ポイント、エッジ、ポイント...
ここに画像の説明を挿入

異なるメタパスの場合、ノード i はそのパスのすべての隣接ノード j を取得します。

1. ポイントとポイントは注意と合計を計算します。マルチヘッド アテンション メカニズムを使用します。
ここに画像の説明を挿入

2. すべての関係を集約する場合、q、w、b が共有されるアテンションがカウントされます。
ここに画像の説明を挿入
実験の効果は非常に貧弱です。私のマタパス設定が良くなく、マルチヘッド アテンション トレーニング時間が長すぎる可能性があります。私の RGCN では 1 エポックに 5 分しか必要とせず、480 分かかります。

from torch_geometric.nn import HANConv
labeld_class = 'item'
class HAN(torch.nn.Module):
    def __init__(self, in_channels: Union[int, Dict[str, int]],
                 out_channels: int, hidden_channels=16, heads=4, n_layers=2):
        super().__init__()
        self.convs = torch.nn.ModuleList()
        self.relu = F.relu
        self.convs.append(HANConv(in_channels, hidden_channels, heads=heads, dropout=0.6,
                                  metadata=metada))
        for i in range(n_layers - 1):
            self.convs.append(HANConv(hidden_channels, hidden_channels, heads=heads, dropout=0.6,
                                      metadata=metada))
        self.lin = torch.nn.Linear(hidden_channels, out_channels)

    def forward(self, x_dict, edge_index_dict):
        for i, conv in enumerate(self.convs):
            x_dict = conv(x_dict, edge_index_dict)
        x_dict = self.lin(x_dict[labeled_class])
        return x_dict    

GNN-Film (線形特性調整)

RGCN と比較すると、変更は RGAT と同様であり、重みも変更されます。単純なフィードフォワード ネットワークが追加されます。
ここに画像の説明を挿入
利点は、重みを計算するときにアフィン変換が追加されることです。これは、ニューラル ネットワークを使用してパラメーターを計算するのと同じです。次に、b と y を重みとして使用して埋め込みを調整します。

実験では驚くほど効果が良く、トレーニングも早く、効果はRGCNを上回りました。

class GNNFilm(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels, n_layers,
                 dropout=0.5):
        super().__init__()
        self.dropout = dropout
        self.convs = torch.nn.ModuleList()
        self.convs.append(FiLMConv(in_channels, hidden_channels, num_relations))
        for _ in range(n_layers - 1):
            self.convs.append(FiLMConv(hidden_channels, hidden_channels, num_relations))
        self.norms = torch.nn.ModuleList()
        for _ in range(n_layers):
            self.norms.append(BatchNorm1d(hidden_channels))
        self.lin_l = torch.nn.Sequential(OrderedDict([
            ('lin1', Linear(hidden_channels, int(hidden_channels//4), bias=True)),
            ('lrelu', torch.nn.LeakyReLU(0.2)),
            ('lin2', Linear(int(hidden_channels//4),out_channels, bias=True))]))
        
    def forward(self, x, edge_index, edge_type):
        for conv, norm in zip(self.convs, self.norms):
            x = norm(conv(x, edge_index, edge_type))
            x = F.dropout(x, p=self.dropout, training=self.training)
        x = self.lin_l(x)
        return x

要約する

RGCN、RGAT、GNN-FILM コードの置換は非常に簡単です。トレーニング コードを変更する必要はまったくありません。モデル コードを変更するだけです。3 つすべての効果を試すことができます。HAN では注意して使用してください。効果はあまりにも大きくなります。マタパスの設定によっては、トレーニング時間は依然として長く、価値がありません。

おすすめ

転載: blog.csdn.net/yzsjwd/article/details/126288084