O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Chainerの使い方と自然言語処理への応用

52.628 visualizações

Publicada em

第10回 NLP若手の会シンポジウム (YANS) のチュートリアルスライドです。ニューラルネットの(アルゴリズムとしての)おさらいと、Chainer v1.3.0の使い方を紹介しています。

Publicada em: Tecnologia
  • Entre para ver os comentários

Chainerの使い方と自然言語処理への応用

  1. 1. Chainerの使い⽅方と ⾃自然⾔言語処理理への応⽤用 NLP若若⼿手の会  2015/09/03  @和倉温泉 得居  誠也,  Preferred  Networks
  2. 2. ⾃自⼰己紹介 l  得居  誠也  (Seiya  Tokui)    @beam2d  (Twitter,  GitHub) l  PFI  (2012-‐‑‒2014)  -‐‑‒>  PFN  (2014-‐‑‒) l  専⾨門:機械学習 –  ⾃自然⾔言語処理理(品詞タグ付け)、近傍探索索のためのハッシング(修⼠士) –  Deep  Learning(2012年年秋ごろ〜~)、画像・映像認識識 l  4  ⽉月に  Chainer  を作り始めて今はこれがメイン 2
  3. 3. Chainer サイト:  http://chainer.org ドキュメント:  http://docs.chainer.org GitHub:  https://github.com/pfnet/chainer l  Deep  Learning  のフレームワーク l  Python  ライブラリとして提供 l  最新版は  v1.3.0  (2015/9/3現在) 3
  4. 4. 今⽇日のおはなし l  Chainer  の使い⽅方を紹介します –  Deep  Learning  のおさらいも簡単にしますが、学術的な詳細は既存の⽂文献 を参考にしてください –  CUDA  サポートについても解説しますが、CUDA  の詳細は  NVIDIA  のド キュメントを参照してください l  ⾃自然⾔言語処理理への応⽤用⽅方法を紹介します –  Recurrent  Net  などのよく知られた結果を  Chainer  で実装する⽅方法を紹介 します 4
  5. 5. ニューラルネットの基礎
  6. 6. ニューラルネット l  値が伝播していく有向グラフ l  エッジで重みをかけて、ノードに⼊入るところで⾜足し込み、ノードの中で⾮非線形 変換する l  全体としては巨⼤大で複雑な関数を表す 6
  7. 7. ニューラルネット=合成関数 l  ニューラルネットは、ベクトルに対して線形・⾮非線形な関数をたくさん適⽤用す る合成関数と捉えるとよい –  ベクトルをまとめると上図のように –  まとめる理理由は⼆二つ u  わかりやすい/扱いやすいから u  ベクトル演算によって⾼高速化しやすいから l  各ノードはベクトルを保持する変数 –  紫のノードは  “中間変数” 7
  8. 8. ⼀一般のニューラルネットは  DAG  =  計算グラフ l  ⼀一般にはグラフが分岐したり合流流したりする l  分岐:同じ変数を複数の場所でつかう l  合流流:⼆二つ以上の変数を受け取る関数を適⽤用する 8
  9. 9. 計算グラフの例例 l  このグラフは  z = x ** 2 + 2 * x * y + y  という式を表す 9 x y _ ** 2 2 * _ _ * _ _ + _ z _ + _
  10. 10. 誤差逆伝播(後退型⾃自動微分) l  合成関数の微分を計算するには連鎖律律  (chain  rule)  をつかう l  たとえば                                                                                                                          を微分すると –  ヤコビ⾏行行列列の掛け算になっている l  ニューラルネットの最適化では、⽬目的関数はスカラーで、微分したいパラメー タや中間変数は⾼高次元のベクトル l  上の式でいえば          がスカラーで、                            はベクトル l  この場合(上の式で)左からかけていったほうが効率率率が良良い –  つまり        (出⼒力力)から        (⼊入⼒力力)に向けてヤコビ⾏行行列列を順にかけていく –  もとの関数と逆順なので誤差逆伝播法という 10 z z = h(y), y = g(x), x = f(w) z w = z y y x x w = Dh(y)Dg(x)Df (w) w, x, y z w
  11. 11. 誤差逆伝播は、計算グラフを逆向きにたどる l  計算グラフと順伝播時の各変数の値があれば計算可能 11
  12. 12. Recurrent  Net l  ループがあるニューラルネット l  時刻の概念念があり、t=T  の状態は  t=T-‐‑‒1  の状態と  t=T  の⼊入⼒力力を使って求める 12 T T-1 T
  13. 13. Recurrent  Net  は時間展開して考える l  時間展開すれば、DAG  の計算グラフになる l  DAG  の計算グラフは誤差逆伝播できる(Backprop  Through  Time) 13 t=1 t=2 t=3 t=4
  14. 14. Truncated  BPTT l  ⻑⾧長い系列列を学習するとき、計算グラフが⻑⾧長⼤大になり計算コストがかかる l  古い情報を忘れて(グラフを切切り落落として)計算コストを削減するのが   Truncated  BPTT(勾配は不不正確になる) 14 t=1 t=2 t=3 t=4 Truncated
  15. 15. Chainer の使い⽅方
  16. 16. Chainer  はニューラルネットのフレームワーク l  ニューラルネットをつかうためには最低限以下の機能が必要 –  ニューラルネットを記述する –  ニューラルネットの順伝播・逆伝播を実⾏行行する –  勾配法を実⾏行行してパラメータを最適化する l  Chainer  はこれらを  Python  上で実装したもの l  Chainer  の特徴 –  順伝播は単純に  Python  のスクリプトとして書ける –  そのスクリプトの実⾏行行結果は計算⼿手順を記憶していて、逆伝播を⼿手で書く必 要はない 16
  17. 17. Chainer  のインストール l  環境は  Linux(特に  Ubuntu)がおすすめです l  インストール⽅方法 –  新しめの  Python  環境を⽤用意(CPython  2.7+  または  3.4+) –  pip  も⽤用意 –  コマンドを実⾏行行:  pip install chainer –  chainer  パッケージが  import  できれば完了了です l  Python  スタックの環境構築は、Anaconda  がおすすめです l  Python  のバージョン管理理は  pyenv  がおすすめです(慣れてるものがある⽅方は そちらで  OK  です) –  pyenv  からコマンド⼀一つで  Anaconda  もインストールできます 17
  18. 18. 順伝播 l  今まで「変数」と呼んでいたものは、Chainer  では  Variable  オブジェクト l  Variable  オブジェクトを特殊な「関数」に⼊入れると、順伝播を実⾏行行しながら計 算グラフが構築される –  「関数」は  Function  オブジェクト –  簡単な四則演算などは  Variable  オブジェクト⾃自体に定義されている –  ほかの  Function  は  chainer.functions(F と略略記)にたくさん⽤用意さ れている x = Varaible(...) y = Variable(...) z = x ** 2 + 2 * x * y + y 18 x y _**2 2*_ _*_ _+_ z _+_
  19. 19. Variable  オブジェクト l  計算グラフの(データ)ノード l  NumPy  または  CuPy(後述)の配列列を保持する –  初期化時に配列列を渡す –  data  属性に保存される x = Variable(np.zeros((10, 20), dtype=np.float32)) x.data #=> セットした配列列が取り出せる l  多くの  Function  は配列列の最初の軸をミニバッチとして使うので注意 –  例例えば上の  x  は、20  次元ベクトルが  10  個⼊入ったミニバッチとみなす l  現状、Chainer  は多くの場所で  float32  配列列を要求するので注意(NumPy/ CuPy  はデフォルトの⼩小数型が  float64) 19
  20. 20. Function  オブジェクト l  計算グラフの「演算」ノード l  chainer.functions (=: F)  にいろいろ定義されている l  パラメータつきの  Function –  F.Linear, F.Convolution2D, F.EmbedID, ... –  あらかじめ定義しておいて、順伝播の計算時につかう l  パラメータなしの関数 –  F.relu, F.max_pooling_2d, F.lstm, ... –  Variable  オブジェクトを返すただの  Python  関数が提供されているので、 順伝播のときに直接つかう 20
  21. 21. FunctionSet  でパラメータつき関数をまとめる l  パラメータ付きの  Function  オブジェクトは複数のイテレーションで使いまわす ので、あらかじめ作っておく l  FunctionSet  を使うと、これらをまとめて管理理できる model = FunctionSet(embed=F.EmbedID(10000, 100), layer1=F.Linear(100, 100), layer2=F.Linear(100, 10000)) def forward(x): h = F.relu(model.layer1(model.embed(x))) return model.layer2(h) 21
  22. 22. ロス関数、勾配計算 l  様々なロス関数が定義されている –  F.softmax_cross_entropy, F.mean_squared_error –  パラメータ付きのロス関数もある:  F.NegativeSampling, F.BinaryHierarchicalSoftmax l  ロス関数を計算したら、Variable.backward()  でそのロス値の勾配を求める def forward(x, t): h = F.relu(model.layer1(model.embed(x))) return F.softmax_cross_entropy(model.layer2(h), t) loss = forward(x) loss.backward() 22
  23. 23. Optimizer  の設定 l  勾配が計算できたら、あとは勾配法をまわす l  勾配法のアルゴリズムはみな  Optimizer  クラスの⼦子クラス –  chainer.optimizers  に定義されている –  実装されている最適化⼿手法:SGD, MomentumSGD, AdaGrad, RMSprop, RMSpropGraves, AdaDelta, Adam l  パラメータと勾配の配列列をあらかじめ  setup  メソッドに渡しておく必要がある l  FunctionSet  をつかう場合、簡単にわたせる optimizer = optimizers.SGD() optimizer.setup(model) 23
  24. 24. Optimizer  による最適化 l  Optimizer  を使う⼿手順 –  まず勾配をゼロ初期化:zero_̲grads() –  順伝播・逆伝播を実⾏行行 –  必要なら正則化メソッドを実⾏行行:weight_̲decay(),  clip_̲grads() –  最適化ルーチンを実⾏行行:update() optimizer.zero_grads() loss = forward(x, t) loss.backward() optimizer.weight_decay(0.005) optimizer.update() 24
  25. 25. Chainer  を使う場合の全体の流流れ 1.  FunctionSet  にパラメータ付き関数を定義する 2.  Optimizer  を定義して、FunctionSet  を設定する 3.  forward  関数を定義する 4.  データセットを読み込み、訓練⽤用と評価⽤用にわける 5.  訓練ループを回す a.  勾配をゼロ初期化 b.  forward  関数を呼び、得られたロス値の  backward  メソッドを呼ぶ c.  正則化処理理をして、update 6.  適当な頻度度で評価ループを回す a.  forward  関数を呼んで結果を記録 25
  26. 26. 例例:MNIST # Model definition model = FunctionSet( l1=F.Linear(784, 100), l2=F.Linear(100, 100), l3=F.Linear(100, 10)) opt = optimizers.SGD() opt.setup(model) # Forward computation def forward(x, t): h1 = F.relu(model.l1(x)) h2 = F.relu(model.l2(h1)) y = model.l3(h2) return F.softmax_cross_entropy( y, t) # Training loop for epoch in xrange(n_epoch): for i in xrange(0, N, batchsize): x = Variable(...) t = Variable(...) opt.zero_grads() loss = forward(x, t) loss.backward() opt.update()
  27. 27. 新しい  Function  を⾃自分で定義する l  Function  は  Python  で新しく作ることができる l  forward(_̲cpu/_̲gpu)  と  backward(_̲cpu/_̲gpu)  を実装する必要がある l  これらは配列列のタプルを受け取って、配列列のタプルを返す class SquaredDiff(Function): def forward_cpu(self, inputs): x, y = inputs z = x – y return z * z, def backward_cpu(self, inputs, grad_outputs): x, y = inputs gz = grad_outputs gx = 2 * (x – y) * gz return gx, -gx 27
  28. 28. 新しい  Function  を⾃自分で定義する l  Function  を書いたらテストしましょう l  とくに勾配チェック  (gradient  check)  は必須 –  有限差分法で  forward  のみから計算した勾配が、backward  で計算した勾 配と⼀一致するかを確かめる –  chainer.gradient_check.numerical_grad  を使うと簡単に書ける l  公式リポジトリの  tests/chainer_̲tests/function_̲tests  にたくさん例例が書いて あります 28
  29. 29. CUDA  サポート l  Chainer  v1.3.0  が昨⽇日リリース l  CuPy:  新しい  CUDA  配列列実装 –  NumPy  と同じようなインターフェイスで使える u  関数・メソッドのサブセットを実装 u  配列列のスライス、転置、reshape  等も⾃自由にできます –  カスタムカーネルも記述できる(elementwise,  reduction) 29
  30. 30. CuPy  を使う準備 l  まず  CUDA  が使える  GPU  を⽤用意する l  CUDA  6.5  以上をインストール –  Ubuntu  なら公式に  deb  パッケージが配布されているのでそれをつかうの がお⼿手軽です l  パスを通す –  PATH  と  LD_̲LIBRARY_̲PATH  を通す必要があります –  公式インストーラからはデフォルトで  /usr/local/cuda  にインストールさ れるので、以下のように設定 u  PATH=/usr/local/cuda/bin:$PATH u  LD_̲LIBRARY_̲PATH=/usr/local/cuda/lib64:$LD_̲LIBRARY_̲PATH l  Chainer  をインストールしたら  cupy  モジュールを  import  してみて動くか確 認 30
  31. 31. CuPy  の使い⽅方 l  基本的に  numpy  の代わりに  cupy  を使う以外は  NumPy  と⼀一緒 l  CPU/GPU  の両⽅方で動く関数の書き⽅方 –  chainer.cuda.get_array_module()  を使うと、引数に  cupy.ndarray   があるかないかで  numpy  /  cupy  のどちらかを返してくれます –  例例えば下は  NumPy  と  CuPy  の両⽅方で動く  logsumexp  の実装例例(より省省 メモリな実装を考えてみてください) def logsumexp(x, axis=None): xp = cuda.get_array_module(x) x_max = x.max(axis=axis) return x_max + xp.log(xp.exp(x – x_max).sum(axis=axis)) 31
  32. 32. ⾃自然⾔言語処理理への応⽤用 32
  33. 33. 単語埋め込み l  単語を  ID  で表したものを対応する密ベクトルに変換する –  この密ベクトルも学習の対象 l  F.EmbedID  がこれを実装している –  パラメータ付きの  Function –  つくるときに  ID  の範囲と密ベクトルの次元を指定する –  int32  配列列が⼊入った  Variable  を受け取って、float32  配列列が⼊入った   Variable  を返す l  例例えば  1  万語彙を  200  次元に埋め込みたい場合は以下のようにする embedder = F.Embed(10000, 200) word_arr = np.ndarray((10,), dtype=np.int32) word = Variable(word_arr) x = embedder(word) #=> サイズ  10 x 200  の配列列が⼊入った変数 33
  34. 34. Recurrent  Net l  時刻を  1  ステップ分だけ実⾏行行する関数を書いて、それを  for  ⽂文の中から呼び出 す l  リカレントな部分は、状態を保持する変数を持っておいてループの中でつかう l  内部的には展開された  DAG  が作られる def forward_one_step(x, h, t): h = F.tanh(model.input(x) + model.lateral(h)) y = model.output(h) return F.softmax_cross_entropy(y, t), h h = Variable(np.zeros((1, 200), dtype=np.float32)) accum_loss = 0 for x, t in input_seq: loss, h = forward_one_step(x, h, t) accum_loss += loss 34
  35. 35. 例例:RNN  ⾔言語モデル # Model definition model = FunctionSet( emb=F.EmbedID(1000, 50), h2h=F.Linear( 50, 50), h2y=F.Linear( 50, 1000)) opt = optimizers.SGD() opt.setup(model) # Forward computation of one step def fwd1step(h, w, t): x = model.emb(w) h = F.tanh(x + model.h2h(h)) y = model.h2y(h) return F.softmax_cross_entropy( y, t), h # Full RNN forward computation def forward(seq): h = Variable(...) # init state accum_loss = 0 for curw, nextw in zip(seq, seq[1:]): x = Variable(curw) t = Variable(nextw) loss, h = fwd1step(h, x, t) accum_loss += loss return accum_loss
  36. 36. Long  Short-‐‑‒Term  Memory l  ⻑⾧長期の依存関係をとらえるのに  LSTM  はシグモイド関数よりもよい挙動を⽰示す l  F.lstm  に実装されている l  これは  2  引数  2  出⼒力力の関数 –  「セル」と「⼊入⼒力力」を受け取り、「新しいセル」と「次の状態」を出⼒力力 –  ⼊入⼒力力は、各ユニットごとに  4  種類の値からなる:⼊入⼒力力、⼊入⼒力力ゲート、忘却 ゲート、出⼒力力ゲート –  この  4  つの値を  2  番⽬目の次元につめた⾏行行列列を受け取る u  単純に、LSTM  ユニット数の  4  倍のサイズの⼊入⼒力力ベクトルをとると思え ばOK 36
  37. 37. 例例:LSTM  RNN  ⾔言語モデル # Model definition model = FunctionSet( emb=F.EmbedID(1000, 50*4), h2h=F.Linear( 50, 50*4), h2y=F.Linear( 50, 1000)) opt = optimizers.SGD() opt.setup(model) # Forward computation of one step def fwd1step(c, h, w, t): x = model.emb(w) c, h = F.lstm( c, x + model.h2h(h)) y = model.h2y(h) return F.softmax_cross_entropy( y, t), c, h # Full RNN forward computation def forward(seq): c = Variable(...) # init cell h = Variable(...) # init state accum_loss = 0 for curw, nextw in zip(seq, seq[1:]): x = Variable(curw) t = Variable(nextw) loss, c, h = fwd1step( c, h, x, t) accum_loss += loss return accum_loss
  38. 38. unchain_̲backward  による  Truncated  BPTT l  Truncated  BPTT  は  unchain_backward()  を使うことで実装できる –  Variable  から逆向きに計算グラフをたどったときに通る辺をすべて計算グ ラフから取り除く –  Python  変数に保持している  Variable  オブジェクトはそのまま残る accum_loss = 0 for i, x in enumerate(batches): loss, h = forward_on_step(*x) # forward accum_loss += loss if i % 30 == 0: optimizer.zero_grads() accum_loss.backward() # backward accum_loss.unchain_backward() # truncate graph optimizer.update() accum_loss = 0 38
  39. 39. 公式の  Examples 公式リポジトリの  examples  ディレクトリにいくつか例例があります l  mnist:  MNIST  を多層パーセプトロンで学習するもっとも基本のサンプル l  imagenet:  ImageNet  からの⼤大規模ConvNet学習 l  modelzoo:  Caffe  公式モデルを読み込んでつかう l  ptb:  Penn-‐‑‒Tree  Bank  から  LSTM  ⾔言語モデルを学習する –  無限⻑⾧長の⼊入⼒力力に対する  Truncated  BPTT  の例例にもなっています l  word2vec:  word2vec  の実装と  PTB  からの学習 l  sentiment:  Recursive  Net  を使った極性判定 39
  40. 40. まとめ l  ニューラルネットを(おもに実装⾯面から)簡単におさらいしました l  Chainer  の使い⽅方をざっくりお伝えしました l  このチュートリアルをもとに、Chainer  を使って⾃自然⾔言語処理理でなにか作って 公開、または論論⽂文発表していただけると⼤大変うれしいです l  Chainer  ⾃自体へのフィードバックもお待ちしております!!! 40

×