Chainerチュートリアル -v1.5向け- ViEW2015

42
Chainerチュートリアル - v1.5向け - 2015/12/04 ViEW 2015@パシフィコ横浜 (株)Preferred Networks 奥田 遼介

Transcript of Chainerチュートリアル -v1.5向け- ViEW2015

Page 1: Chainerチュートリアル -v1.5向け- ViEW2015

Chainerチュートリアル- v1.5向け -

2015/12/04 ViEW 2015@パシフィコ横浜

(株)Preferred Networks

奥田 遼介

Page 2: Chainerチュートリアル -v1.5向け- ViEW2015

Chainer(http://chainer.org/)

3

Chainer の使い方を紹介します

Deep Learning の簡単な説明から実装へ

CUDA サポートについても簡単に解説します

学術的な詳細は既存の文献を参考にしてください

CUDA の詳細は NVIDIA のドキュメントを参照してください

Page 3: Chainerチュートリアル -v1.5向け- ViEW2015

ニューラルネットの基礎と実装準備

Page 4: Chainerチュートリアル -v1.5向け- ViEW2015

ニューラルネット

値が伝播していく有向グラフ

エッジで重みをかけて、ノードに入るところで足し

込み、ノードの中で非線形変換する

全体としては巨大で複雑な関数を表す

5

Page 5: Chainerチュートリアル -v1.5向け- ViEW2015

ニューラルネット=合成関数

ベクトルに対して線形・非線形な関数をたくさん適

用する合成関数と捉えるとよい

各ノードはベクトルを保持する変数

6

Page 6: Chainerチュートリアル -v1.5向け- ViEW2015

一般のニューラルネットは DAG = 計算グラフ

一般にはグラフが分岐したり合流したりする

分岐:同じ変数を複数の場所でつかう

合流:二つ以上の変数を受け取る関数を適用する

7

Page 7: Chainerチュートリアル -v1.5向け- ViEW2015

計算グラフの例

z = x ** 2 + 2 * x * y + y

8

x

y

_ ** 2

2 * _ _ * _ _ + _ z

_ + _

z x x y y

Page 8: Chainerチュートリアル -v1.5向け- ViEW2015

機械学習のおさらい

多くの機械学習手法は、

1. 目的関数の設計

2. 勾配の計算

3. 最小化のための反復計算

からなる

9

先ほどの計算はここに使う

Page 9: Chainerチュートリアル -v1.5向け- ViEW2015

機械学習の例:分類学習の目的関数

10

argminw ∑(x, y) l(x, y; w)

xは入力ベクトル、yは予測ラベル

l(x, y)は予測が正しければ小さく、間違えれば大

きくなる値(損失関数)

上記関数を最小化するパラメータwを求めたい

Page 10: Chainerチュートリアル -v1.5向け- ViEW2015

機械学習の例:分類学習のアルゴリズム

目的関数をパラメータwで微分した値(勾配)を

計算する方法を用意する

wを勾配の方向に少しだけ動かす、を繰り返す

実際は更新方向の取り方に工夫が他数ある

11

initialize w

until converge:

w := w - η d/dw L(x, y; w)

最急降下法

Page 11: Chainerチュートリアル -v1.5向け- ViEW2015

誤差逆伝播(後退型自動微分)

合成関数の微分を計算するには連鎖律 (chain rule)

をつかう

12

各関数の微分がわかれば機械的に計算できる

Page 12: Chainerチュートリアル -v1.5向け- ViEW2015

誤差逆伝播は、計算グラフを逆向きにたどる

計算グラフと順伝播時の各変数の値があれば計算可能

13

Page 13: Chainerチュートリアル -v1.5向け- ViEW2015

ニューラルネットの学習方法

1. 目的関数の設計

計算グラフを自分で設計する

2. 勾配の計算

誤差逆伝播で機械的に計算できる

3. 最小化のための反復計算

勾配を使って反復更新する

14

1は設計が必要2、3は自動化されている

Page 14: Chainerチュートリアル -v1.5向け- ViEW2015

Recurrent Net

ループがあるニューラルネット

時刻の概念があり、t=T の状態は t=T-1 の状態と t=T の入力

を使って求める

15

T

T-1

T

Page 15: Chainerチュートリアル -v1.5向け- ViEW2015

Recurrent Net は時間展開して考える

時間展開すれば、DAG の計算グラフになる

DAG の計算グラフは誤差逆伝播できる(Backprop Through

Time)16

t=1

t=2

t=3

t=4

Page 16: Chainerチュートリアル -v1.5向け- ViEW2015

Chainer の使い方

Page 17: Chainerチュートリアル -v1.5向け- ViEW2015

Chainer はニューラルネットのフレームワーク

機能

ニューラルネットを順伝播を記述する

ニューラルネットの順伝播・逆伝播を実行する

勾配法を実行してパラメータを最適化する

Chainer の特徴

順伝播は単純に Python のスクリプトとして書ける

そのスクリプトで実行した計算手順を記録されて、

逆伝播を内部で自動生成する

18

Page 18: Chainerチュートリアル -v1.5向け- ViEW2015

ニューラルネットワークフレームワークの構成要素

構成要素 Chainerの場合

変数 chainer.Variable

関数(損失関数/活性化関数)

chainer.Functionを継承

パラメーター付き関数 chainer.Linkを継承

パラメーター付き関数集合 chainer.Chainを継承

最適化 chainer.Optimizer

19

大きく分けて三要素 変数・関数・最適化

Page 19: Chainerチュートリアル -v1.5向け- ViEW2015

Chainer のインストール

環境は Linux(特に Ubuntu)がおすすめ

インストール方法 新しめの Python 環境を用意(CPython 2.7+, 3.4+, 3.5+)

pip も用意

コマンドを実行

pip install -U cython

pip install chainer

chainer パッケージが import できれば完了です

Python 環境は、Anaconda がおすすめ

Python のバージョン管理は pyenv がおすすめ pyenv からコマンド一つで Anaconda もインストールできます

20

Page 20: Chainerチュートリアル -v1.5向け- ViEW2015

順伝播

今まで「変数」と呼んでいたものは、Chainer で

は Variable オブジェクト

Variable を Function に入れると、順伝播後の

Variable が返ってくる

Variable が計算グラフを保持している

Function は、四則演算以外に

chainer.functions に用意されている

21

Page 21: Chainerチュートリアル -v1.5向け- ViEW2015

順伝播とコード例

22

x = Varaible(...)

y = Variable(...)

z = x ** 2 + 2 * x * y + y

x

y

_ ** 2

2 * _ _ * _ _ + _ z

_ + _

Page 22: Chainerチュートリアル -v1.5向け- ViEW2015

Variable オブジェクト

計算グラフの(データ)ノード

NumPy または CuPy(後述)の配列を保持する

初期化時に配列を渡す

data 属性に保存される

多くの Function は配列の最初の軸をミニバッチとして使

うので注意

下の x は、20 次元ベクトルが 10 個入ったミニバッチとみなす

現状、Chainer は多くの場所で float32 配列を要求するの

で注意

23

x = Variable(np.zeros((10, 20),

dtype=np.float32))

x.data

Page 23: Chainerチュートリアル -v1.5向け- ViEW2015

Function オブジェクト

計算グラフの「演算」ノード

chainer.functions (以降 F) にいろいろ定義され

ている F.relu, F.max_pooling_2d, F.lstm, ...

Functionの呼び出し結果が、再びVariableになる

v1.5からパラメータはLinkとして分離された(後述)

24

x = Variable(...)

y = F.relu(x) # yもVariable

Page 24: Chainerチュートリアル -v1.5向け- ViEW2015

Link オブジェクト

パラメータ付きの関数

最適化の対象となる

save/loadができる(v1.5からsave/loadをサポート)

chainer.links(以降L)に色々用意されている

L.Linear, L.Convolution2D, L.EmbedID, ...

Linkの呼び出し結果が、再びVariableになる

v1.5からFunctionとパラメータは分離され、パラメータ

付きの関数はLinkオブジェクトになった

25

v1.5~

Page 25: Chainerチュートリアル -v1.5向け- ViEW2015

ChainでLinkをまとめる

一般的にパラメータ付きの関数(Link)は複数あるので、

Chainでまとめて管理できる

Chainを継承すると再利用しやすくなる

model = Chain(embed=L.EmbedID(10000, 100),

layer1=L.Linear(100, 100),

layer2=L.Linear(100, 10000))

x = Variable(...)

h = F.relu(model.layer1(model.embed(x)))

y = model.layer2(h)

26

v1.5~

Page 26: Chainerチュートリアル -v1.5向け- ViEW2015

ロス関数、勾配計算

ロス関数もFunctionの一種

ロス関数の出力に、Variable.backward()を呼ぶと

勾配が計算できる

loss = F.softmax_cross_entropy(y, t)

loss.backward()

27

Page 27: Chainerチュートリアル -v1.5向け- ViEW2015

Optimizer の設定

勾配が計算できたら、あとは勾配法をまわす

勾配法のアルゴリズムは Optimizer クラスの子クラス chainer.optimizersに定義されている

実装されている最適化手法:SGD, MomentumSGD, AdaGrad,

RMSprop, RMSpropGraves, AdaDelta, Adam

最適化対象をsetup メソッドに渡す

正則化はhook関数として登録する

optimizer = optimizers.SGD()

optimizer.setup(model)

optimizer.add_hook(optimizer.WeightDecay())

28

Page 28: Chainerチュートリアル -v1.5向け- ViEW2015

Optimizer による最適化

まず勾配をゼロ初期化:zerograds()

順伝播・逆伝播を実行

最適化ルーチンを実行:update()

以上を何回も繰り返す

model.zerograds()

loss = ...

loss.backward()

optimizer.update()

29

Page 29: Chainerチュートリアル -v1.5向け- ViEW2015

Chainer を使う場合の全体の流れ

1. Linkを使ってChainを定義する

2. Optimizer に、Chain を設定する

3. forward 関数を定義する

4. データセットを読み込み、訓練用と評価用にわける

5. 訓練ループを回す

a. 勾配をゼロ初期化

b. 順伝播して、得られたロス値の backward メソッドを呼ぶ

c. Optimizerを、update

6. 適当な頻度で評価ループを回す

a. テストデータで順伝播関数を呼んで結果を記録

30

Page 30: Chainerチュートリアル -v1.5向け- ViEW2015

例:MNIST

# Model definition

class MnistMLP(chainer.Chain):

def __init__(self, n_in,

n_units, n_out):

super(MnistMLP, self).__init__(

l1=L.Linear(n_in, n_units),

l2=L.Linear(n_units, n_units),

l3=L.Linear(n_units, n_out))

# Forward computation

def __call__(self, x):

h1 = F.relu(self.l1(x))

h2 = F.relu(self.l2(h1))

return self.l3(h2)

# Setup

model = L.Classifier(net.MnistMLP(

784, n_units, 10))

opt = optimizers.SGD()

opt.setup(model)

# Training loop

for epoch in xrange(n_epoch):

for i in xrange(0, N, batchsize):

x = Variable(...)

t = Variable(...)

opt.update(model, x, t)

Page 31: Chainerチュートリアル -v1.5向け- ViEW2015

新しい Function を自分で定義する

Function は Python で新しく作ることができる

forward(_cpu/_gpu) と backward(_cpu/_gpu) を実装する必

要がある

配列のタプルを受け取って、配列のタプルを返す

Linkは内部でFunctionを呼んで作る

32

Page 32: Chainerチュートリアル -v1.5向け- ViEW2015

自作Functionの例

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

33

tupleを返す

勾配をtupleで返す

Page 33: Chainerチュートリアル -v1.5向け- ViEW2015

新しい Function を自分で定義する

Function を書いたらテストしましょう

とくに勾配チェック (gradient check) は必須 有限差分法で forward のみから計算した勾配が、backward で計

算した勾配と一致するかを確かめる

chainer.gradient_check.numerical_grad を使うと簡単

に書ける

公式リポジトリの

tests/chainer_tests/function_tests にたくさん例

が書いてあります

34

Page 34: Chainerチュートリアル -v1.5向け- ViEW2015

CUDA サポート

CuPy: 新しい CUDA 配列実装

NumPy と同じようなインターフェイスで使える

関数・メソッドのサブセットを実装

配列のスライス、転置、reshape 等も自由にできます

カスタムカーネルも記述できる(elementwise, reduction)

35

Page 35: Chainerチュートリアル -v1.5向け- ViEW2015

CuPy を使う準備

まず CUDA が使える GPU を用意する

CUDA 6.5 以上をインストール Ubuntu なら公式に deb パッケージがお薦め(aptがdriverも管理してくれる)

パスを通す PATH を通すことが必要

CuPyはnvccのパスからライブラリの場所を見つけます

デフォルトでは /usr/local/cuda にインストールされます

PATH=/usr/local/cuda/bin:$PATH

Chainer をインストールしたらimport cupyで動作を確認

36

Page 36: Chainerチュートリアル -v1.5向け- ViEW2015

cuDNNの使い方

cuDNN

NNの計算を省メモリで高速におこなってくれるライブラリ

特にConvolutionに効果がある

cuDNNは画像系では超重要(メモリ使用量が数分の1に減る場合も)

NVIDIAのページでユーザー登録してダウンロード

ダウンロードできるようになるまで数日かかります

インストーラーはありません

展開して手動でCUDAのフォルダにコピー(おすすめ)

lib64とinclude に対応するファイルを放り込む

もしくはパスを通す

CPATH、 LIBRARY_PATH、LD_LIBRARY_PATHの設定が必要

CuDNNを導入したらChainerを再インストール

import cupy.cudnnで動作を確認

37

Page 37: Chainerチュートリアル -v1.5向け- ViEW2015

CuPy の使い方

numpy の代わりに cupy を使う(だいたい動く)

CPU/GPU の両方で動く関数の書き方 chainer.cuda.get_array_module()を使うと、引数に

cupy.ndarray があるかないかで numpy / cupy のどちらかを返してくれ

ます

例えば下は NumPy と CuPy の両方で動く logsumexp の実装例(より省

メモリな実装を考えてみてください)

38

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))

Page 38: Chainerチュートリアル -v1.5向け- ViEW2015

公式の Examples

公式リポジトリの examples にいくつか例があります

画像系

mnist: MNIST を多層パーセプトロンで学習。NN界のHello World

imagenet: ImageNet からの大規模ConvNet学習

modelzoo: Caffe 公式モデルを読み込んで使うサンプル

言語系

ptb: Penn-Tree Bank から LSTM 言語モデルを学習する

無限長の入力に対する Truncated BPTT の例にもなっています

word2vec: word2vec の実装と PTB からの学習

sentiment: Recursive Net を使った極性判定

39

Page 39: Chainerチュートリアル -v1.5向け- ViEW2015

Chainer を使う利点

Pythonで書ける

NumPyが書ければCuPyを使ってGPU化できる

自作のレイヤーも前処理もPythonで書ける

CuPyを使うことでPythonのまま簡単にGPU化

ループや複雑な分岐があるNNも直感的に書ける

Pythonの制御構文でNNのforward処理が書ける

Define by Run

デバッグが楽

Pythonのスタックトレースを活用してのデバッグが可能

ファンクションの中身もほとんどPythonコード

NNのバグの原因がどの行で起きているかが分かる

40

Page 40: Chainerチュートリアル -v1.5向け- ViEW2015

Chainer 1.5が正しくインストールできないときは?

v1.5 からHDF5とCythonに依存 周辺パッケージとの兼ね合いでインストールにちょっとしたテ

クニックが必要

ログを活用する pip install chainer –vvvv

何が問題かが分かります

Cythonをあらかじめインストール pip install -U cython

メモリを食いつぶすエラーを防げます

sudo に注意する

環境変数が引き継がれません

「Chainer 1.5 インストール」で検索

対処法が出てきます 41

Page 41: Chainerチュートリアル -v1.5向け- ViEW2015

まとめ

ニューラルネットを実装面から簡単におさらいしました

Chainer の構成と使い方をざっくりお伝えしました

本チュートリアルを参考にChainer を使っていただけれ

ば幸いです

Chainer 自体へのフィードバックもお待ちしております

42

Page 42: Chainerチュートリアル -v1.5向け- ViEW2015

ご清聴ありがとうございました

43

We are Hiring!

https://www.preferred-networks.jp/job_ja