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

2016年9月24日土曜日

word2vec その2


はじめに


 このページの続きです。

やりたいこと


 単語列 \begin{equation} W = \{w_1,\cdots, w_T\} \end{equation} が与えられているとき、この単語列に含まれる任意の単語$w_t$を考える。$w_t$を含む文からその周辺の単語の集合$\Xi_{w_t}$を作ることができる。 \begin{equation} \Xi_{w_t} = \{\xi_1^t, \cdots, \xi_C^t\} \end{equation} このとき、以下の対数尤度を考える。 \begin{eqnarray} L&=&\sum_{t=1}^T \sum_{c=1}^{C} \biggl\{ \log{\sigma(s(\xi_c^t,w_t))}+\sum_{w \in {\rm Ng}}\log{\sigma(-s(w,w_t))} \biggr\} \label{obj}\\ \sigma(x) &=& \frac{1}{1+\exp{(-x)}}\\ s(a,b) &=& \vec{u}^T_a \cdot \vec{v}_b \end{eqnarray} ここで、${\rm Ng}$は分布 \begin{equation} p(w) = \frac{U(w)^{0.75}}{\sum_{t=1}^{T}U(w_t)^{0.75}} \end{equation} に従ってサンプリングした$k$個の単語の集合である。$U(w)$は単語の出現頻度である。本ページでは、上記の対数尤度の最大化問題を、Neural Networkを用いて解くことができることを示す。

Neural Networkによる表現


 単語列$W$内の$t$番目の単語$w_t$を以下のone-hot vector $\vec{x}_t$で表現する。 \begin{equation} \vec{x}_t = \left( \begin{array}{c} 0 \\ \vdots \\ 1 \\ 0 \\ \vdots \\ 0 \end{array} \right) \end{equation} $t$番目の要素だけが1の$T$次元ベクトルである。次に、行列$W_I$と$W_O$を次式で定義する。 \begin{eqnarray} W_I&=&\left[\vec{v}_1, \cdots, \vec{v}_T\right] \\ W_O&=&\left( \begin{array}{c} \vec{u}_1^T \\ \vdots \\ \vec{u}_T^T \end{array} \right) \end{eqnarray} ここで、$\vec{v}_t$と$\vec{u}_t$は$M$次元ベクトルとする。従って、$W_I$は$M\times T$行列、$W_O$は$T\times M$行列である。これらを用いると \begin{eqnarray} (W_O\; W_I\; \vec{x}_t)_i &=& (W_O)_{ik}\;(W_I\;\vec{x}_t)_k \\ &=&(W_O)_{ik}\;(W_I)_{km} (\vec{x}_t)_{m}\\ &=& u_{ik}\;v_{mk}\;x_{tm} \\ &=& u_{ik}\;v_{mk}\;\delta_{tm} \\ &=& u_{ik}\;v_{tk} \\ &=& \vec{u}_{i}^T \cdot \vec{v}_{t} \\ &=& s(i, t) \end{eqnarray} となる。これを図にすると以下のようなる。
以上から以下のことが分る。
  1. 式(\ref{obj})の第1項に含まれる$s(\xi_c^t, w_t)$を計算するには、$w_t$に相当するone-hot vector $\vec{x}_t$をネットワークに入力し、その出力ベクトル($T$次元ペクトル)の成分のうち、$\xi_c^t$に相当するものを取り出せば良い。
  2. 式(\ref{obj})の第2項に含まれる$s(w, w_t)$の計算も同様である。
これらの計算のあと活性化関数としてsigmoid関数を作用させ、従来の手法(確率的最急降下法など)を使って$L$を最適化すれば良い。この計算で求まる行列$W_I$を使って単語$w_t$を表現するベクトル$\vec{v}_t$が次式で決まる。 \begin{equation} \vec{v}_t = W_I\;\vec{x}_t \end{equation} $T \gg M$と取るので低次元で効率良く単語を表現できるベクトルを得ることができる。

Chainerによる実装


 Chainerのソースには、word2vecのサンプルプログラムが含まれている。このサンプルプログラムには、Skip Gram以外にContinuous BoWも実装されており、さらに、Negative Sampling以外の損失関数も選択できるようになっている。以下に示すのは、サンプルプログラムを参考にして、Skip GramかつNegative Samplingの場合のクラスを実装したものである。
  1. 5行目で定義されるL.EmbedIDは、$W_I$に相当する。
  2. 6行目で定義されるL.NegativeSamplingは、式(\ref{obj})を計算する。この関数の中に$W_O$に相当するものがある。
  3. n_vocabは$T$、n_unitsは$M$に相当する。
  4. countsは$U(w)$に相当する。
  5. sample_sizeは$k$に相当する。
  6. 13行目の引数xはいま対象にする単語$w_t$、contextは$\Xi_{w_t}$に相当する。ただし、batch処理が考慮されている。
ここまでは式と対応付けることができたが、関数__call__の中で行っている処理で分らなくなる。最初にself.embed(context)を実行している。$\Xi_{w_t}$の中の1つの単語を$\vec{x}_t$とおくと、この計算は$W_I\;\vec{x}_t$に相当してしまう。定式化では$\Xi_{w_t}$に含まれる単語には$W_O$が作用するはずである。さてどこでおかしくなったのか?

2016年9月23日金曜日

word2vec その1


はじめに


 word2vecについてまとめます(その2を書きました)。

やりたいこと


 ある程度まとまった量の文章$A$を考える。これに出現する単語を重複を許さずに取り出すと、長さ$T$の単語列が出来上がる。 \begin{equation} W = \{w_1, \cdots, w_T\} \end{equation} いま、この単語列に含まれる単語$w_t$を含む文を$A$から取り出し、$w_t$の前後$b$個の範囲にある単語の集合$\Xi_{w_t}$を考える。 \begin{equation} \Xi_{w_t} = \{\xi_1^t, \cdots, \xi_C^t\} \end{equation} これは文脈を反映した集合である。たとえば、
Linux was originally developed as a free operating system for personal computers based on the Intel x86 architecture.
という文からは、$w_t={\rm developed}$、$b=1$のとき \begin{equation} \Xi_{{\rm developed}} = \{{\rm originally}, {\rm as}\} \end{equation} を、$w_t={\rm free}$のとき \begin{equation} \Xi_{{\rm free}} = \{{\rm a}, {\rm operating}\} \end{equation} を得る。$w_t$を指定したとき$\Xi_{w_t}$が実現する確率 \begin{equation} p(\Xi_{w_t}|w_t) \end{equation} を最大化するような単語の表現(ベクトル)を求めることがword2vec(Skip-Gram model)の目的である。

対数尤度の最大化


\begin{eqnarray} p(\Xi_t|w_t) &=& p(\xi_1^t, \cdots, \xi_C^t|w_t) \\ &=& \prod_{c=1}^{C}p(\xi_c^t|w_t) \end{eqnarray} 対数をとり、全ての単語について足し合わせたもの \begin{equation} L=\sum_{t=1}^T \sum_{c=1}^{C}\log{p(\xi_c^t|w_t)} \label{obj} \end{equation} を最大化する。

Softmax関数による計算


 $p(\xi_c^t|w_t)$としてSoftmax関数を仮定する。 \begin{equation} p(\xi_c^t|w_t)=\frac{\exp{\vec{u}^T_{\xi_c^{\;t}} \cdot \vec{v}_{w_t}}}{\sum_{w \in W} \exp{\vec{u}^T_w \cdot \vec{v}_{w_t}}} \end{equation} ここで、$\vec{v}$は入力単語を表現するベクトル、$\vec{u}$は出力単語を表現するベクトルである。$\sum_{w \in W}$は全単語について足し合わすことを意味する。モデルに入力する単語とモデルが出力する単語は区別されることに注意する。式(\ref{obj})に代入すると \begin{equation} L = \sum_{t=1}^T \sum_{c=1}^{C} \left\{ s(\xi_c^t, w_t) - \log{\sum_{w \in W} \exp{s(w, w_t)}} \right\} \end{equation} を得る。ただし、$s(a,b) = \vec{u}^T_a \cdot \vec{v}_b$とした。$W$の要素数が少なければ総和($\sum_{w \in W}$)を取ることは可能であるが、現実の問題では$10^5\sim10^7$のオーダーであるため計算は困難である。

1次元ロジスティック回帰による計算(2分類問題への置き換え)


 単語$a$と$b$が与えられたとき、これらが同じ文脈上に存在する確率を$p(D=1|a, b)$、同じ文脈上に存在しない確率を$p(D=0|a, b)$とする。 このとき、次式のように書くことができる。 \begin{equation} p(D|a,b)=p(D=1|a, b)^{D}\; p(D=0|a, b)^{1-D} \end{equation} ここで以下を考える。
  1. $w_t$が与えられた時の集合$\Xi_{w_t}$の各要素は、$w_t$と同じ文脈上に存在する。
  2. $w_t$が与えられた時の集合$\Xi_{w_t}$に属さない要素は、$w_t$と同じ文脈上に存在しない。
これらを実現するには、次の対数尤度を最大化すればよい。 \begin{equation} L = \sum_{t=1}^T \sum_{c=1}^{C} \biggl\{ D_t \log{p(D_t=1|\xi^t_c, w_t)}+\sum_{w \not\in \Xi_{w_t}}(1-D_t)\log{p(D_t=0|w, w_t)} \biggr\} \label{f1} \end{equation} さらに \begin{eqnarray} p(D_t=1|a, b) &=& \sigma(s(a,b)) \\ p(D_t=0|a, b) &=& 1- \sigma(s(a,b)) = \sigma(-s(a,b)) \end{eqnarray} を仮定すれば($\sigma(x)$はシグモイド関数)、1次元ロジスティック回帰の問題に帰着する。 式(\ref{f1})を最大にすることにより
  1. 同じ文脈上にある2語の確率を高くし(第1項からの寄与)
  2. 同じ文脈上にない2語の確率を高くする(第2項からの寄与)
ことが実現される。上記とほとんど同じことであるが次式を最大化する手法が存在する。 \begin{equation} L = \sum_{t=1}^T \sum_{c=1}^{C} \biggl\{ \log{p(D_t=1|\xi^t_c, w_t)}+\sum_{w \in {\rm Ng}}\log{p(D_t=0|w, w_t)} \biggr\} \end{equation} ${\rm Ng}$は、分布 \begin{equation} p(w) = \frac{U(w)^{0.75}}{\sum_{t=1}^{T}U(w_t)^{0.75}} \end{equation} に従ってサンプリングした$k$個の単語の集合である。$U(w)$は単語の頻度である。人為的に外れ(negative)データを導入することから、本手法をNegative Samplingと呼ぶ(その2を書きました)。

2016年7月24日日曜日

LSTMによる正弦波の予測 〜 Chainerによる実装 〜


はじめに


 「RNNにsin波を学習させて予測してみた」ではTensorflowを使って、「深層学習ライブラリKerasでRNNを使ってsin波予測」ではKerasを使って、RNNによる正弦波の学習・予測が行われている。ここでは同じことをChainerを使って実装する。

ネットワークの構造


 実装は以下の通りである。

-- lstm.py -- コンストラクタの引数の意味は以下の通り。

引数名 意味 デフォルト値
in_units 入力層のユニット数 1
hidden_units 隠れ層のユニット数 2
out_units 出力層のユニット数 1

隠れ層の各ユニットはLSTM(Long Short Term Memory)、損失関数は2乗平均誤差である。in_unitsout_unitsは1に固定し(実数値を1つ受け取り実数値を1つ返す)、hidden_unitsの値を変えた時の精度の変化を見る(後述)。

訓練データの作成


 実装は以下の通りである。

-- make_data.py -- コンストラクタの引数の意味は以下の通り。

引数名 意味
steps_per_cycle 正弦波1周期の分割数
number_of_cycles 生成する周期の数

steps_per_cycleを50に、number_of_cyclesを100としてデータを作成した。関数makeは全データを1次元の配列(np.ndarray)に入れて返す。関数make_mini_batchは、長さlength_of_sequenceのデータをバッチサイズ分(mini_batch_size)だけ切り出す。

訓練


 実装は以下の通りである。

-- train.py -- プログラム冒頭の定数の意味は以下の通り。

引数名 意味
IN_UNITS 入力層のユニット数
HIDDEN_UNITS 隠れ層のユニット数
OUT_UNITS 出力層のユニット数
TRAINING_EPOCHS 訓練時のエポック数
DISPLAY_EPOCH ログを出力するタイミング
MINI_BATCH_SIZE ミニバッチの数
LENGTH_OF_SEQUENCE 学習する実数値のシーケンスの長さ
STEPS_PER_CYCLE 正弦波1周期の分割数
NUMBER_OF_CYCLES 周期の数

関数compute_lossでは、長さLENGTH_OF_SEQUENCEの配列をMINI_BATCH_SIZE個一括して処理を行っている(下図参照)。
また、LENGTH_OF_SEQUENCE$\times$MINI_BATCH_SIZE個のデータの塊を1epochと定義した。以下を実行する。 DISPLAY_EPOCH(上の場合は10)epoch ごとに訓練時の損失値が表示される。上記のパラメータのとき計算時間は27分ほどであった。

学習曲線


 下図はHIDDEN_UNITSの値を2,3,4,5に変えた時の学習曲線である。縦軸は損失(2乗平均誤差)の対数($\log_{10}$)を取った値である。10epoch毎に1回ずつ表示していので横軸の値を10倍したものが実際のepoch数である。
隠れ層のユニット数を増やすと損失は小さくなるが、3以上になるとそれほど差はないことが分る。

予測


 予測時のスクリプトは以下の通りである。

-- predict.py -- 上記のスクリプトでしていることを以下に図示する。
ここで、input_seqは最初に与える波形、pre_lengthはその波形をもとに予測する波形の長さを表す。例えば、input_seqの長さを4、pre_lengthを3とすると予測手順は以下のようになる。
  1. 4つの実数値の並びから最後の値を予測する(これを4とする)。
  2. 最初の値を捨てて4を最後尾に追加し、これを使って最後の値を予測する(これを5とする)。
  3. 最初の値を捨てて5を最後尾に追加し、これを使って最後の値を予測する(これを6とする)。
  4. (4,5,6)が求める予測値である。
input_seqの長さを50として、pre_lengthを50とした時の結果を以下に示す。
input_seqの長さを25として、pre_lengthを75とした時の結果を以下に示す。
隠れ層のユニットの数が多いほど精度は良い。しかし、いずれのユニット数の場合も、最初に与える波形から遠ざかるにつれて精度は悪くなる。

2016年7月18日月曜日

Fully Convolutional Networks 〜 Chainerによる実装 再考2 〜


はじめに


 先のページで、fcn32sを Chainer を使って実装した。今回は、fcn32sの訓練済みモデルを使って、fcn16sの学習を行う。

学習曲線


 最初に学習曲線を示す。

Accuracy
Loss
今回はEpoch60回で打ち切った(かろうじて収束していないように見えるが課金量の関係である)。テスト画像の正解率は94%程度となり前回の92%より向上した。このあとfcn8sを行うことになる。

計算機環境


 前回と同じく、Amazon EC2 にある g2.2xlarge を利用した。GPU を搭載したインスタンスである。今回もミニバッチ処理ができないので1枚ずつ学習する。

データセット


 訓練画像、テスト画像ともに前回と全く同じである。

ネットワークの構造


 ネットワークの構造は以下の通りである。
前回と同じである。上記の表では224$\times$224の正方形画像を想定してその1辺の長さだけをinputに記してあるが、縦横の長さは任意で構わない。表の各項目の意味は以下の通りである。
  1. name: 層の名前
  2. input: 入力featureマップの1辺のサイズ
  3. in_channels: 入力featureマップ数
  4. out_channels: 出力featureマップ数
  5. ksize: カーネルのサイズ
  6. stride: ストライドのサイズ
  7. pad: paddingのサイズ
  8. output: 出力featureマップの1辺のサイズ
今回はfcn16sを実装するのでpool4、pool5 の出力に接続する層(score-pool4、score-pool5)が必要である。これを通ったあとの出力データ名をそれぞれp4、p5とする。p4とp5のfeatureマップの数はクラスの数に等しくなる。
この表も、正方形画像を想定してその1辺の長さをinputに記してあるが縦横任意で構わない。出力p5はbilinear補間で2倍され、p4に加算される。そのあと、元画像と同じサイズに拡大され、ラベル画像と比較される。


ネットワークの実装


 上記の構造をそのままChainerで記述する。

-- myfcn_16s_with_any_size.py -- 物体の境界線には-1を配置し、softmax_cross_entropyの計算時に境界の寄与を無視するようにした。また、関数F.accuracyの引数 ignore_labelを使えば境界線上の画素を除いてaccuracyを計算することができる。112行目から113行目にかけて記述した関数でp5を2倍に拡大し、116行目でp4に加算している。122行目から123行目にかけて記述した関数で加算結果を16倍し、126行目でラベル画像との間のクロスエントロピーを計算している。

訓練


 訓練時のスクリプトは以下の通りである。

-- train_16s.py -- 関数 copy_model は前回と同じである。 train_16s.pyでしていることは、
  1. オブジェクトmini_batch_loader_with_any_sizeを作る。
  2. fcn32sで学習したモデルを読み込む。
  3. MyFcn16sWithAnySize.pyで定義されたネットワークのオブジェクトを作る。
  4. 学習済みモデルのパラメータをこれにコピーする。
  5. 最適化アルゴリズムとして MomentumSGD を選択する。
  6. あとは、通常の訓練過程である。
mini_batch_loader_with_any_size.pyは前回と同じである。

結果画像


 以下にテスト画像に適用した結果を示す。左の列はfcn32sの結果、中央の列はfcn16sの結果、右の列はGround Truthである。下に記した数値はaccuracyである。ここでaccuracyとは、1枚の画像の中で何%の画素が正解したかを計算したものである(境界線上の画素は除く)。

一番最後の画像以外は、精度は向上している。

ダウンロード


 ここの、タグが2016-07-17のものです。