Graph Attention Network Layerを実装する Part3 (End)

piqcy
programming-soda
Published in
10 min readNov 16, 2018

Part3では、Graphにおける適切なAttentionのかけ方を検証します。というのも、Part2の実験ではGraph Attention Networkで提案されているAttentionが、本当にAttentionとして効いているのか疑問な結果が出たためです。そのため、本記事ではAttentionのかけ方を整理し、どれが有効なのか検証したいと思います。

結果として、いわゆるAdditive Attentionを実装することで精度を向上させることができました。Part2で行った実験結果との比較が下表になります。

Attentionの実装方式による精度の比較

オリジナルの精度を上回る結果です。ちょっと良すぎるので数回実験しましたが、平均0.83ほどにはなりました。ただ、Attentionに使用する重みが増えた分、モデルのサイズ・実行速度は重たくなっています。そして、Part1のExpectation Checkはやはり通りませんでした。これについては後述します。

実験に使用したコードは以下になります。

以下のセクションでは、Attentionを検証するタスクの設計、検証するAttention種別の定義、実験/実験結果、の3つを解説していきます。

検証タスクの設計

実験のため、最もノード特徴が近い(=距離が小さい)隣接ノードに、Attentionが立つようなタスクを作成しました。

最もNode特徴が近いノードに、Attentionをはる

上図において、ノードの色はノードの特徴を表しています。図中の括弧で囲まれたノードは隣接ノードを4つ持っていますが、そのうち最も特徴が近い(同じ緑色のノード)に対しては1、それ以外は0、というAttentionが予測できればOKとなります。これは、分類問題と同等です。各Attentionのタイプについて、最も精度高くなるのはどの手法かを検証します。

テストにおいては、ノードの特徴ベクトルサイズが2、隣接行列が10x10で検証を行いました。各ノードは最大9の接続を持つため、適当に選んだ場合は10%の確率で正解ということになります。ただ、実際の接続数は最大数の9より少なくなるため、ランダムに選んだ場合の精度は20%前後になります。

検証するAttentionの種別

Attentionの基本

検証するAttentionの種別を決める前に、Attentionの基本を押さえておきます。Attentionの基本式は、以下のようになっています。

Attentionの基本式

Attentionの計算に使う”score”の式は任意の関数になります。代表的な関数としては、以下の種類があります。

Bahdanau attention

今回は、Graph Attention Networkの形式に近いBahdanau attentionを使用しました(Additive Attention)(LuongのMultiplicativeについても検証していますが、本記事は精度の良かったAdditiveの方を中心に書きます)。AdditiveはAにとってどのBが重要かというAttentionを作成する際に、A/Bそれぞれに重みをかけ合計し、tanhをとりさらにAttentionの重みをかけたスコアを使用します。

Attentionの掛け方については、GoogleがColabで公開しているNeural Machine Translation with Attentionのチュートリアルがとてもわかりやすいです(上で掲載したAttentionの式についても、このチュートリアルから引用しています)。

Attentionの種別

Graph Attention Networkで提案されているAttentionの方法は、Bahdanau attentionとは異なります。

Graph Attention NetworkにおけるAttention (式3より)
Graph Attention NetworkにおけるAttention (Figure1 Leftより)

具体的な差異は、以下の点です。

  • 重みをかけた結果のMerge方法が、合計(Add)ではなく結合(Concat)
  • Merge後に、重みをかけていない(Bahdanau attentionにおけるvがない)

Attentionのscore関数として使用されているのは活性化関数(LeakyReLU)のみであり、重みを使わず内積も取らないという面ではかなりシンプルです。

Graph Attention NetworkにおけるAttentionのかけ方として、気になる点がもう一つあります。それが、Node同士の相関行列の作成方法です。Graph Attention Networkの実装では、ブロードキャストにより相関行列を作成しています(Graph Convolutionを自然言語処理に応用する Part2より)。

dense = attn_for_self + K.transpose(attn_for_neighs)  # (N x N) via broadcasting

わかりやすくNumpyで試してみると以下のような形になります。

import numpy as np
w_self = np.array([1, 2, 3])
w_neig = np.array([0.1, 0.2, 0.3])
matrix = w_self + np.rehape(w_neig, (-1, 1))
> matrix
array([[1.1, 2.1, 3.1],
[1.2, 2.2, 3.2],
[1.3, 2.3, 3.3]])

これはちょっとおかしい気がします。行がNodeを表している場合、行の中の各要素は「Node iからNode j への遷移、Node iからNode j +1への遷移・・・」を表しているはずです。つまり、以下のようになるべきではと感じます。

array([[1.1, 1.2, 1.3],
[2.1, 2.2, 2.3],
[3.1, 3.2, 3.3]])

そのため、オリジナルの実装の通り各Nodeの特徴がcolumn方向に維持されている場合と、理論上正しいと思われる行方向に維持されている場合の2つを検証します。そのため、観点は以下の3つになります。

  1. Merge方法: 合計(Add)か結合(Concat)か
  2. Attention Weight (v)の有無
  3. Nodeの特徴維持方向: columnかrowか

3つの観点の組み合わせが、検証するAttentionのかけ方になります。なお、Merge方法としてConcatを使う場合はAttention Weightがないと結合後のサイズを1に集約できないため、Attention Weightが必須になります。

実験結果

結果は以下のようになりました。

Attentionのタイプ別の精度(5回実験によるvalidation accuracyの平均と標準偏差を記載)

Add/Attention Weight有りが、精度が良いです。Node Directionはあまり関係がないようでした(重みが適応的に学習するのかもしれません)。検証ではAttentionの活性関数にtanhを使いましたが、Graph Attention NetworkではLeakyReLUを使用していたためその結果も掲載しておきます。全体的に若干悪くなります。

Leaky ReLUによる実験

では、バッチ対応した実装をAdd/Attention Weight有で書き直してみます。修正後Part2の実験を行ったところ、元の精度を大幅に更新しました。

original/batch対応後/Type5 attentionの実行結果比較

スコアが高すぎる気がするので何回か実験しましたが、0.83近辺にはなります。学習に若干時間がかかりますが、これは、Attention分の行列演算が追加されるためと思います。また、重みの数も多くなります。なお、Multiplicativeの場合1.511/0.81ほどになり、こちらもoriginalと同程度になります。学習結果の比較は以下のようになります。

AdditiveとMultiplicativeの比較(オレンジ: Additive、青: Multiplicative)

ただ、Part1のExpectation Checkのスコアは改善しませんでした。Attention Accuracyは0.6程度だったので十分に思えますが、Attentionのbiasを抜くと途端に0.2~0.3へ悪化します。Attentionは隣接行列とサイズが同じため、biasについても同様のサイズになります。このためbiasを持つ場合隣接行列と同じサイズのパラメーターを持つことになります。小さいサイズのグラフでは問題ないのですが、巨大なグラフの場合演算グラフが巨大になりすぎるためか非常に時間がかかります(計算時にrepeat_elementを使って隣接行列と同じサイズの行列を作ろうとすることについても同様の影響があります)。Part2で使用したCORAのデータセットではハングしたため、実装ではAttentionのbiasを隣接行列のサイズになる前に適用しています

何にせよ、これで有効なAttentionの実装方法がわかりました。言語で使うグラフはそれほど大きいものではないので、Attentionのbiasを使うことも考慮してNLP用のGraph Attention Layerを実装しようと思います。

Graph Attention Network Layer実装編はこれにて終了です。次回は、Part3の結果を基に作成したLayerをいよいよ自然言語処理に活かしてみたいと思います。

--

--

piqcy
programming-soda

All change is not growth, as all movement is not forward. Ellen Glasgow