2017年10月13日金曜日

pyenvの導入手順

覚書
参照先

macportsにはpyenvがない。以下を実行する。
使い方

以下のコマンドで、インストール可能なpythonインタープリターの一覧が表示される。 インストールしてみる。 インストールしたバージョンを見る。 切り替え 確認する。 アンインストールする。 この状態でpythonを起動すると、 ディレクトリを作ってその中だけでversionを変えるときは、ディレクトリ内で以下を実行する。 この状態で以下を実行 確認。

virtualenvの導入手順

覚書 以下を.bash_profileに記述する。
export VIRTUALENVWRAPPER_PYTHON='/opt/local/bin/python3.6'
export VIRTUALENVWRAPPER_VIRTUALENV='/opt/local/bin/virtualenv-3.6'
export VIRTUALENVWRAPPER_VIRTUALENV_CLONE='/opt/local/bin/virtualenv-clone-3.6'
source /opt/local/bin/virtualenvwrapper.sh-3.6
以下を実行する。 色々作られる。

使い方
仮想環境を作る。 自動的に今作った仮想環境に入る。 仮想環境から出るには 確認する。 仮想環境を削除する。

2017年2月26日日曜日

Canonical Labelling by Nauty

はじめに


 先のページで、論文「Learning Convolutional Neural Networks for Graphs」の紹介を行った。その中で、Canonical Labellingを行う際に、Nautyというツール(ライブラリ)を用いていた。ここでは、Nautyの提供するC言語インタフェースを用いて、Canonical Labellingを行う手順を示す。

Nautyのインストール


 ここからソースをダウンロードする。コンパイル手順はソースに含まれるREADMEに書いてある。 上の処理が終わると、ディレクトリnauty26r7の直下に実行ファイル、オブジェクトファイル、ソースファイル、ユーザガイドが混在する状態になる。上の例では、--prefixを指定してあるが、ディレクトリに含まれるmakefileにはinstall命令が記述されていない(後で気づいた)。make installできないので、実行ファイル等を手で適当な場所にコピーする必要がある。ユーザガイドはオンラインでも見ることができる。

開発環境

  1. Xcode Version 8.2.1 (C++ Language Dialect: C++14)
  2. boost library
  3. cpplinq

サンプル1


 最初に、ユーザガイドのp4の冒頭にある下図を取り上げる。
図1
図1の上段2つのグラフは同型(isomorphic)であるが、頂点の隣接関係は異なっている。これらを2つをcanonizeすると、頂点の隣接関係の等しい2つのグラフを得ることができる(図1の下段)。2つの同型のグラフは、canonical labellingにより、頂点の隣接関係の等しいグラフになる。言い換えれば、canonical labellingを用いれば、2つのグラフが同型であるか否かを判定することができるのである。この判定を、NautyのC言語インタフェースを用いて実装したものを以下に示す。 上の出力を検討してみる。最初に、図1左側のグラフについて(図2)。
図2
108行目でdensenautyを呼び出した後、配列labに以下の値が設定される。 これは以下を表現している。 すなわち、図2の上段の元のグラフの頂点番号3は0に、6は1に置き換えることを意味する(他の頂点についても同様)。配列relabelling1は分かり易いように表現方法を変えただけの値である。 これは を意味する。すなわち、元グラフの頂点番号0を6に、1を5に置き換える(他の頂点も同様)。図1右側の2つのグラフについても同じように解釈すれば良い。結局、図1下段の2つのグラフが得られたことになる(図3)。
図3
これら2つのグラフを見ると、頂点{5,1,4,0}の位置は異なるが、全頂点の隣接関係は全く同じである。これを確認しているのが148行目である。

サンプル2


 次にユーザガイドのp5冒頭にある図を考える(図4)。
図4
グラフの形はサンプル1と同じであるが、partitioning(coloring)が導入されている。頂点が色分けされている場合、同じ色に属する頂点についてcanonical labellingが実行される(サンプル1は全ての頂点が同じ色を持つと解釈される)。実装例は以下の通り。 9行目で色分けを行うことをNautyに伝えている。実際に色分けを行なっているのは、31,32行目と58,59行目である。Nautyでは色分けを2つの配列lab,ptnを用いて表現する。図4左側の2つのグラフの色分けは以下の2つの配列で記述される。 labには頂点番号が任意の順番で格納される。この格納順にptnで色の分離位置を表現する。0の場合そこが色の境界である。0以外の値のとき同じ色である。すなわち、{0,2}と{1,3,4,5,6,7}に色分けされることになる。図4では前者は黒、後者は白で描かれている。図4右側の2つのグラフの色分け(58,59行目)も同様である。densenautyの呼び出し(39,66行目)の後のlabにはcanonize後のラベルが格納され、この解釈方法はサンプル1と同じである。canonize後に得るグラフは図4の下段である。これら2つのグラフの頂点の隣接関係は異なる。これを確認しているのが80行目である。最後に、headerファイルとmain関数を示す。

論文「Learning Convolutional Neural Networks for Graphs」への適用


 論文「Learning Convolutional Neural Networks for Graphs」では、最初に、betweenness centralityやWLアルゴリズムにより頂点のラベル付けを行なった。そして、同じラベルを持つ頂点が存在する場合、この縮退を解くためにNautyを用いている。同じラベル値を持つ頂点を同じ色を持つ頂点と解釈し、Nautyを適用すれば良いだろう。 

2017年2月7日火曜日

Learning Convolutional Neural Networks for Graphs

1. はじめに


 論文「Learning Convolutional Neural Networks for Graphs」のアルゴリズムについてまとめる。

2. 本論文の目的


 本論文の目的は、一般的なグラフにConvolutional Neural Network(CNN)を適用することである。CNNでは畳み込み処理を行うが、これをグラフに適用する手順が提案されている。本論文で考案されたグラフ構造のためのCNNを著者らはPatchy-sanと名付けている。

3. CNNとグラフ


 最初に、画像に適用されるCNNを考えてみる。図1は畳み込みに使うフィルタ(Receptive Field: 以下RF)、図2はRFを画像(4$\times$4)に適用している様子を表したものである(本論文より引用)。
図1
図2

画像の形状は矩形であり、RFも矩形とするのが一般的である。さらに、RFを適用していく順番は左上から右下である。ところで、画像は形状が矩形であるグラフとみなすことができる。このときのノードは画素である。本論文は、任意の形状を持つグラフに適用できるように上記の手順を一般化する方法を提案している。一般化するには2つの手順を明確にする必要がある。
  1. RFを適用するノードとその順番(ノード・シーケンス)を決める。
  2. RFの形状を決める。
この2つを決めれば、通常のCNNのアルゴリズムに載せる事ができる。

4. ノード・シーケンスの決定


 画像の場合、画素の並びは左上から右下に向かって「ラベル」が付けられていると考え、ノード・シーケンスもそれに従い決定される。一般のグラフに対し一番最初に行うことは、各ノードに「ラベル」を付ける事である。ただし、以下の条件を満たすラベルでなければならない。
任意の2つのグラフ$G$と$G^{\prime}$を考える。$G$を構成するあるノード$n_G$の局所的な接続関係が、$G^{\prime}$内のあるノード$n_{G^{\prime}}$の局所的な接続関係と似ているなら、これら2つのノードに割り当てるラベルも似ている。
本論文ではこれを満たす2つの方法を取り上げている。
  1. 1次元Weisfeiler-Lehmanアルゴリズムを用いたラベリング
  2. Centralityを用いたラベリング
次にこれらを説明する。

4-1. 1次元Weisfeiler-Lehman(WL)アルゴリズムを用いたラベリング


 アルゴリズムの手順は以下の通りである。
  1. 2つのグラフ$G$と$G^{\prime}$を考える。最初に各ノードに1を割り振る(図3)。
  2. 図3
  3. ノードAを考える(図3)。Aは右と左のノードと接続しており、そのラベルはいずれも1である。この関係を1,11と書くことにする。カンマの前にAのラベルを、カンマの後ろに右と左のラベルを並べて書いたものである。カンマの後ろに並ぶ数字の順序はあとでソートするので任意でよい。同じ事を全てのノードについて繰り返すと図4を得る。
  4. 図4
  5. 1,11などを文字列とみて昇順に並べ、新たなラベルを割り当てる。新たなラベルは既存のラベルを上書きしないものとする。
    1,11 $\rightarrow$ 2
    1,111 $\rightarrow$ 3
    1,1111 $\rightarrow$ 4
  6. $G$と$G^{\prime}$の各ノードに新たなラベルを付ける(図5)。$G$のラベルは$\{2,2,2,3,3,4\}$、$G^{\prime}$のラベルは$\{2,2,2,3,3,4\}$であり、これらは同じである。同じ場合、2と3の手順を繰り返す。
  7. 図5
  8. ノードAを考える。先と同じように接続関係から2,43を得る。今度はラベルが同じとは限らないことに注意する。同じことを全てのノードについて繰り返すと図6を得る。
  9. 図6
  10. カンマの後ろに並ぶ数字を昇順に並べ替える。例えば、2,43を2,34とする。同じことを他のラベルについても繰り返す。得られたラベルを文字列とみなしてソートし、新たなラベルを割り当てる。
    2,24 $\rightarrow$ 5
    2,33 $\rightarrow$ 6
    2,34 $\rightarrow$ 7
    3,224 $\rightarrow$ 8
    3,234 $\rightarrow$ 9
    4,2233 $\rightarrow$ 10
  11. 新たなラベルを$G$と$G^{\prime}$に割り当てる(図7)。
  12. 図7
  13. 図7のとき、$G$のラベルは$\{6,7,7,8,8,10\}$、$G^{\prime}$のそれは$\{5,5,6,9,9,10\}$となり、これらは異なる。異なるとき終了する。ただし、何回繰り返しても終了しない場合があり得るので、あらかじめ適当な繰り返し数の上限を決めておく。
  • 異なるグラフに属する2つのノードが類似の接続関係を持つなら、これらのノードは類似のラベル値を持つ。また、ラベル値が大きいノードは、多くの隣接ノードと連結していることになる。
  • あらかじめ決めておいた回数だけ繰り返した結果、ラベルのセットが同じになるなら、「これらのグラフは同型である」か、「同型でないと結論づけることはできない」かのいずれかである。ほとんどの場合、同型であると結論してよい。
  • 上で取り上げた2つのグラフのノードの総数は12である。このときラベルの上限値は12としてよい。従って、繰り返し数の上限値は、いま現在使われているラベルの最大値から判断することができる。
上で取り上げた2つのグラフは同型でない場合であった。念のため、同型となる場合の例を以下に示す。
  1. $G$と$G^{\prime}$の各ノードに1を割り振る(図8)。
  2. 図8
  3. 先と同じ手順を行うと図9を得る。
  4. 図9
  5. 1,11 < 1,111< 1,1111と並べ、2,3,4を割り当てる(図10)。
  6. 図10
  7. $G$のラベルは$\{2,3,3,4,4\}$、$G^{\prime}$のそれは$\{2,3,3,4,4\}$であり同じなので、手順を繰り返す(図11)。2,44 < 3,344 < 4,2334と並べ替え、新たなラベル5,6,7を割り当てる(図12)。
  8. 図11
    図12
  9. $G$と$G^{\prime}$のラベルは同じになる。いまの場合、何回繰り返しても同じままである。
  10. 2つのグラフは同型である。
ここまでは、2つのグラフを取り上げてラベリングの手順を見てきた。Patchy-sanに本アルゴリズムを適用する際は、訓練データとなる全てのグラフを対象としなければならない。

4-2. Centralityによるラベリング


 Centralityとは、グラフ内における各ノードの重要性を表す指標である。Centralityが大きいノードほど「重要」となる。Centralityにはいくつかの種類があり、その代表的なものは以下のものである。
  1. Betweenness Centrality
    1. 任意に取り出した2つのノードを結ぶ最短経路を見つける。
    2. その経路上にある各ノードに+1を与える。
    3. この手順を繰り返す。
    4. 大きな値を持つノードは、最短経路に寄与する回数が多く、重要なノードである。
  2. Closeness Centrality
    1. あるノードを考え、このノードから他の任意の複数のノードへの最短経路を見つける。
    2. 最短経路の長さの平均値をそのノードのCentralityとする。
    3. Centralityが大きいノードほど、たくさんのノード、遠いノードと接続しており重要である。
  3. Degree Centrality
  4. そのノードと連結する辺の数である。
図13. Betweenness Centralityの例。赤から青に向かってCentralityは大きくなる。
(Wikipediaより抜粋)
先の1次元WLアルゴリズムの場合は、全グラフを使ってラベル値を決定するが、Centralityの場合は個々のグラフからラベル値が決まる。

4-3. ノード・シーケンス


 1次元WLアルゴリズムあるいはCentralityを用いて全グラフの全ノードにラベル付けを行ったあと、個々のグラフについてラベル値の大きなものから順に$w$個のノードを取り出す。これがノード・シーケンスとなる(図14)。要素数$w$は全グラフで同じである。画像の言葉で言えば、画像サイズは固定されるということである。本論文では、1つのグラフを構成するノード数の平均値を$w$としている。
図14. {A,B,C,D,E,F}がノード・シーケンス
ノード・シーケンスの各要素においてRFを作り、畳み込みを行う。画像におけるCNNと同様に、畳み込みを行うノード(画像の場合は画素)を$s(\neq 1)$個ずつ進めることもできる。

5. Receptive Field(RF)の決定


 ノード・シーケンスの要素$v$が与えられとき、$v$を中心にしてサイズ$k$のRFを作成する。その手順は以下の通りである。
  1. $v$から出発して隣接ノードを順にたどり$k$個を越えたところで止める。
  2. 集めたノードをNormalizationする(後述)。
各手順の詳細を以下に示す。

5-1. 近傍ノードの収集


 ノード$v$に対し、図15に示した順に近傍ノードを集めて行く。図16はこれをアルゴリズムにしたものである。
図15
図16. 本論文より抜粋

5-2. 近傍ノードのNormalization


 手順は以下の通りである。
  1. $v$(赤丸)を中心に近傍ノードを集める(図17A)。
  2. $v$からの距離で色分けを行う。図17Bでは距離1と距離2で色分けを行っている。
  3. 距離1のノードをラベル値の降順に並べる(図17C)。同じことを距離2のノードについても行う。
  4. 赤ノードを先頭に1次元に展開する(図18)。ノードの総数が$k$を越えている場合は末尾から必要なだけ削除する。$k$より少なければ0パディングする。ラベル値が同じとき1次元に展開したときの位置が一意に決まらない。この場合は、Canonicalizationを行いラベル値の縮退を解く。本論文ではNautyなるツールを用いてこれを行っている(こちらに追記しました(2017/02/26))。
図17. 本論文より抜粋
図18. 本論文より抜粋
各ノードに一意の並び順を与えベクトル化することをNormalizationという。図19は上記の手順をアルゴリズムとして示したものである。
図19. 本論文より抜粋

6. ここまでのまとめ


 図20,21は、ノード・シーケンスをたどりながらRFを作成する手順を示したものである。RFは$w$個作られる。ストライド$s(\neq 1)$でたどると$w$に達する前にノード・シーケンスの要素を使い果たすことになる。その場合は、0パディングしたRFを返す(ZeroReceptiveField())。その他の関数については既に説明した。
図20. 本論文より抜粋
図21. 図20に現れるReceptiveField関数。本論文より抜粋
あとは機械的にCNNを実行すればよい。

7. CNNの実行


 本論文のネットワーク構造は以下の通りである。
第1層目の点線で囲んだ部分がグラフ固有の処理である。この層で、上で説明したグラフ固有の畳み込みが実行される。2層目以降は通常のCNNである。畳み込みは次式で定式化される。 \begin{equation} g_{m,p,i}=\sum_{k,l}\;w_{p,l,k}\;x_{m,l,i+k} \end{equation} ここで、$p$はRFの種類、$i$はノード・シーケンスの要素番号(画像の言葉で言えば画素の位置)、$k$はRFのサイズ、$l$はチャンネル数である。また、バッチ処理を行う際、複数のノード・シーケンスを一度に扱うが、$m$はそのときのノード・シーケンスの番号である。さらに、チャンネルとは、グラフの場合、ノード属性に相当する。いま、畳み込みを記号$\otimes$で表すと上式は \begin{equation} g_{m,p}=\sum_{l}\;w_{p,l}\otimes x_{m,l,} \end{equation} と書ける。$x_{m,l}$が$g_{m,p}$に更新され、今度は、$g_{m,p}$に対して畳み込みを行うというのがCNNの一連の処理である。ここまでの議論でグラフをCNNの流れに載せることができたことになる。

8. 参考文献

  1. Weisfeiler-Lehman Graph Kernels
  2. Boosting and Semi-supervised Learning
  3. Centrality
  4. 著者らのスライド
  5. PFNの人のスライド

2016年12月12日月曜日

word2vec 〜 日本語wikipediaによる学習 〜


はじめに


 日本語wikipediaを使いword2vecを行う。詳細な手順はこちらのサイトにある。以下サイトAと呼ぶことにする。ここでは、サイトAと異なる箇所だけを示す。

mecabのインストール


 mecabだけでなく、その辞書であるmecab-ipadic-neologdもインストールする。以下のコマンドで日本語の分かち書き(品詞の間に空白を入れる)を行う事ができる。形容詞や動詞の活用形を終止形に直すこともしている。参考サイト 実行例は以下の通り。

原文
このページは、コンピュータ プログラムが記事を自動収集し、生成しています。 表示される日付や時刻は(記事のタイムライン機能の表示を含む)、Google ニュースに記事が追加/更新された時間です。
結果
この ページ は 、 コンピュータ プログラム が 記事 を 自動 収集 する 、 生成 する て いる ます 。 表示 する れる 日付 や 時刻 は ( 記事 の TIME LINE 機能 の 表示 を 含む ) 、 Googleニュース に 記事 が 追加 / 更新 する れる た 時間 です 。

日本語wikipediaのダウンロード


 サイトAでは、2.2GB程度とあるが5GBを越えるデータ(xml)がダウンロードされた。rubyを使ったテキストファイルへの変換手順と1つのテキストファイルへの統合手順はサイトAと同じである。サイトAでは触れられていないが、空白の行が一行おきに入るので、この空白行を取り除いた。そのあと、以下のコマンドを使い、このテキストファイル(jawiki.txt)を分かち書きする。 -bオプションは入力バッファサイズである。デフォルト値(8192)のまま行うと途中で落ちるので上記のように増やした。

word2vecの訓練


 word2vecのインストール手順はサイトAと同じ。以下のコマンドで学習を行う。 1つの単語を200次元ベクトルに置き換えます。

word2vecの予測


 以下のコマンドで相関の強い単語を検索できる。 わずか200次元のベクトルでこれだけの精度が出るとは。凄いの一言。単語をベクトルで表現できたので、画像のCNNによるベクトル化と統合して何かしたい。

2016年12月11日日曜日

迷子のaws

macportsで入れたpipでawscliをインストールしたら、awsコマンドが迷子になりました。以下の場所に隠れておりました。
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin

2016年10月30日日曜日

ec2にnvidia dockerを導入しtensorflowを動かす手順


はじめに


 ec2にnvidia dockerを導入しtensorflowを動かす手順を示す。

使用したインスタンス


 ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-20160114.5 - ami-a21529cc

システムのアップデート



gccなどのインストール



nouveauをブラックリストに追加


 以下を/etc/modprobe.d/blacklist-nouveau.confに記載する。 以下を/etc/modprobe.d/nouveau-kms.confに記載する。 以下で上記の設定を反映させる。

再起動



nvidia driver のインストール


参照先 [追記:2016/12/04] 上記のドライバのバージョンは古いので以下をインストールした方が良い。

再起動



dockerのインストール


 ここを見てdockerを入れる。下記の通りではなくその時点で指定されているバージョンを指定する。 logout/loginすることでusermodeの変更が反映され、sudoなしでdockerコマンドを使えるようになる。
[追記:2016/12/04] docker.listに記載する内容は14.04と16.04とで異なることに注意する。ここを参照のこと。

dockerの動作確認



nvidia dockerのインストール


 nividia-dockerは、dockerのプラグインである。これを入れた後はdockerではなくnvidia-dockerを使う。 ここを見て、その時点で指定されているバージョンを指定する。

nvidia dockerのテスト


[引用] 「NVIDIA Dockerは、NVIDIAが開発しているDockerプラグインです。 Dockerホスト側にNVIDIA GPUドライバを持たせ、 Dockerコンテナ側にCUDA Toolkit(+cuDNN)を持たせるという明確な役割分担により、 同一ホスト上の複数コンテナでバージョンの異なるCUDA Toolkitを柔軟に組み合わせられます。 さらに、NVIDIA Docker用に事前ビルドされたcuDNN入りDockerイメージを利用すると、 NVIDIAへの開発者登録無しに(!)cuDNNライブラリを利用できます」 引用元

tensorflow入りのimageの導入


 tensorflowを手動でインストールする手間を省くことができる。以下の3つを試みた。 最初の2つは、最新のtensorflowがインストールされた同じIMAGE IDを持つimageをインストールする。 このimageから作ったcontainer内でtensorflowの計算を実行すると以下のエラーが出る。 正しく動いたのは1つ前のバージョンを持つ3目である。この時点での状態は以下の通り。

tensorflow入りのimageの動作確認


 ここの項目「AWS GPU TensorFlow Docker」を見て 以下を実行した。

- docker containerに入る。 /notebookの直下に入ることになる。

- container内のシステムのアップデート - ソースを取ってくる。 - 実行 - 以下でtensorboard を起動 [your url]:6006で接続する。[your url]:8888とすればjupyterに接続できる。

caffe入りimageの導入


以下を実行してcaffe+cuda入りのimageをインストールする。 確認。 8.0もあるがこちらはmnistの実行中に以下が出て動作しなかった。 [追記:2016/12/04] 上記で指摘したように、nvidiaのドライバを新しいバージョンのものにすれば8.0は動きます。 containerを作り起動する。 containerに入る。 サンプルとして提供されているmnistで動作確認を行った。

参照サイト


[nvidia docker/tensorflow]
http://www.muo.jp/2016/05/nvidia-docker-tensorflow.html http://qiita.com/masafumi_miya/items/8263a25642d65a0c4a20 https://github.com/fluxcapacitor/pipeline/wiki/AWS-GPU-TensorFlow-Dock

[docker]
https://docs.docker.com/cs-engine/install/#/install-on-ubuntu-14-04-lts

[nvidia docker]
https://github.com/NVIDIA/nvidia-docker#plugin-install-recommended

[docker/tensorflow]
http://www.kabuku.co.jp/developers/errors-with-tensorflow-on-gpu

[docker/nvidia docker/tensorflow]
https://www.tensorflow.org/versions/master/get_started/os_setup.html#docker-installation

[ec2/tensorflow]
https://gist.github.com/erikbern/78ba519b97b440e10640