やる気がストロングZERO

やる気のストロングスタイル

ゼロから作るDeep Leaning 読んだ

ゼロから作るDeep Leaning読んだ。

ざっくり感想

ニューラルネットワークを学んで感じた事

漠然としていた、機械学習ニューラルネットワークディープラーニングの違いが理解できたと思う。 機械学習は以前から存在していて、今AIとかの意味で盛り上がってるのはニューラルネットワークを使った機械学習である、という認識になった。 このニューラルネットワークを使った機械学習のネットワーク構成をどのように組むか(効果を出そうとすると層が深くなりがち)?あたりがディープラーニングが指す領域という認識。

読んでいて今までの技術書と違う印象を抱いた。 あまりプログラミング技術を学んでいる感がなかった。 結構漠然としていて「なぜかこうすると結果がよくなる」みたいな話も多く、物理とか自然現象を相手にしているような感覚があった。 「パラダイム・シフト」ってこういう間隔なんかな、みたいなことを感じたりした。

言語の適材適所について思った事

この本でPythonを使ってニューラルネットワークやそれを使った学習ロジックを組むのだが、この分野にPythonが利用される理由がわかった気がする。 行列の計算ロジックがすごくスッキリとかける。

昔、2,3の言語を浅く触ったくらいの経験の頃「言語って構文の差だけでどの言語も似たようなもん」って思ってた時期があったけど、今回のPythonのように言語の適材適所ってスゴイあって利用言語選択をミスると死ぬなって思いを再確認した。

以下、メモとか書く。 自分用なので本を読んでないと意味不明だと思う。

パーセプトロン

入力 -> 重み・バイアス -> 出力 という処理を行う層。

例えば、AND, OR, XORをパーセプトロンで実現することができる。 この層を2層にするとNANDも実現することができるようになる。 NANDがあればコンピュータを実装できるので、パーセプトロンはコンピュータを実装することができる。

ニューラルネットワーク

パーセプトロンでは「重み・バイアスの計算結果」が0を超えていたら出力が1(active)みたいな感じだったのを、判定関数(シグモイド関数)にすることでニューラルネットワークとして扱えるようになる。 たぶん、重みやバイアスの変更量がわずかでも結果への影響が測定できるようにしなければならない理由からだと思われる。

■ソフトマックス関数
複数の出力値の合計が1.0(=100%)になるように変換して出力する関数である。
分類系のニューラルネットワークの出力で使われる。

■恒等関数
入力をそのまま出力する関数。
回帰問題系のニューラルネットワークで使われる。
回帰問題とは、例えば人の写った画像から、その人の体重を予測するような問題。

ニューラルネットワークの学習とは?

ニューラルネットワークを使って算出した結果(判定関数のシグモイド関数をつかって出した結果)の行列から損失関数をつかって値を出す。 この値が大きければ予測結果は実際の結果からより遠く、小さければより正確だったという指標になる。

ニューラルネットワークに設定されている重みやバイアスなどのパラメータの1つを少し増やしたり減らした時に、この損失関数の結果の値が増えるのか減るのかを、微分を使って判断することができる。これを勾配という。 各パラメータごとに微分を使って勾配を求め、この勾配を使ってより損失関数の結果が小さくなる方向に、各パラメータの値を調整し、再度ニューラルネットワークで予測値を出して、、を繰り返して、損失関数が最小になるパラメータの組み合わせを探る。 これがニューラルネットワークによる学習である。

誤差逆伝播

各重みやバイアスに対する勾配を求めるにはたくさんの計算が必要で時間がかかる。 それは、各パラメータの微分計算を行わないと行けなくて、パラメータは無数になるためである。 ここで、あるパラメータに対する微分はそれを構成する計算の各部分での微分の積であるという性質を利用すると、計算量をかなり減らすことができる。 この性質を使って計算量を減らすために、各計算をレイヤーとして用意し、ニューラルネットワークを使った予測計算を行う方向を順伝播、勾配を求める方向の計算を逆伝播として実装しておくことで、各パラメータの勾配を求める計算量を節約する方法が誤差逆伝播法である。

ReLUレイヤ

■Rectified Linear Unit
活性化関数
特定の値を超えると活性化するやつ。しきい値を超えるとその値が出力される, それまでは0。(パーセプトロンの説明で使われてたやつ)
これの微分は0より大きいと1,以下だと0になる。

■Sigmoidレイヤ
シグモイド関数
これの微分は計算ノードを逆伝播で解析すると特定の式が導き出される(y2exp(-x))
さらに整理するとy(1-y)になるらしい。これはsigmoidの出力だけわかっていれば微分を計算できるということ。

■Affineレイヤ
ニューラルネットワークの順伝播で(入力 * 重み + バイアス)で計算する。これをAffineと呼ぶ
行列の積の微分は逆伝播時に行列の転置を行うことで計算できるらしい。
バッチを考慮したレイヤ関数も実装できる。

■Softmax-with-Lossレイヤ
ソフトマックスと損失関数を行うレイヤ。
ソフトマックスは入力された値を合計1になる正規化された値で出力する関数。
このレイヤの逆伝播は色々あって結果だけいうとかなりシンプルな計算式で計算できる。

これらレイヤーを使ってニューラルネットワークを実装することができる。 誤差逆転電波法で出した勾配と、実際に微分を計算して出した勾配を比較して実装ミスがないかどうかを確認したりする。

学習に関するテクニック

パラメータの更新を試しながら損失関数が最小になる組み合わせを探るのが学習だが、どのようにパラメータを試していくかによって学習の進み方が変わる(もしくは全く学習できなかったりする)。 色々と手法が編み出されたりしている。

SGD

パラメータの勾配を算出して、勾配の加工方向へ一定間隔で調整しながら最適値を探る方法。
欠点: 勾配を形成する空間の形状によっては学習が非効率になる場合がある。

対応策

■Momentum
勾配がきつい部分は一定間隔がのび、勾配が少ない部分は一定間隔が狭まる。
勾配の角度によって加速調節されるイメージ

■AdaGrad
学習初期は間隔を大きく取って「ざっくりおおきく学習」し、次第に小さく学習していく。

■Adam
MomentumとAdaGradを融合したような手法

どれを使うべきか?
問題によって最適なものは変わる。色々ためしてみるべき。 最近ではAdamがよく利用されている。

重みの初期値

重みの初期値はランダムにすべき。均一な初期値は学習の障害になる。

隠れ層のアクティベーション

アクティベーションの値に偏りがあると、ニューロンが多数ある意味がなくなる。 アクティベーションの分布は適度な広がりを持つことが求められる。

■Xavier Clorot
適切な重みの初期値を導き出す設定方法。
sigmoid関数やtanh関数など、「線形の活性化関数」に適している。

■Heの初期値
適切な重みの初期値を導き出す設定方法。
ReLUに適しているやつ。

■Batch Normalization
アクティベーションの分布が広がりを持つように強制的に調整する手法
・学習の進行が早くなる
・初期値にそれほど依存しない
過学習を抑制する。
Batch Normレイヤを挟み込んで調整をする。
Affineレイヤ->Batch Normレイヤ->ReLUレイヤ

正則化

過学習を抑えるためのテクニック

■Weight decay
大きな重み値を取ることが過学習につながるため、大きな重みを持ちにくいように調整する手法

■Dropout
ニューロンをランダムに消去しながら学習する方法。
学習時にニューロンをランダムに消すことで、毎回異なるデータモデルを学習させているような状況になることで過学習が抑えられる、というような仕組み

ハイパーパラメータ

各層のニューロンの数やバッチサイズや学習係数など(入力や重みやバイアス以外の値)をハイパーパラメータと呼ぶ。 テストデータを使ってハイパーパラメータを調整すると過学習の危険性があるのでやらないようにする。

■調整手法
パラメータの範囲を設定する。
範囲からランダムにサンプリングする
サンプリングした値のハイパーパラメータで学習を行い、検証データで認識精度を評価する。
これを繰り返し、結果からハイパーパラメータの範囲を狭める。

畳み込みニューラルネットワーク

畳み込みニューラルネットワーク = CNN
CNNはConvolutionレイヤ->ReLU->Poolingという組み合わせで使うことができる。
CNNは例えば3次元で受け取ったデータを3次元データとして次の層に伝えることができる。
画像などの形状を持ったデータを正しく理解できる(可能性がある)

ディープラーニング

ニューラルネットワークのレイヤをたくさん用意した機械学習のこと。 今までのニューラルネットワークの学習でレイヤーをどのように構成するか、どのように構成すれば良い結果を得られるか、というような内容 このあたりはまだはっきりした理屈も答えも見つかっておらず、(そもそもなぜ良い結果が出るのかも研究段階っぽい)切磋琢磨している状況っぽい。