Python DeepLearningに再挑戦 7 ニューラルネットワークの学習
概要
Python DeepLearningに再挑戦 7 ニューラルネットワークの学習
参考書籍
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
- 作者: 斎藤康毅
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/09/24
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (6件) を見る
データから学習する
ニューラルネットワークが学習を行えるようにするためには、損失関数という指標を利用する。
1つの方法は、画像から特徴量を抽出して、その特徴量のパターンを機械学習の技術で学習する。特徴量は、画像から重要なデータを的確に抽出できるように抽出できるように設計された変換器。
画像の特徴量は、通常ベクトルとして記述される。
コンビュータビジョンで有名な特徴量は、SIFT, SURF, HOGなどがある。
その特徴量を使って、画像データをベクトル(本質的なデータ)に変換、そのベクトルを利用して、機械学習で使われる識別子(SVM, KNNなど)で学習させる。
この手法の場合、どの特徴量を使うか(もしくは設計するか)、そしてそれをどのように機械学習させるかが重要になってくる。
deep learning(ニューラルネットワーク)の場合は、すべての問題を同じ流れで解くことができる点。数字の「5」を認識する問題なのか、「犬」を認識する問題なのか、「人の顔」を認識する問題なのかといった詳細とは関係なしに、ニューラルネットワークは与えられたデータをひたすら学習し、問題のパターンを発見しようと試みる。データをそのまま学習することができる。
機械学習の訓練データとテストデータ
- 機械学習では、訓練データと、テストデータの2つに分けて学習実験を行うのが一般的。訓練データは教師データと呼ぶ場合があり。
損失関数
- ニューラルネットワークが教師データに対してどれだけ一致していないかを表す指標が損失関数。
2乗和誤差
なんとマークダウンで、数式を表記できるのか!つってもTeX記法が必要みたいだから、ハードルは高いな。。。
E(w)===12∑n=1N{y(xn,w)−tn}212∑n=1N{(∑j=0Mwjxjn)−tn}212∑n=1N(w0+w1xn+w2x2n+⋯+wixin+⋯+wMxMn−tn)2E(w)=12∑n=1N{y(xn,w)−tn}2=12∑n=1N{(∑j=0Mwjxnj)−tn}2=12∑n=1N(w0+w1xn+w2xn2+⋯+wixni+⋯+wMxnM−tn)2
Yk = ニューラルネットワークの出力、Tk=教師データで、k=データの次元数
例えば、手書き文字認識の場合は、以下のような感じ。
Y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0] t = [0,0,1,0,0,0,0,0,0,0]
名前と式の通り、ニューラルネットワークの出力と正解となる教師データの各要素の差の2乗を計算し、その総和を求める。上記の例だと (0.1-0)2 + (0.05-0)2 .... という感じで、差の2乗を合計していく。
pythonで実装すると以下のような感じ。
import numpy as np def mean_squared_error(y, t): return 0.5 * np.sum((y-t)**2) t = [0,0,1,0,0,0,0,0,0,0] y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0] mean_squared_error(np.array(y), np.array(t)) >>> 0.097500000000000031 # これがいい数字なのかどうかは不明。。。 # 正解の確率をあえて小さくする y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0] >>> 0.59750000000000003 # めっちゃ大きくなった。
数字が小さい方が、誤差が少ないという判定になる。
交差エントロピー誤差
yk = ニューラルネットワークの出力、tk = 正解ラベル(one-hot表現)
y = logx のグラフは以下の通り
交差エントロピー誤差では、正解ラベルが1に対応する出力の自然対数を計算するだけ。(one-hot表現だと正解以外は、0になるため、E=0になる。)
結論的には、正解ラベル1に対する出力が大きければ、小さい値が出てきて、小さければ、大きい答えが出てくる。 y = logxは、xが小さくなればなるほど、yが小さくなるが、y = -logxの場合はその逆になる。
pythonでの実装は以下の通り。
def cross_entropy_error(y, t): delta = 1e-7 return -np.sum(t * np.log(y + delta))
ポイント
* delta = 1e-7
というのは、「0.0000001」という数字を表現する一つの方法が「1e-7」で、指数表示と呼ばれているらしい。1*10-7(1かける10の-7乗)。
- なぜdeltaが必要かというと、
np.log(0)
は、マイナスの無限大である、-infとなってしまい計算ができなくなってしまうので、微小な数値を追加してそれを防ぐため。
t = [0,0,1,0,0,0,0,0,0,0] y = [0.1, 0.5, 0.6, 0.0, 0.05, 0.1,0.0,0.1,0.0,0.0] cross_entropy_error(np.array(y), np.array(t)) >>> 0.51082545709933802 y = [0.1, 0.5, 0.1, 0.0, 0.05, 0.1,0.0,0.6,0.0,0.0] cross_entropy_error(np.array(y), np.array(t)) >>> 2.3025840929945458 # ちなみに正解以外のラベルに関する出力は関係ないので、それ以外を変えても数値は変わらない、、、はず。 y = [0.2, 0.5, 0.1, 0.1, 0.05, 0.1,0.0,0.6,0.0,0.0] cross_entropy_error(np.array(y), np.array(t)) >>> 2.3025840929945458
徐々に難しくなってきたなぁ。。。