• 検索結果がありません。

スケジュール 第1回 (1/10): ガイダンス ニューラルネット概論と肩慣らし 第2回 (1/15): 誤差逆伝播のミニ講義と実装 作ってわかる深層学習 山 匡 (MIコース) 第3回 (1/17): 手書き文字認識のテスト 第4回 (1/22): 自己符号化器のミニ講義と実装 第5回 (1/24

N/A
N/A
Protected

Academic year: 2021

シェア "スケジュール 第1回 (1/10): ガイダンス ニューラルネット概論と肩慣らし 第2回 (1/15): 誤差逆伝播のミニ講義と実装 作ってわかる深層学習 山 匡 (MIコース) 第3回 (1/17): 手書き文字認識のテスト 第4回 (1/22): 自己符号化器のミニ講義と実装 第5回 (1/24"

Copied!
6
0
0

読み込み中.... (全文を見る)

全文

(1)

2017年度 MI/CS実験第2 第4ラウンド

匡 (MIコース)

「作ってわかる深層学習」

2回目スライド資料

スケジュール

第1回 (1/10): ガイダンス、ニューラルネット概論と肩慣らし

第2回 (1/15): 誤差逆伝播のミニ講義と実装

第3回 (1/17): 手書き文字認識のテスト

第4回 (1/22): 自己符号化器のミニ講義と実装

第5回 (1/24): 実装

第6回 (1/29): 実装

パーセプトロン

パーセプトロン

Rosenblat (1958)

パーセプトロン

Rosenblat (1958)

世界で最初のニューラルネット

第一次ブームの火付け役

3層構造 (入力・中間・出力)

教師付学習機械

教師信号

パーセプトロンの特徴

中間層に多数のニューロン

入力層∼中間層の結合は

スパースかつランダムで

固定

→ (教師付)学習

教師信号

中間層∼出力層の結合重みを

教師信号を使って変化させる

教師信号

教師付学習

文脈信号 (

x) と教師信号 (z)のペア

n種類

x

(i)

を入力層に入れると

z

(i)

を出力

するように重みを変える

→ (教師付)学習

誤差

を定義して、これを減らす

E =

!

n

1

2

"

"z

(teacher)

n

− z

(output)

n

"

"

2

D = {(x

(1)

, z

(1)

)

, · · · , (x

(

n)

, z

(

n)

)

}

ベクトル

学習ルール (パーセプトロン則)

E =

!

n

1

2

"

"z

(teacher)

n

− z

(output)

n

"

"

2

誤差

dw

(hidden)

dt

= −

∂E

∂w

(hidden)

計算する式

w

(hidden)

(

t + 1) = w

(hidden)

(

t) − η

∂E

∂w

(hidden)

= w

(hidden)

(

t) − η∇E

w

(hidden)

エポック数に

関して離散化

ベクトル

学習係数

w

(hidden)

(

t + 1) = w

(hidden)

(

t) − η

!

n

∂E

n

∂w

(hidden)

= w

(hidden)

(

t) − η

!

n

∇E

n,w

(hidden)

個々のサンプル

に関して書くと

E =

!

n

E

n

E

n

=

1

2

!

i

"

z

(teacher)n i

− z

(output)n i

#

2

(2)

学習ルール (パーセプトロン則)

w

(hidden)

(

t + 1) = w

(hidden)

(

t) − η

!

n

∂E

n

∂w

(hidden)

= w

(hidden)

(

t) − η

!

n

∇E

n,w

(hidden)

個々のサンプル

に関して書くと

E =

!

n

E

n

def

∂En ∂w0

..

.

∂En ∂wl−1

中間層∼出力層の結合一つ一つ

よって、任意の

w

ij

(hidden)

に対して、

を計算

∂E

n

∂w

ij

(hidden)

すれば良い。

∂E

n

∂w

ij

(hidden)

の計算

∂E

n

∂w

(hidden)

ij

=

∂E

n

∂z

(output)

n

i

∂z

(output)

n

i

∂w

(hidden)

ij

E

n

=

1

2

!

i

"

z

(teacher)n i

− z

(output)n i

#

2

∂E

n

∂z

(output)n i

= −

!

z

(teacher)n i

− z

(output)n i

"

z

(output)n i

= f

#

j

w

(hidden) ij

z

(hidden)n j

∂z (output)n i ∂w(hidden) ij = f′ ⎛ ⎝# j w(hidden) ij z (hidden)n j⎠ z(hidden)n j

f (x) =

1

1 +

e

−x

f

(

x) = f (x) (1 − f (x))

まとめると

∂E

n

∂w

hidden ij

= −

!

z

(teacher)n i

− z

(output)n i

"

z

(output)n i

!

1

− z

i(output)n

"

z

(hidden)n j

w

(hidden) ij

(

t + 1) = w

(hidden) ij

(

t) − η

!

n

∂E

n

∂w

(hidden) ij

= w

(hidden) ij

(

t) + η

!

n

"

z

(teacher)n i

− z

(output)i n

#

z

(output)n i

"

1

− z

(output)n i

#

z

(hidden)n j

となるので、更新式は

となる。

勾配降下法

という名前がついている

コード

Layer *output_layer = &network -> layer [ network -> n - 1 ]; Layer *hidden_layer = &network -> layer [ network -> n - 2 ]; Connection *c = &network -> connection [ network -> n - 2 ]; for ( int i = 0; i < c -> n_post; i++ ) {

for ( int j = 0; j < c -> n_pre; j++ ) { double o = output_layer -> z [ i ]; double d = ( z [ i ] - o ) * o * ( 1 - o );

c -> dw [ j + c -> n_pre * i ] += Eta * d * ( hidden_layer -> z [ j ] ); } }

w

(hidden) ij

(

t + 1) = w

(hidden) ij

(

t) − η

!

n

∂E

n

∂w

(hidden) ij

= w

(hidden) ij

(

t) + η

!

n

"

z

(teacher)n i

− z

(output) n i

#

z

(output)n i

"

1

− z

(output)n i

#

z

(hidden)n j

double updateByPerceptronRule ( Network *network, Neuron z [ ] );

質問は?

例: XORの学習

x

1

x

0

z

0

0

0

0

1

1

1

0

1

1

1

0

1個

128個

2個

Network network; createNetwork ( &network, 3, rng ); createLayer ( &network, 0, 2 ); createLayer ( &network, 1, 128 ); createLayer ( &network, 2, 1 );

createConnection ( &network, 0, sparse_random ); createConnection ( &network, 1, uniform_random );

double uniform_random ( Network *n, const int i, const int j ) {

return 1. - 2. * sfmt_genrand_real2 ( &n -> rng ); }

double sparse_random ( Network *n, const int i, const int j ) {

return ( sfmt_genrand_real2 ( &n -> rng ) < 0.5 ) ? uniform_random ( n, i, j ) : 0.;

}

コード

void createConnection ( Network *network, const int layer_id, double ( *func ) ( Network *, const int, const int ) )

{

Connection *connection = &network -> connection [ layer_id ];

const int n_pre = network -> layer [ layer_id ] . n + 1; // +1はバイアスの分 const int n_post = ( layer_id == network -> n - 1 ) ? 1 : network -> layer [ layer_id + 1 ] . n;

connection -> w = ( Weight * ) malloc ( n_pre * n_post * sizeof ( Weight ) ); for ( int i = 0; i < n_post; i++ ) {

for ( int j = 0; j < n_pre; j++ ) {

connection -> w [ j + n_pre * i ] = func ( network, i, j ); }

}

connection -> dw = ( Weight * ) malloc ( n_pre * n_post * sizeof ( Weight ) ); for ( int i = 0; i < n_post; i++ ) {

for ( int j = 0; j < n_pre; j++ ) { connection -> dw [ j + n_pre * i ] = 0.; }

}

connection -> n_pre = n_pre; connection -> n_post = n_post; }

void deleteConnection ( Network *network, const int layer_id ) {

Connection *connection = &network -> connection [ layer_id ]; free ( connection -> w );

free ( connection -> dw ); }

Neuron x [ 4 ][ 2 ] = { { 0., 0. }, { 0., 1. }, { 1., 0. }, { 1., 1. } }; Neuron z [ 4 ][ 1 ] = { { 0. } , { 1. } , { 1. } , { 0.} };

const int number_of_training_data = 4; // Training

double error = 1.0; // arbitrary large number const double Epsilon = 0.001; // tolerant error rate int i = 0;

while ( error > Epsilon ) { error = 0.;

initializeDW ( &network );

for ( int j = 0; j < number_of_training_data; j++ ) {

//int k = ( int ) ( number_of_training_data * sfmt_genrand_real2 ( &rng ) );

int k = j;

setInput ( &network, x [ k ] ); forwardPropagation ( &network, sigmoid );

error += updateByPerceptronRule ( &network, z [ k ] ); }

updateW ( &network ); printf ( "%d %f\n", i, error ); i++;

}

(3)

// Test

Layer *output_layer = &network . layer [ network. n - 1 ]; const int n = output_layer -> n;

for ( int i = 0; i < number_of_training_data; i++ ) { setInput ( &network, x [ i ] );

forwardPropagation ( &network, sigmoid ); for ( int j = 0; j < n; j++ ) {

fprintf ( stderr, "%f%s", output_layer -> z [ j ], ( j == n - 1 ) ? "\n" : " " );

} }

void initializeDW ( Network *network ) {

Connection *c = &network -> connection [ network -> n - 2 ]; for ( int i = 0; i < c -> n_post; i++ ) {

for ( int j = 0; j < c -> n_pre; j++ ) { c -> dw [ j + c -> n_pre * i ] = 0.; }

} }

void updateW ( Network *network ) {

Connection *c = &network -> connection [ network -> n - 2 ]; for ( int i = 0; i < c -> n_post; i++ ) {

for ( int j = 0; j < c -> n_pre; j++ ) {

c -> w [ j + c -> n_pre * i ] += c -> dw [ j + c -> n_pre * i ]; }

} }

コンパイルして実行

[ya000836@purple99 ~/dl]$ gcc -O3 -std=c99 -Wall -I SFMT-src-1.5.1 -D SFMT_MEXP=19937 -o perceptron perceptron.c SFMT-src-1.5.1/SFMT.c [ya000836@purple99 ~/dl]$ ./perceptron 0 0.879170 1 0.836272 2 0.766234 3 0.658244 4 0.543239 : 4302001 0.001000 4302002 0.001000 4302003 0.001000 4302004 0.001000 4302005 0.001000 # of epochs = 4302006 0.022023 0.977739 0.977538 0.022691

}

学習結果

}

エポック番号と誤差

誤差の減り方を見る

[ya000836@purple99 ~/dl]$ ./perceptron > perceptron.dat 0.022023 0.977739 0.977538 0.022691 [ya000836@purple99 ~/dl]$ gnuplot G N U P L O T

Version 4.6 patchlevel 6 last modified September 2014 Build System: Darwin x86_64

Copyright (C) 1986-1993, 1998, 2004, 2007-2014 Thomas Williams, Colin Kelley and many others gnuplot home: http://www.gnuplot.info faq, bugs, etc: type "help FAQ"

immediate help: type "help" (plot window: hit 'h') Terminal type set to 'x11'

gnuplot> plot 'perceptron.dat'

ボーナス課題 1

2層のパーセプトロンでXORは学習できるか?

単純パーセプトロン

学習できる→具体的にネットワークを呈示せよ

学習できない→なぜなのか理由を考察せよ

ヒント: 「線形分離」についてググれ

色々試すこと

・中間層のニューロン数を変える

・収束までのエポック数を調べる

多層パーセプトロン

多層パーセプトロン

XORのためには中間層のニューロンは何個必要か?

2個で必要十分

(4)

パーセプトロンの問題

中間層にたくさんのニューロンが必要

→ 入力信号を区別可能にするため

解決策:

入力層∼中間層の結合も変化させる

→誤差逆伝播

誤差逆伝播

w

i j

(l −1)

(t + 1) = w

i j

(l −1)

(t) − η

!

n

∂E

n

∂w

i j

(l −1)

∂E

n

∂w

i j

(l −1)

=

∂E

n

∂z

i

(l )

∂z

(l )

i

∂w

i j

(l −1)

l-1から層lへの結合の重みの更新式は同様に

上の層で決まる値

∂z

i(l )

∂w

i j(l −1)

= z

(l )i

!

1 − z

(l )i

"

z

(l −1) j

誤差逆伝播

∂E

n

∂z

(l ) i

= −

!

z

(teacher)n i

z

(l ) i

"

lが出力層の場合はパーセプトロン則と同じで

∂E

n

∂z

(l )

i

=

!

k

∂E

n

∂z

(l +1)

k

∂z

(l +1)

k

∂z

(l )

i

それ以外の場合は

さらに上の層で決まる値

誤差逆伝播

上の層から下の層に向かって順番に計算すれば、

∂E

n

∂z

(l +1)

k

は計算済み (出力層の場合は

∂En ∂z(l ) i = − ! z(teacher)n iz (l ) i "

)

∂E

n

∂z

(l )

i

=

!

k

∂E

n

∂z

(l +1)

k

∂z

(l +1)

k

∂z

(l )

i

(再掲)

z(l+1) k = f ! " i w(l) kiz (l) i #

∂z

(l +1)

k

∂z

(l )

i

= f

!

"

i

w

(l )

ki

z

(l )

i

#

w

(l )

ki

= z

k

(l +1)

$

1 − z

(l +1)

k

%

w

(l )

ki

ここで

かつfはシグモイド

誤差逆伝播

w

i j(l −1)

(t + 1) = w

i j(l −1)

(t) + η

!

n

∂E

n

∂z

(l )i

&

z

i(l )

&

1 − z

(l )i

'

z

j(l −1)

'

∂E

n

∂z

(l ) i

=

$

z

(teacher)n i

z

(l ) i

%

l

is output layer

&

k ∂En ∂z(l +1) k

z

(l +1) k

$

1 − z

(l +1)k

%

w

(l ) ki

otherwise

まとめると、

とってもきれいな式が導出できる

「デルタ」という名前がついている

質問は?

何層あってもこの方法は使える→多層パーセプトロン

コード

関数updateByBackPropagationを実装しよう

typedef double Neuron, Delta, Weight;

typedef struct { Neuron *z; Delta *delta; int n; } Layer;

void createLayer ( Network *network, const int layer_id, const int number_of_neurons )

{ :

layer -> delta = ( Delta * ) malloc ( ( number_of_neurons + bias ) * sizeof ( Delta ) );

for ( int i = 0; i < layer -> n; i++) { layer -> delta [ i ] = 0.; } if ( bias ) { layer -> delta [ layer -> n ] = 0.; } // バイアス初期化 }

1. デルタの定義を追加

void deleteLayer ( Network *network, const int layer_id ) {

:

free ( layer -> delta ); }

2. デルタの確保と初期化

コード

あとはperceptron.cの

updateByPerceptronRuleを

updateByBackPropagationに

変更する

レポート課題 2

色々試すこと

・中間層のニューロン数を変える (中間層2個でいいか?)

・収束までのエポック数を調べる

updateByBackPropagationを実装して上記を試せ

コードの雛形はdl/code/bp.cにある

(5)

手書き文字認識

XORはあまりにもtoy problemなので、もう少しましな何か

手書き文字認識

MNISTデータベース

・手書き文字画像のデータベース+ラベル付き

・画像は28x28ピクセル256階調グレースケール

・ラベルは 0 から 9 の数字 (そりゃそうだ)

詳しくは付録B

・60000個のトレーニングデータ

・10000個のテストデータ

必ずデータを分ける

データの読み書き

code/mnist.{c, h}を用意した。

code/mnist_test.cをまず試す。

code/mnist/以下にデータがあるのでフォルダ毎コピー。

make mnist_test

mkdir png

./mnist_test

./pngの下にpngファイルが作成される。

手書き文字のテスト

レポート課題 3

誤差逆伝播法を実装した3層のパーセプトロンで、

手書き文字の学習と認識を行え。

やり方はテキストを参照。

以下では多少補足を。

バッチ学習の問題点

E =

!

n

1

2

"

"z

(teacher)

n

− z

(output)

n

"

"

2

誤差 (再掲)

全トレーニングデータに関する和

XORのときはn=4だった。

MNISTではn=60000。←計算が終わらない

学習が局所解に落ちる可能性が高い。

勾配降下法の性質

「最も良い解」はすごく少ない。

「そこそこ良い解」はたくさんある。

勾配降下法は初期値に依存するので、「最も良い解」

の近くから始めない限り「そこそこ良い解」に捕まる。

確率的勾配法とミニバッチ

確率的に勾配を降りることで、「そこそこ良い解」から

脱出できるようにする。

× 全トレーニングデータを使う

トレーニングデータからいくつかをランダムに選んで使う

(バッチ)

(ミニバッチ)

エポック毎にミニバッチを作り直す

ミニバッチのサイズをどうするかに依存

極端な例: サイズ 1 (1データ毎に重みを更新)

ミニバッチへの布石がここに…

while ( error > Epsilon ) { error = 0.;

initializeDW ( &network );

for ( int j = 0; j < number_of_training_data; j++ ) {

//int k = ( int ) ( number_of_training_data * sfmt_genrand_real2 ( &rng ) );

int k = j;

setInput ( &network, x [ k ] ); forwardPropagation ( &network, sigmoid );

error += updateByBackPropagation ( &network, z [ k ] ); }

:

while ( error > Epsilon ) { error = 0.;

initializeDW ( &network );

for ( int j = 0; j < MINI_BATCH_SIZE; j++ ) {

int k = ( int ) ( number_of_training_data * sfmt_genrand_real2 ( &rng ) );

setInput ( &network, x [ k ] ); forwardPropagation ( &network, sigmoid );

error += updateByBackPropagation ( &network, z [ k ] ); }

(6)

手書き文字のテスト

レポート課題 3

誤差逆伝播法を実装した3層のパーセプトロンで、

手書き文字の学習と認識を行え。

やり方はテキストを参照。

サイズ1のミニバッチでとりあえずやる。その後で

ミニバッチのサイズを色々変えてみる。

手書き文字のテスト

ボーナス課題 2

中間層のニューロンは何を表現しているか?

・入力層∼中間層の結合を可視化する。

・mnist_generate_png関数を参考にすると良い。

質問は?

参照

関連したドキュメント

*2 施術の開始日から 60 日の間に 1

第7回 第8回 第9回 第10回

第1回 平成27年6月11日 第2回 平成28年4月26日 第3回 平成28年6月24日 第4回 平成28年8月29日

第 25 サイクルから第 27 サイクルの炉心について,サイクル初期とサイクル末期の減 速材ボイド係数を図 3.2-5(1)〜図 3.2-5(2)示す。第 25 サイクルから第

41 の 2―1 法第 4l 条の 2 第 1 項に規定する「貨物管理者」とは、外国貨物又 は輸出しようとする貨物に関する入庫、保管、出庫その他の貨物の管理を自

 活動回数は毎年増加傾向にあるが,今年度も同じ大学 の他の学科からの依頼が増え,同じ大学に 2 回, 3 回と 通うことが多くなっている (表 1 ・図 1

 講義後の時点において、性感染症に対する知識をもっと早く習得しておきたかったと思うか、その場

回  テーマ  内  容 . 第 1 回