<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>GNN - まったり勉強ノート</title>
	<atom:link href="https://www.mattari-benkyo-note.com/tag/gnn/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.mattari-benkyo-note.com</link>
	<description>shuの日々の勉強まとめ</description>
	<lastBuildDate>Sun, 22 May 2022 23:09:31 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
<site xmlns="com-wordpress:feed-additions:1">189243286</site>	<item>
		<title>PyTorch Geometricを使ってVariational Graph Auto-Encodersを作って学習してみる</title>
		<link>https://www.mattari-benkyo-note.com/2022/05/23/pytorch-geometric-vgae/</link>
					<comments>https://www.mattari-benkyo-note.com/2022/05/23/pytorch-geometric-vgae/#respond</comments>
		
		<dc:creator><![CDATA[Shuji Suzuki (shu)]]></dc:creator>
		<pubDate>Sun, 22 May 2022 23:08:14 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[GNN]]></category>
		<category><![CDATA[pytorch]]></category>
		<category><![CDATA[pytorch-geometric]]></category>
		<guid isPermaLink="false">https://www.mattari-benkyo-note.com/?p=1436</guid>

					<description><![CDATA[<p>はじめに 最近読んだ論文にVariational Graph Auto-Encoders (VGAE) を使ったモデルがあったので、自分でもやってみようと思い、作ってみました。本日はそのまとめになります。 本日紹介する使 [&#8230;]</p>
<p>The post <a href="https://www.mattari-benkyo-note.com/2022/05/23/pytorch-geometric-vgae/">PyTorch Geometricを使ってVariational Graph Auto-Encodersを作って学習してみる</a> first appeared on <a href="https://www.mattari-benkyo-note.com">まったり勉強ノート</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">はじめに</h2>



<p>最近読んだ論文に<a href="https://arxiv.org/abs/1611.07308" target="_blank" rel="noreferrer noopener">Variational Graph Auto-Encoders</a> (VGAE) を使ったモデルがあったので、自分でもやってみようと思い、作ってみました。本日はそのまとめになります。</p>



<p>本日紹介する使うコードは以下のものです。</p>



<p><a href="https://github.com/shu65/pytorch_geometric_examples/blob/main/PyTorch_Geometric_Variational_Graph_AutoEncoder.ipynb">https://github.com/shu65/pytorch_geometric_examples/blob/main/PyTorch_Geometric_Variational_Graph_AutoEncoder.ipynb</a></p>



<p>また、このコード自体、以下のPyTorch Geometricのexampleのコードとほぼ同じです。</p>



<p><a href="https://github.com/pyg-team/pytorch_geometric/blob/ee509ad65aefa679047356bb00bc498f35ce7e20/examples/autoencoder.py">https://github.com/pyg-team/pytorch_geometric/blob/ee509ad65aefa679047356bb00bc498f35ce7e20/examples/autoencoder.py</a></p>



<p>このblog記事ではVGAEで必要な機能がPyTorch Geometricでどう実装されているのかわからなかった部分がいくつかあるのでその部分を解説していく記事になります。</p>



<h2 class="wp-block-heading">PyTorch Geometricとは</h2>



<p>PyTorch GeometricはPyTorchを使って構築されたGraph Neural Network向けのライブラリになります。</p>



<p>GitHubのURLは以下の通りです。</p>



<p><a href="https://github.com/pyg-team/pytorch_geometric">https://github.com/pyg-team/pytorch_geometric</a></p>



<p>最新のPyTorchやCUDAにもちゃんと対応しており、Graph Neural Networkで必要な基本的な機能はそろっている印象です。</p>



<h2 class="wp-block-heading">Variational Graph Auto-Encoders (VGAE)とは</h2>



<p>VGAEは<a href="https://arxiv.org/abs/1312.6114" target="_blank" rel="noreferrer noopener" title="Variational Auto-Encoder">Variational Auto-Encoder</a> (VAE) というモデルをGraphデータ向けに拡張したモデルです。VAEの説明を始めるとそれだけですごく長くなりますので、今回はVGAEを実装するうえで必要なところだけ紹介します。</p>



<p>VAEは以下のようにEncoderとDecoderという二つのモデルを組み合わせたモデルになります。</p>



<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" src="https://www.mattari-benkyo-note.com/wp-content/uploads/2022/05/VAE.png" alt="" class="wp-image-1441" width="227" height="338" srcset="https://www.mattari-benkyo-note.com/wp-content/uploads/2022/05/VAE.png 480w, https://www.mattari-benkyo-note.com/wp-content/uploads/2022/05/VAE-201x300.png 201w" sizes="(max-width: 227px) 100vw, 227px" /><figcaption>VAEの概要図</figcaption></figure></div>



<p>このうち、EncoderとDecoderは以下のようなモデルになります。</p>



<ul class="wp-block-list"><li>Encoder: 入力Xを受け取って潜在変数Zの分布のパラメータを出力する</li><li>Decoder: 潜在変数Zを受け取って入力Xを再構成する</li></ul>



<p>VAEで重要なのがEncoderの部分と潜在変数Zのサンプリングの部分です。この潜在変数Zの分布が標準正規分布という仮定のもと学習させながら、Encoderで潜在変数Zの分布のパラメータを出力し、その分布のパラメータを使って潜在変数ZをサンプリングしてDecoderに渡すということを行います。</p>



<p>このVAEをGraph データに拡張するためにVGAEはEncoderとDecoderを以下のようなモデルにしています。</p>



<ul class="wp-block-list"><li>Encoder: ノードの特徴ベクトルXと隣接行列Aを入力として受け取り、潜在変数Zの分布のパラメータを出力する</li><li>Decoder: 潜在変数Zを受け取り隣接行列Aを再構築する</li></ul>



<p>図にすると以下のようなイメージです。</p>



<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><img decoding="async" src="https://www.mattari-benkyo-note.com/wp-content/uploads/2022/05/VGAE.png" alt="" class="wp-image-1442" width="288" height="356" srcset="https://www.mattari-benkyo-note.com/wp-content/uploads/2022/05/VGAE.png 578w, https://www.mattari-benkyo-note.com/wp-content/uploads/2022/05/VGAE-243x300.png 243w" sizes="(max-width: 288px) 100vw, 288px" /><figcaption>VGAEの概要図</figcaption></figure></div>



<p>VGAEとVAEとの違いはEncoderでグラフの情報であるノード情報と隣接行列を受け取れるようにしたことと、Decoderが出力するものが隣接行列になることです。</p>



<h2 class="wp-block-heading">VGAEをPyTorch Geometricを使って実装する</h2>



<p>VGAEの概略を説明したので次は実際に実装を紹介していきます。まずはEncoderである<code>VariationalGCNEncoder</code>から見ていきます。EncoderではPyTorch Geometricに実装されている <code>GCNConv</code> を使って実装します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="vgae_encoder" data-lang="Python"><code>from torch_geometric.nn import GCNConv

class VariationalGCNEncoder(torch.nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.conv1 = GCNConv(in_channels, 2 * out_channels)
        self.conv_mu = GCNConv(2 * out_channels, out_channels)
        self.conv_logstd = GCNConv(2 * out_channels, out_channels)

    def forward(self, x, edge_index):
        x = self.conv1(x, edge_index).relu()
        return self.conv_mu(x, edge_index), self.conv_logstd(x, edge_index)</code></pre></div>



<p> <code>GCNConv</code> はノードのインプットのチャンネル数、アウトプットのチャネル数を引数にとってインスタンスを作ります。そしてforwardではノードのtensor <code>x</code> と隣接行列のかわりにどのノード同士がつながっているか？を示す<code>edge_index</code>を渡します。<code>GCNConv</code> の中身についてはドキュメントに詳しく書かれているのでそちらをご覧ください。</p>



<p><a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#torch_geometric.nn.conv.GCNConv">https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#torch_geometric.nn.conv.GCNConv</a></p>



<p>このEncoderではVGAEの概要でも説明した通り、潜在変数の分布のパラメータを返します。ここではガウス分布の平均を表すmuと標準偏差にlogを適用したlogstdを返しています。</p>



<p>モデルの実装としてはあとはPyTorch Geometricで実装されている<code>VGAE</code>というクラスに渡せば終わりになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="vgae" data-lang="Python"><code>from torch_geometric.nn import VGAE

model = VGAE(VariationalGCNEncoder(in_channels, out_channels))</code></pre></div>



<p>ただ、これだとさすがに初見だと何が何だかわからなかったので、少し説明します。</p>



<p>まず、Decoderについてです。Decoderは<code>VGAE</code> のデフォルトでは<code>InnerProductDecoder</code>というものが使われます。これはVGAEの元論文でも使われていたDecoderの実装で、エッジの両端のノードに対応する潜在変数の各要素の積を取って総和を取り、sigmoidを適用して0-1の値にして出力します。出力値が0-1の値になっているのでDecoderの出力値は計算に使った二つのノードの間にエッジがある確率とみることができます。</p>



<p>詳しくは以下のドキュメントをご覧ください。</p>



<p><a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#torch_geometric.nn.models.InnerProductDecoder">https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#torch_geometric.nn.models.InnerProductDecoder</a></p>



<p>また、ロス関数についてですが、<code>VGAE</code> の中にVGAEで必要な以下の二つが実装されています。</p>



<ul class="wp-block-list"><li><code>recon_loss</code>: 潜在変数zとノード同士のつながりを示すpos_edge_indexを入力にとり、Decoderを利用して各エッジのある確率を計算、その確率に対してbinary cross entropyを計算してlossとして返す関数<br><a href="https://pytorch-geometric.readthedocs.io/en/latest/_modules/torch_geometric/nn/models/autoencoder.html#GAE.recon_loss" target="_blank" rel="noreferrer noopener">https://pytorch-geometric.readthedocs.io/en/latest/_modules/torch_geometric/nn/models/autoencoder.html#GAE.recon_loss</a></li><li><code>kl_loss</code>: Encoderの出力したmuとlogstdを使って標準正規分布とのKLダイバージェンスを計算しlossとして返す関数<br><a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#torch_geometric.nn.models.VGAE.kl_loss" target="_blank" rel="noreferrer noopener">https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#torch_geometric.nn.models.VGAE.kl_loss</a></li></ul>



<p>これを以下のように学習ループで利用して学習をおこないます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="vgae_train" data-lang="Python"><code>for epoch in range(0, 400):
    model.train()
    optimizer.zero_grad()
    z = model.encode(train_data.x, train_data.edge_index)
    recon_loss = model.recon_loss(z, train_data.pos_edge_label_index)
    kl_loss = (1 / train_data.num_nodes) * model.kl_loss()
    loss = recon_loss + kl_loss
    loss.backward()
    optimizer.step()</code></pre></div>



<p>最後に上のコードではノード間にエッジがあるところの情報は<code>train_data.pos_edge_label_index</code>で渡しているのですが、ノード間にエッジがないという情報はどこで渡しているか？ということについて説明します。</p>



<p>コードを読むと実はrecon_lossの中で自動的にエッジがないという情報を生成してそれを込みでロスが計算されています。具体的には以下の部分です。</p>



<p><a href="https://github.com/pyg-team/pytorch_geometric/blob/d2b2e662488eae07d153de6d4b8c56c24bf413d9/torch_geometric/nn/models/autoencoder.py#L101">https://github.com/pyg-team/pytorch_geometric/blob/d2b2e662488eae07d153de6d4b8c56c24bf413d9/torch_geometric/nn/models/autoencoder.py#L101</a></p>



<p>ここで引数で<code>neg_edge_index</code>が<code>None</code>のときは自動でエッジが存在しないノードのペアをサンプリングするという処理になっています。</p>



<p>以下です。その他の部分で気になるところがある場合は全体のコードを以下のところに置いてありますのでご覧ください。</p>



<p><a href="https://github.com/shu65/pytorch_geometric_examples/blob/main/PyTorch_Geometric_Variational_Graph_AutoEncoder.ipynb">https://github.com/shu65/pytorch_geometric_examples/blob/main/PyTorch_Geometric_Variational_Graph_AutoEncoder.ipynb</a></p>



<h2 class="wp-block-heading">終わりに</h2>



<p>今回はPyTorch Geometricの練習として、VGAEを実装してみたのでまとめの記事を書きました。PyTorch Geometricを今回初めて使ったのですが、Graph Neural Networkに必要な基本的な機能はそろっていそうなので、今後もGraph Neural Networkを使う機会があれば使ってみようと思います。</p><p>The post <a href="https://www.mattari-benkyo-note.com/2022/05/23/pytorch-geometric-vgae/">PyTorch Geometricを使ってVariational Graph Auto-Encodersを作って学習してみる</a> first appeared on <a href="https://www.mattari-benkyo-note.com">まったり勉強ノート</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.mattari-benkyo-note.com/2022/05/23/pytorch-geometric-vgae/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1436</post-id>	</item>
	</channel>
</rss>
