ゼロから作る Deep Learning - izudon/izudon.github.io GitHub Wiki
- ニューラルネットワークとはどういうものかを、
実際に手組みでプログラムを組むことによって体験的に学び、
最新の研究成果の実感をもった理解につなげていくという本。 - -> コードのダウンロード : Matplotlib
- Python を使いこなせるようにはならない。
- Python で Matplotlib を自由自在に使いこなして
グラフ描画をできるようにはならない。 - Python で NumPy を自由自在に使いこなして
行列演算を組んだり、意図した機械学習マシンを作れるようにはならない。
- Python で Matplotlib を自由自在に使いこなして
- 数理科学的根拠には踏み込まない
- 成果の紹介がなされ直感的理解が促される。
- 8章 ディープラーニング
- 最新の研究成果の紹介(頑張ってきたご褒美)。
- ディープラーニング小史。層が深くなる傾向。そのメリット。
- 人気のマシン -> VGG, GoogLeNet, Resnet。
- 計算を早くする -> GPU, 分散学習, ビット削減(半精度浮動小数点数)。
- 他の実用例 -> 物体検出, セグメンテーション, 画像キャプション生成。
- 未来の実用例 -> 画像スタイル変換、画像生成(DCGAN)、自動運転。
Deep Q-Network(強化学習)。
- 7章 畳み込みニューラルネットワーク
- 画像データを扱う際に有効とされるニューラルネットワーク。
- 畳み込み(Convolution)とプーリング(Pooling)のイメージをつける。
- 途中経過の抜き取り -- Edge と Blob 。LeNet, AlexNet 紹介。
- 6章 学習に関するテクニック
- 前章までの基本的な考え方に続き、本章では、実際に応用しようとしたときに
立ち現れる様々な問題に対してどういう対処方法があるのかを学ぶ。 - 収束を早く、精度を高く:
- SGD -> Momentum, AdaGrad, Adam
- 重みの初期値:
- シグモイド関数 -> Xavier の初期値
- ReLU -> He の初期値、がベストプラクティス。
- Batch Normalization
- 初期値を程よく分散させる計算をレイヤとして差し込む方法。
- 収束が早くなり、初期値への依存が減り、過学習も抑制できる。
- 過学習を防ぐ:
- 人口的に過学習を起こしてみる。
- データを少なく
- パラメタを多く
- 過学習の抑制
- -> Weight decay(加重減衰)
- -> Dropout(間引き法(意訳))
- 人口的に過学習を起こしてみる。
- ハイパーパラメタの決定:
- 対数スケールで範囲を決め
- 対数スケールでそこからランダムサンプリング
- 試してみて良さそうな範囲を見極め
- さらにその範囲からランダムサンプリング
- -> ベストプラクティス。
- -> 検証データとテストデータの2段構えにする(過学習の抑制)。
- 前章までの基本的な考え方に続き、本章では、実際に応用しようとしたときに
- 5章 誤差逆伝搬法
- 導関数(偏微分)を最終出力から逆算して解析的に求め精度を上げる方法を学ぶ。
- レゴブロックのようにレイヤを重ねていくイメージを学ぶ。
- 4章 ニューラルネットワークの学習
- 勾配法を使って重みとバイアスをデータから学習する(イメージをつける)。
- ミニバッチ学習 -> MNIST
- 3章 ニューラルネットワーク
- 重み、バイアス、活性化関数、最終出力層、損失関数 -- いよいよ本論。
- シグモイド関数 / ReLU
- 恒等関数 / ソフトマックス関数
- 2乗和誤差 / 交差エントロピー誤差
- Python での実装を通じてニューラルネットワークのイメージを持つ。
- MNIST をはじめて使う。
- 重み、バイアス、活性化関数、最終出力層、損失関数 -- いよいよ本論。
- 2章 パーセプトロン
- 「層を重ねる」というイメージを持つ。
- 1章 Python入門
- クラス、ディクショナリ変数、パディングによるブロック表現、は抑える。
- NumPy = Python で行列計算するライブラリ。
- Matplotlib = Python でグラフ描画するライブラリ
- データ拡張(Data Augumentation)
- 下の画像をチョット傾けたりチョット平行移動させたものを
学習データに加えて精度を上げる手法。 - 単純だが良い結果をもたらすことが多い。
- 下の画像をチョット傾けたりチョット平行移動させたものを
- 層が深くなる傾向=最近のディープラーニング
- 層が深くなると(相対的に)パラメタを少なくできる。
- 各層より様々な「レベル」で画像を「見ている」ことになる。 = 受容野(receptive fields) を広くカバーできる。
- ImageNet
- 100万枚を超えるラベル付き画像データのセット。
- ILSVRC
- ImageNet を利用したクラス分類のコンペ。
- 2012 年に AlexNet が登場しグンと性能が向上。
以来、ニューラルネットワークが上位。 - VGG
- 16層または19層からなる「基本的な」CNN。
- GoogLeNet ( by Google )
- 横方向にも広がり(幅)を持ったニューラルネットワーク。
- インセプション構造という。
- ResNet ( by Microsoft )
- 途中の層を飛び越える構造を持つ。
- スキップ構造(またの名を ショートカット や バイパス)という。
- 転移学習(再学習(fine tuning))
- ImageNet の膨大なデータによる学習結果=重みを、 そのまま次のマシンの重みとして利用しさらなるチューニングを行うこと。
- 実践的によくなされる。
- GPU の利用
- -> NVIDIA 製
- 分散学習
- -> TensorFlow など著名なフレームワークは対応している。
- ビット削減
- ニューラルネットワークは実数の精度が悪くても十分に成果が出るという結果。
- 半精度浮動小数点(16bit)で十分。理論上4倍高速になる。
- NVIDIA の GPU が対応した。
- 物体検出
- 画像の「どこ」に「何」が写っているかを見分ける。
- 1.候補領域抽出(extract region proposals)
- 2.CNN特徴の計算(compute CNN features)-- の2段構え。
- セグメンテーション
- 写真の「どこ」に「何」が写っているか、
背景と切り分けるマスクデータをラベルとした学習。 -
FCN ( Fully Convolutional Network )
- すべて畳み込み層からなるネットワーク(直訳)
- 写真の「どこ」に「何」が写っているか、
- 画像キャプション生成
- この写真は「何」の写真かを説明する言葉を写真から自動生成。
- NIC ( Neural Image Caption ) と呼ばれるモデルがあり・・・
-
RNN ( Recurrent Neural Network ) というものを使っている。
- 再起的なつながりを持つネットワーク
- 自然言語などの連続性のあるデータに対してよく用いられる。
- 「私」といったのを学習していて、それに「は」を付けて、
「私は」とする。それにまた「寝る」をつけて「私は寝る・・・」 と続けていくようなモデル。
- 「私」といったのを学習していて、それに「は」を付けて、
-
マルチモーダル処理
- 「画像」と「自然言語」など、複数種類の情報を組み合わせて処理すること。
- 近年注目を集めている。
- 画像スタイル変換
- ゴッホの絵を学習させることでただの写真をゴッホ風の絵にしてしまえる技術。
- 画像生成
- 「ベッドルーム」という言葉から、ベッドルームのそれっぽい画像を大量に生成する技術。
- DCGAN ( Deep Convolcational Generative Adversarial Network ) を使用。
- GAN とは・・・
- Generator より精巧なだまし画像の技術を学習
- Discriminator より高精度に見破る技術の学習
- Generator と Discriminator が互いに切磋琢磨しながら
腕を磨いていく機械学習の技術。
- 教師あり学習(supervised learning)
- 教師なし学習(unsupervised learning)
- DBN ( Deep Belief Network )
- DBM ( Deep Boltzman machine )
- 最近下火だった教師なし学習が DCGAN などの手法により再び脚光を浴びるかも。
- 日経コンピュータでは「自己教師あり学習」が最近の本命とか書いてあった。
- 自動運転
- SegNet -- CNNベースのネットワーク 高精度に走路環境を認識。
- 強化学習
- DQN ( Deep Q-Network )
-
最適行動価値関数 を最大化するように動く。
(見込み価値の最大化を狙う行動) - テレビゲームの画像を学習してコントローラの動きに反映。
- スーパープレイが生成される。
-
最適行動価値関数 を最大化するように動く。
- AlphaGo
- ディープラーニングと強化学習が利用。
- 3千万のプロ棋譜を学習 -> 自己対局を繰り返す。
- -> いずれも DeepMind社(Google の子会社)。
- DQN ( Deep Q-Network )
畳み込みニューラルネットワーク ( convolutional neural network : CNN ) とは・・・
Affine 演算を行う Affine レイヤに替えて
- 畳み込み演算を行う「Convolution レイヤ(畳み込み層)」
- プーリング演算を行う「Pooling レイヤ(プーリング層)」
を実装したニューラルネットワーク。
これまでのニューラルネットワーク
- 入力値 -- Affine - ReLU -- Affine - ReLU -- Affine - Softmax - 出力値
畳み込みニューラルネットワーク(CNN)
- 入力値 -- Conv - ReLU - Pool -- Conv - ReLU - Pool -- Conv - ReLU -- Affine - ReLU -- Affine - Softmax - 出力値
- これまで: 隣接層ですべてのノードがすべてのノードと結合
- -> 全結合(fully-connected) という
- 畳み込み: 全結合ではない。
- これまで: 28 x 28 画像をのべたんで 784 要素の配列にして計算。
- -> 画像としての形状を無視している
- -> 上下に隣接するピクセル間にはやはりそれなりの関連性を認めるべき
- 畳み込み: 畳み込み演算においてその関連性を考慮する。
- -> 実際、画像データの学習に用いられることが多い。
- 畳み込み層の入出力データを「特徴マップ(feature map)」
入力を「入力特徴マップ(input feature map)」
出力を「出力特徴マップ(output feature map)」という。
入力(+パディング) <- フィルタで走査(ストライド) + バイアス => 出力データ
- バイアスはスカラ値である。全ピクセルに同じだけの値を上げ底(下げ底)する。
- チャネル(CYMK, RGB等)を考慮した3次元データを入力とすることもある。
- このときフィルタもチャネル数方向に拡張した3次元のデータとする。
- -> 出力は2次元データのまま。
- フィルタとしてチャネル数方向に拡張した3次元データを「チャネル数個分」用意する。
- -> 出力はチャネル数拡張された3次元データ。
- このときフィルタもチャネル数方向に拡張した3次元のデータとする。
入力(C, H, W) * フィルタ(FN, C, FH, FW) + バイアス(FN, 1, 1) -> 出力(FN, OH, OW)
記号 | 意味 | 記号 | 意味 | 記号 | 意味 |
---|---|---|---|---|---|
C | チャネル数 | FN | フィルタの数 | . | . |
H | 高さ(Height) | FH | フィルタの高さ | OH | 出力の高さ |
W | 幅(Width) | FW | フィルタの幅 | OW | 出力の幅 |
バッチ処理する場合はこれにバッチ処理1単位のデータ数がつく。
入力(N, C, H, W) * フィルタ(FN, C, FH, FW) + バイアス(FN, 1, 1) -> 出力(N, FN, OH, OW)
記号 | 意味 |
---|---|
N | バッチ処理1単位のデータ数 |
>>> import numpy as np >>> x = np.random.rand( 10, 1, 28, 28 ) >>> x.shape (10, 1, 28, 28)
^ こういうこと(実装で入力が4次元配列になる)
入力(C, 12, 12)-> 出力(C, 4, 4) --- 高さと幅の数は一例 / C:チャネル数
- Maxプーリング: 最大値を取る演算 <- こちらのがよく用いられる
- Averageプーリング: 平均値を取る演算
-
パラメタが存在しない
- 最大値をとったり平均値をとったりするだけの処理であるため
-
チャネル数は変化しない
- 高さと幅方向だけのまとめ演算。
-
微小な位置変化に対してロバスト(頑強)
- 1ピクセル程度動いてもまとめ演算しているわけだから大差ない。
- フィルタの適用領域を先頭から順番に1行に展開した2次元配列を作る関数。
入力 (N, C, H, W) -(img2col)-> 入力 ( FHxFW, (NxCxHxW)/(FHxFW) ) - ループ処理を無くし処理を高速化する。
- フィルタも2次元に展開する。
フィルタ (FN, C, FH, FW)-> フィルタ ( FNxC, FHxFW ) - これらを 2 x 2 行列の行列の積演算する。
入力( FHxFW, (NxCxHxW)/(FHxFW) ) x フィルタ ( FNxC, FHxFW )
MNIST で検証
- -> 精度 99% 。
- 1層目の重みを可視化(重み値をグレースケールとみて画像化)。
- 最初はランダムな濃淡だが -> 学習後は「様々なパターン」。
- 横方向グラデーション -> 画像の中で横方向のエッジを見るフィルタとして機能
- 縦方向グラデーション -> 画像の中で横方向のエッジを見るフィルタとして機能
- 斜め方向、縞模様繰り返し、など、それぞれそれなりに意味のあるパターンを見るいくつものマイクロフィルタとして機能しているっぽい。
- ある論文によれば
- 1層目 -> エッジ(直線方向のパタン)とブロブ(放射状のパタン)を見ている。
- 3層目 -> テクスチャを見ている。
- 5層目 -> 物体のパターン(犬の鼻、火炎、車のタイヤ、等)を見ている。
- 7層目 -> 物体の「クラス」を見ている。
- CNN の元祖。
- シグモイド関数 を用いる。
- サブサンプリングは間引くだけ(-> 現在の主流は Maxプーリング)。
- ディープラーニングの火付け役になったニューラルネットワーク。
- ネットワーク構成は LeNet とほとんど変わらない。
- ReLU を用いる。
- Dropout を使用
- LRN(Local Response Normalization)という局所的正規化を行う層を用いる。
- これまでやってきた、微分係数に学習率(lr: learning rate)を掛けて引くというやり方。
- 微分係数x学習率 から、前回の調整値をやや減衰させたものを引いた上で、
重みベクトルから引くという学習のさせかた。 - 符号が逆転した(振動している)場合などにその影響を緩和できる。
- 最初は大きく学習し、次第に小さく学習するというやり方。
- これまで経験した勾配の値を2乗和として保持。
今回の微分係数にこの平方根分の1を掛けて重みベクトルから引く。 - 大きく学習した成分は以後の学習が緩やかになる。
- この性質のため、最終的にほとんど学ばなくなる。
これを改善した RMSProt という手法が提案されている。 - RMSProt では、過去の勾配を徐々に忘れていく。
(指数移動平均)
- この性質のため、最終的にほとんど学ばなくなる。
- Momentum の慣性と AdaGrad の適応的減衰を
いいとこ取りしたようなアルゴリズム(詳細省略)。
- SDG に比べ他の3つはあきらかに優秀(p.178)。
- 収束が早い。
- 最終精度も高い(
93%-> 98%)。
- なかでも AdaGrad がもっとも優秀。
- 処理するデータにより異なると思われるが。
- 重みの初期値をどう与えるかで学習効率に影響する。
意外と見落とされがちな観点。 - ニューラルネットワークの途中段階の値を取り出して
知見を得てみる。 - 活性化関数を出た直後の値=アクティベーションを
各層で見てみる。
- 大きすぎた場合
- アクティベーション後の値がほぼ 0 か 1 に(つまり両端に)
寄りついてしまっている。 - 誤差逆伝播法による微分係数が概ね0になる。
(シグモイド関数の形を思い出せばわかる通り) - 学習しなくなってしまう。
- 勾配消失(gradient vanishing) という。
- アクティベーション後の値がほぼ 0 か 1 に(つまり両端に)
- 小さすぎた場合
- ほとんどの値が中央付近によってしまう。
- 微分係数がほぼ1に揃ってしまう。
- 表現力の問題の発生。
- 前層ノードの個数 n の平方根分の1( √(1/n) )の標準偏差を持つガウス分布とするもの。
- シグモイド関数の場合のベストプラクティスとされている。
- シグモイド関数のかわりに tanh を使うともっとなめらかになる。
(キレイな釣鐘型の分布のまま最後までいく)。
- 前層ノードの個数 n 分の2の平方根分( √(2/n) )の標準偏差を持つガウス分布とするもの
- ReLU の場合のベストプラクティスとされている。
- MNIST で検証 -> 均等なばらつきのまま最後までいく。
ReLU の場合、収束も Xavier より早い。
- 初期値に困らなくても良いよう、層間にばらつきを正規化する計算を入れようというもの。
- メリット
- 学習が早い
- 初期値にあまり依存しなくなる
- 過学習を抑制できる。
- 検証 -> 実際にその通り(精度向上が早い(3倍程度))
- 過学習は
- 少なすぎる訓練データ
- パラメータの多いモデル
- で起きると言われているため
- 本来 60,000 個の MNIST から 300 個だけ抽出して訓練に用いる。
- 7層のニューラルネットワークにしてパラメタを膨大にする。
- 結果・・・
- 訓練データ精度:
- 100 エポックあたりでほぼ 100% 到達。
- テーストデータ精度:
- 100 エポックあたりでほぼ 70% 頭打ち。
- 訓練データ精度:
- 訓練されたマシンが
それ以外のデータへ「汎化」できていない。- -> 過学習(overfitting)
- 大きな重みを持つことにペナルティを課すアルゴリズム。
- 重みに大きな値をもってしまうことによって過学習が起きているケースが多いため。
- たとえば、重みの2乗ノルム(L2ノルム)を損失関数の値に加算。
(損失関数を減らすのが目的なのに大きな重みだと逆に増えてしまう)。 - 実際にやってみると・・・
- 訓練データとテストデータの精度の開きは減った。
- テストデータの精度は 68% 程度。
- 訓練データの精度は 93% 程度(100% 近くまで行かない)。
- 訓練時に、ニューロンの一定数をランダムに除去して(間引いて)学習。
- テスト時は全てのニューロンを元に戻す(出力も間引率で割り戻す)。
- 実際にやってみると・・・
- 学習が緩やかになる。
- 訓練精度なかなか 100% に達しない。
- テスト精度 訓練精度より小さいが、訓練精度との差は縮まる。
アンサンブル学習
- 複数のモデルを個別に学習させ、推論時にはそれら複数の出力を平均するもの。
- 例えば5つの同じ(または良く似た)モデルを別々に学習させ推論ではこれを平均する。
- -> Dropout もこれと同じ発想と言える。
- アンサンブル学習を行うことで認識精度が数%向上することが実験的に分かっている。
- ハイパーパラメタの例
- 各層のニューロンの数
- バッチサイズ
- 学習係数(学習率や Weight decay 等)
- ハイパーパラメタの調整
- テストデータを使ってハイパーパラメタを調整してはいけない。
- そのテストデータに最適化したモデルにしてしまうことになるため。
(汎化性能が阻害されるため)。 - ハイパーパラメタの調整には
検証データ(validation data) を用いる。- ない場合は、訓練データ から取り分ける。
- テストデータ は汎化性能の検証のために最後に1度だけ使う。
- ハイパーパラメタの探索
- ざっくりを範囲を決め、その中からランダムに取り出す。
- -> グリッドサーチなどの規則的な探索より良い結果になることが報告されている。
- 例えば 0.001(1e-3)〜1,000(1e3)と決める(対数スケールで)。
- そこからランダムに取る 1e( -3 <=random=> 3 )
- エポックは小さく設定して筋の悪そうなパラメタ早めに見切りをつける。
- よさそうなところを範囲として再設定しそこからまたランダムサンプリングする。
- (繰り返し)
- より洗練された手法に ベイズ最適化(Bayesian optimization) がある。
- f:( x1, x2, x3 ) -> ( y1, y2 ) という写像を考える。
典型的には 3 x 2 行列で表される線形変換。- f の微分係数は x1, x2, x3 の3方向ある「と同時に」
y1 成分に及ぼす変化と y2 方向に及ぼす変化の両方がある。- x2, x3 を固定して x1 だけ少し動かしたときに y1 に及ぼす変化
- x2, x3 を固定して x1 だけ少し動かしたときに y2 に及ぼす変化
- x3, x1 を固定して x2 だけ少し動かしたときに y1 に及ぼす変化
- :
- 従って 6 成分ある。
- 関数を要素とする 3 x 2 行列みたいなものができる。
- これを ( ∂/∂X ) f = ∂f/∂X と書き表す。
X を太字にしているのは3次元ベクトルだよという意味。 - n 次元 -> m 次元 の写像に拡張しても同じ。
n x m 行列の関数の束みたいなものが偏微分になる。
- f の微分係数は x1, x2, x3 の3方向ある「と同時に」
- そもそも、計算結果を導く過程というのは、
データ同士を演算してアウトプットを導く作業の、多段重ねである。 - これをわかりやすく模式図化にしたものが「計算グラフ」である。
-
順伝搬(forward propagation) とは・・・
- 手順通りに左から右へ計算を進めること
-
逆伝搬(backward propagation) とは・・・
- 手順とは逆に右から左へ計算を進めること
- 今やろうとしているのは・・・
- (入力データ、重み(各段階の)、バイアス(各段階の))
<- これ全部入力と考えて(何次元になるのだか知らないけれども) - 各値を少し動かしたら最終出力にどの程度影響するのか・・・
- つまり、各変数ごとの微係数を知ろうとしている。
- 何次元ベクトルになるか知らないけれども。
- -> 平たくいうと要するに 偏微分 しようとしている。
- (入力データ、重み(各段階の)、バイアス(各段階の))
- 前章では偏微分を求めるために
- リアルに各変数を少し動かして 毎度毎度順方向に計算し
最終結果への影響を調べた。 - だが、計算グラフをもとに、計算過程を逆に辿ることで、
より「効率的に」偏微分の値を求められる。
(無論、解析的な解き方を援用するわけだが)
また「精度」も向上する(頭打ちになった時点の精度が概して高くなる)
- リアルに各変数を少し動かして 毎度毎度順方向に計算し
本章では
- そのやり方を見て
- Python で実装し
- MNIST で実際にやってみる。
最初に整理をしておくと、いまやろうとしているのは、 「モデルベース」の「教師あり学習」である。
- ここでいう モデル は ニューラルネットワーク である。
- 層数および各層のノード数は固定。 <= つまりモデルのうち
- 活性化関数および最終層の出力関数も固定。<= これもモデルのうち
- これに対し、最適化するための パラメタ は、重みベクトル である。
- 前章ではアプリオリに与えた。
- 本章と次章ではこれをどう調整すれば良いかを考える。
- さて、前章で苦労して出した最終出力値であるが、これは、
正解値である ラベル にどれほど肉薄していたのであろうか。- それを決める(数値化する)ために 損失関数(loss function) を導入する。
ある意味これは正解との「距離」。0に近いほど正解に近いと判断する。 -
2乗和誤差
- 最終出力ベクトルとラベルベクトルの各要素の差の2乗を総和したもの。
- 最小二乗法的なもの。
-
交差エントロピー誤差
- 最終出力ベクトルの正解要素(確率値)の対数をとり符号反転して正数としたもの。
- 最終出力ベクトルで正解要素(確率値)が1に近いほど0に近づく。
- それを決める(数値化する)ために 損失関数(loss function) を導入する。
- 2次元ベクトル空間上の関数 ( f:(x1, x2) -> y ) 。
- 点 (a1, a2) 上の微分係数は x1 方向と x2 方向と2種類ある。
- つまり、2次元ベクトルになる。
- つまり、
- f が f:( x1, x2 ) -> y という写像だったのに対し
- f' は f':( x1, x2 ) -> ( y1, y2 ) という写像になる。
- f の結果が実数だったのに対し
- f' の結果はベクトルになる。定義域がベクトルだったというだけで!
- この f から f' を求める演算を 偏微分 という。
- ( ∂/∂x1, ∂/∂x2 ) f こう書くとこれで f を偏微分したことになる。
- ( ∂/∂x1 ) f = ∂f/∂x1 とは
- f を x1 で偏微分したものであり
- x1 にはもはや依存しなくなっている可能性はあるがまぎれもなく
- x2 の関数ではありこれは
- ( ∂/∂x1, ∂/∂x2 ) f の x1 要素(第1要素)である。
- ( ∂/∂x2 ) f = ∂f/∂x2 とは
- f を x2 で偏微分したものであり
- x2 にはもはや依存しなくなっている可能性はあるがまぎれもなく
- x1 の関数ではありこれは
- ( ∂/∂x1, ∂/∂x2 ) f の x2 要素(第2要素)である。
- ( ∂/∂x1, ∂/∂x2 ) f という表記には
- ( ∂/∂x1 ) f = ∂f/∂x1 を第1要素
- ( ∂/∂x2 ) f = ∂f/∂x2 を第2要素 として持つ
- 「ベクトルなんだョ!(なるんだよ!)」という気持ちが込められている。
- ( ∂/∂x1 ) f = ∂f/∂x1 とは
- x2 を固定し x1 の関数とみたときの x1 方向の微分係数
- -> x2 に依存する x1 の関数になる。
- ( ∂/∂x1 ) f と書き表す。
- x1 を固定し x2 の関数とみたときの x2 方向の微分係数
- -> x1 に依存する x2 の関数になる。
- ( ∂/∂x2 ) f と書き表す。
- いずれにせよ両要素とも x1 にも x2 にも依存したものとなる。
- 3次元、4次元...n次元 でも同じ。
- これを 勾配(gradient) という。
- 勾配は数値的に求めることが可能。
- 重みベクトルを入力、損失関数の値を出力と考えて、
重みベクトルの各値を少し動かして、損失関数の値が増えるか減るか調べる。- 減る方向に重みベクトルの各値を少し動かす。
- これを繰り返していけば少なくとも損失関数を極小にする
重みベクトルが求められる。
- -> 勾配法。
- 「少し」動かす。
- 求められた偏微分の値を何倍してもとの入力値に足すかのパラメータ
-> 学習率(learning rate) という - 学習率は ハイパーパラメータ 。
モデルに固定された値である。 - 学習率が・・・
- 小さすぎる
- -> いつまで経っても誤差が(損失関数)が減らない。
- 大きすぎる
- -> 飛び跳ねるばかりで収束しない。
- 少し動かすことを「繰り返す」。
- -> 小さすぎる場合は繰り返しの数さえ大きくすれば収束する。
- -> 無駄に計算資源を使うので非効率ではあるが。
- 実際的には・・・
- 学習率を色々変化させてみて、おかしなことが起きていないかを
確認する。
- 学習率を色々変化させてみて、おかしなことが起きていないかを
- 小さすぎる
- 損失関数(loss function) は、計算一回ごとの肉薄の評価尺度。
- 精度(accuracy) は、訓練セット中何割を正しく判定したかという評価値。
-> この時点でモノが違うわけなんだが・・・
- 「精度(accuracy) は、重みベクトルを少しいじったところでたいそう変わらない。」
と書いてある。- それはそうだ。
訓練データがそもそも「何個」という離散的な値なのだから、
精度は飛び飛びの値にしかならない。
- それはそうだ。
- 「だから、勾配法に使えない。」と結論づけている。
- 上記が理由とは思わないが、勾配法に使うのはお門違いなのは同意できる。
- そもそも、計算一回ごとの肉薄度をすっ飛ばしていきなり精度を上げようとするのは
発想として無理がある(飛躍している)。 - 前の本 でやったように 「その訓練セットに最適化したモデル」を作ってしまう恐れもある。
- むしろ、訓練セットも変えながらパラメタも変えたら、 出力値がどっちの影響か分からなくなってパラメタを調整したことにならないだろうと思う。
- そもそも、計算一回ごとの肉薄度をすっ飛ばしていきなり精度を上げようとするのは
- 上記が理由とは思わないが、勾配法に使うのはお門違いなのは同意できる。
-> この議論、意味不明なのではないか。
- 回を重ねるごとに
- 損失関数の値は順調に減少。
- 精度は向上。ただし、93% 程度で頭打ち。
パーセプトロンを以下の通り拡張する。
- ノードの出力値を実数値とする(パーセプトロンでは0か1だった)。
- バイアス -- 前層の重み付け総和を「上げ底(下げ底)」する値の列。
- 活性化関数 -- 前層からの演算結果を変換(強調?)する関数。
- ステップ関数(階段関数)
- ある値を超えるといきなり1になる関数。
- シグモイド関数
- ステップ関数をなめらかにしたような関数。
- ReLU 関数
- 0以下の時0、0を超えるとその値となる折れ線のような関数。
- 第n層の各値(x)は「n 次元ベクトル」
- 第n+1層の各値(x)は「m次元ベクトル」とすると:
- 重み(w)は「n * m 行列」
- バイアス(b)は「m 次元ベクトル」
- 活性化関数 h() は各値への演算となる。
- x(n+1) = h( x(n) * w + b ) ーーこの演算で計算を前に進める。
最終層の出力は活性化関数ではない別のもので処理する。
- 恒等関数
- 入力値をそのまま出力する関数。
- 回帰問題で一般的に利用。
- ソフトマックス関数
- exp(入力値)したものの全体での割合を出力する関数。
- 単純平均より差が強調されて極端になる。
- 分類問題で一般的に利用。
ソフトマックス関数は容易に桁溢れするため 桁溢れ防止のための一工夫をする(詳細省略)。
設計
- 活性化関数はシグモイド関数。
- 最終出力はソフトマックス関数(分類問題なので)。
- 入力は 784 次元のベクトル(28 x 28 ピクセルの画像なので)。
- 隠れ層を2層とする。1層目は50次元、2層目は100次元のベクトル。
- 最終出力は10次元のベクトル。0〜9の数字に対応。
MNIST は 60,000 個の訓練データ。
- 入力を 784 次元ベクトルではなく 100 x 784 行列とした方が効率的。
- 出力は 100 x 10 行列となる。
- 並列処理できるため。
- いちどに 100 個まとめて処理する。
- バッチ処理という。
結果 93% 程度の精度 ー> これから上げていく!
- XOR ゲートは、AND, NAND, OR ゲートを組み合わせて(2層にして)実現できる。
- XOR の結果は線形分離不可能なので1層では実現できない。
層を重ねて(2層にすれば)実現することができた(多層パーセプトロン) - 層を重ねれば(理論上)コンピュータさえ実現できる。
しかも NAND ゲートだけで実現できることが知られている。
- XOR の結果は線形分離不可能なので1層では実現できない。
- NumPy
- ベクトルや行列を Python で扱えるようになる。
- ベクトルの演算は基本的に「要素ごとに」その演算を行ってしまう。
行列としての乗算は np.dot(A,B) を使わねばならない。
-
Matplotlib
- Python でグラフ描画できてしまうライブラリ(gnuplot みたいなもの)。