深層学習①
- 6. 1.入力層~中間層
入力層と中間層
#単層単ユニットの場合
W = np.array([[0.1], [0.2]]) #重み
b = np.array(0.5) #バイアス
x = np.array([2, 3]) #入力
u = np.dot(x, W) + b #総入力
xの入力信号を受け取り、重みとバイアスを掛けて総和としたuを出力する。こ
れを活性化関数f(u) によって変換し、その変換された値が出力zとなる。
b
x1
w1
w2
wm
z
z = f(u)
x2
xm
入力層 中間層
z
u
実装参考)
Numpy.dot(a, b, out=None)
a:第一引数
b:第二引数
out:これを指定した場合、指定した配列をドット積を行った
新しい配列で上書きする。
・a,b が共にベクトルであればドット積となる。
・aがN次元配列、bが1次元配列(ベクトル)の場合は、aの1次元軸と
bの2次元軸の要素の内積の和
# 中間層出力
z = functions.relu(u)
# ReLU関数, 0より多ければそのまま、それ以外は0を返す
def relu(x):
return np.maximum(0, x)
- 9. 3.出力層
誤差関数
出力層から得られた結果と、訓練データの真値とのズレ具合を定量的に表す。
回帰 二値分類 多クラス分類
活性化関数 恒等関数 シグモイド関数 ソフトマックス関数
誤差関数 二乗誤差 交差エントロピー
解きたい問題毎によしとされる関数はだいたい決まっている。
二乗誤差
・回帰の場合は恒等関数によって得たい数値がそのまま予測値として
得られるため二乗誤差を用いて誤差を計算する。
・二乗することで誤差が正の値となり、絶対値等の複雑な計算が不
要となる。係数1/2は今後の計算(微分)での計算をしやすくするた
めである。
交差エントロピー
・分類の場合はソフトマックス/シグモイド関数を通して得られた、確率
として扱える値として予測値が得られる。
・このため、負の尤度が最大(尤度最小)となるように交差エントロ
ピーを採用することが多い。
# 平均二乗誤差
loss = functions.mean_squared_error(d,y)
def mean_squared_error(d, y):
return np.mean(np.square(d - y)) / 2
# クロスエントロピー
def cross_entropy_error(d, y):
if y.ndim == 1:
d = d.reshape(1, d.size)
y = y.reshape(1, y.size)
# 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
if d.size == y.size:
d = d.argmax(axis=1)
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7)) / batch_size
① return で返しているのがE(w)
② -np.sum(np.log(y[np.arrange(batch_size),d]+1e-7))/batch_size
- 10. 4.勾配降下法
深層学習の目的
学習を通して誤差を最小にするネットワークを作成すること
➡ 勾配降下法を利用してパラメータを最小化
勾配降下法
(ε:学習率)
学習率 ε を大きくしすぎると、最小値に収束せず発散する。
逆に学習率を小さくしすぎると、収束までの時間がかかる。また、真の最
小値ではない、極値で収束してしまう可能性がある。
収束化手法として Momentum / AdaGrad / Adadelta / Adamなどがある。
grad = backward(x, d, z1, y)
learning_rate = 0.01
for key in ('W1', 'W2', 'b1', 'b2'):
network[key] -= learning_rate * grad[key]
backward(x, d, z1, y) で勾配(grad) ∇Eを求めて、
学習率 ε=0.01 として、パラメータ(network[key])の値を更新
している。
パラメータの更新
# 数値微分
def numerical_gradient(f, x):
h = 1e-4
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
# f(x + h)の計算
x[idx] = tmp_val + h
fxh1 = f(x)
# f(x - h)の計算
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2 * h)
# 値を元に戻す
x[idx] = tmp_val
return grad
勾配の求め方
プログラムで微小な数値を生成し疑似
的に微分を計算する一般的な手法
各パラメータでE(wm+h)等の計算を
するため、順伝播の計算を繰り返し行
う必要があり負荷が大きい
➡ 誤差逆伝播法を利用(後述)
- 11. 4.勾配降下法
勾配降下法の各手法
勾配降下法 確率的勾配降下法 ミニバッチ勾配降下法
用いるデータ 全サンプルの平均誤差 ランダムに抽出したサンプルの誤差 ランダムに分割したデータの集合(ミニバッチ)Dtに属
するサンプルの平均誤差
メリット 計算コスト軽減、局所極小解に収束するリスクの低減
オンライン学習ができる。オンライン学習:新たなデータが入
力するたびにパラメータを更新する方法であり、インターネット
上で得た情報を用い、即モデルの更新を行うことができる。
確率的勾配降下法のメリットを損なわず、計算機の計
算資源を有効利用できる。→ GPUによる並列計算
コード # データのランダム抽出
random_datasets = np.random.choice(data_sets, epoch)
# 勾配降下の繰り返し
for dataset in random_datasets:
x, d = dataset['x'], dataset['d']
z1, y = forward(network, x)
grad = backward(x, d, z1, y)
# パラメータに勾配適用
for key in ('W1', 'W2', 'b1', 'b2'):
network[key] -= learning_rate * grad[key]
# 誤差
loss = functions.mean_squared_error(d, y)
losses.append(loss)
更新イメージ図
- 14. 5.誤差逆伝播法
# 誤差逆伝播
def backward(x, d, z1, y):
# print("n##### 誤差逆伝播開始 #####")
grad = {}
W1, W2 = network['W1'], network['W2']
b1, b2 = network['b1'], network['b2']
# 出力層でのデルタ
delta2 = functions.d_mean_squared_error(d, y)
# b2の勾配
grad['b2'] = np.sum(delta2, axis=0)
# W2の勾配
grad['W2'] = np.dot(z1.T, delta2)
# 中間層でのデルタ
#delta1 = np.dot(delta2, W2.T) * functions.d_relu(z1)
## 試してみよう
delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)
delta1 = delta1[np.newaxis, :]
# b1の勾配
grad['b1'] = np.sum(delta1, axis=0)
x = x[np.newaxis, :]
# W1の勾配
grad['W1'] = np.dot(x.T, delta1)
return grad
# 平均二乗誤差の導関数
def d_mean_squared_error(d, y):
if type(d) == np.ndarray:
batch_size = d.shape[0]
dx = (y - d)/batch_size
else:
dx = y - d
return dx
yとdを入植すれば、∂E/∂y=y-dを返す
# シグモイド関数(ロジスティック関数)の導関数
def d_sigmoid(x):
dx = (1.0 - sigmoid(x)) * sigmoid(x)
return dx
# ReLU関数の導関数
def d_relu(x):
return np.where( x > 0, 1, 0)
(∂y/∂u=1)
# 順伝播
def forward(network, x):
# print("##### 順伝播開始 #####")
W1, W2 = network['W1'], network['W2']
b1, b2 = network['b1'], network['b2']
u1 = np.dot(x, W1) + b1
z1 = functions.relu(u1)
## 試してみよう
#z1 = functions.sigmoid(u1)
u2 = np.dot(z1, W2) + b2
y = u2
return z1, y
x1, y は forward(network, x)によって求められる
(計算結果を保持)
(計算結果を保持)
- 16. 6.勾配消失問題解決法
①活性化関数:ReLU関数
最も使われている活性化関数。勾配消
失化問題の回避とスパース化に貢献す
る。
ReLU関数
微分値は0 or 1 となり、1であれば勾
配を減少さない。0の場合はスパース化
に貢献する。
②重みの初期値設定
活性化関数に応じた最適な初期値の設
定方法が提案されている。
Xavierの初期値
<初期値>
・重みの要素を前の層のノードの数の平方根
で除算した値
<対応活性化関数>
・ReLU/シグモイド/双曲線正接
Heの初期値
<初期値>
・重みの要素を前の層のノードの数の平方根
で除算した値に対し√2を掛け合わせた値
<対応活性化関数>
・ReLU関数
③バッチ正規化
ミニバッチ単位で、入力値のデータの偏りを
抑制する手法。
➡活性化関数に値を渡す前後に、バッチ
正規化の処理を含んだ層を加える
これにより勾配消失問題のリスク低減、過学
習の抑制ができる。
- 17. 6.勾配消失問題(補足)
Xavierの初期値コード
Heの初期値コード
# Heの初期値
network['W1'] = np.random.randn(input_layer_size, hidden_layer_size) / np.sqrt(input_layer_size) * np.sqrt(2)
network['W2'] = np.random.randn(hidden_layer_1_size, hidden_layer_size) / np.sqrt(hidden_layer_size) * np.sqrt(2)
# Xavierの初期値
network['W1'] = np.random.randn(input_layer_size, hidden_layer_size) / (np.sqrt(input_layer_size))
network['W2'] = np.random.randn(hidden_layer_size, hidden_layer_2_size) / (np.sqrt(hidden_layer_size))
重みの初期値が全て0(均一)の場合:
すべての重みの値がおなじように更新されてしまい、同じ値をもつ重みとなってしまうという問題が発生する。
バッチ正規化
- 20. 7.学習率最適化手法
勾配降下法 モメンタム AdaGrad RmsProp Adam
アルゴリズム
誤差をパラメータで微分
したものと学習率の積を
計算する
誤差をパラメータで微分したもの
と学習率の積を減算した後、現
在の重みに前回の重みを減算し
た値と慣性の積を加算する
誤差をパラメータで微分したもの
と、再定義した学習率の積を減
算する。
誤差をパラメータで微分したもの
と再定義した学習の積を減算す
る。
モメンタムの、過去の勾配の指
数関数的減衰平均。
RMSPropの、過去の勾配の2
乗の指数関数的減衰平均。
この2つを含んだ最適化アルゴリ
ズム。
メリット
局所最適解にはならず、大域
的最適解となる。
谷間についてから最も低い位置
に行くまでの時間が早い
勾配の緩やかな斜面に対して、
最適解に近づける。
局所最適解にはならず、大域
的最適解となる。
廃ーパーパラメータの調整が必
要な場合が少ない。
モメンタムとRMSPropのメリット
を含んでいる。
デメリット
学習率が徐々に小さくなるので、
鞍点問題を引き起こすことがあ
る。
数式
コメント
前回の勾配を用いることで、少し
くらいの谷であれば乗り越えてく
れる。ボールがお椀の中を転がる
イメージ。
学習率は初めは大きくし、大域
的最適解を探し、その後は学習
率を小さくし、収束させたい。うま
くいかないこともある。
原理は難しそう。
(ε:学習率)
(μ:慣性)
- 21. 7.学習率最適化手法
class SGD:
def __init__(self, learning_rate=0.01):
self.learning_rate = learning_rate
def update(self, params, grad):
for key in params.keys():
params[key] -= self.learning_rate * grad[key]
class Momentum:
def __init__(self, learning_rate=0.01, momentum=0.9):
self.learning_rate = learning_rate
self.momentum = momentum
self.v = None
def update(self, params, grad):
if self.v is None:
self.v = {}
for key, val in params.items():
self.v[key] = np.zeros_like(val)
for key in params.keys():
self.v[key] = self.momentum * self.v[key] - self.learning_rate * grad[key]
params[key] += self.v[key]
class AdaGrad:
def __init__(self, learning_rate=0.01):
self.learning_rate = learning_rate
self.h = None
def update(self, params, grad):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] += grad[key] * grad[key]
params[key] -= self.learning_rate * grad[key] / (np.sqrt(self.h[key]) + 1e-7)
class RMSprop:
def __init__(self, learning_rate=0.01, decay_rate = 0.99):
self.learning_rate = learning_rate
self.decay_rate = decay_rate
self.h = None
def update(self, params, grad):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] *= self.decay_rate
self.h[key] += (1 - self.decay_rate) * grad[key] * grad[key]
params[key] -= self.learning_rate * grad[key] / (np.sqrt(self.h[key]) + 1e-7)
class Adam:
def __init__(self, learning_rate=0.001, beta1=0.9, beta2=0.999):
self.learning_rate = learning_rate
self.beta1 = beta1
self.beta2 = beta2
self.iter = 0
self.m = None
self.v = None
def update(self, params, grad):
if self.m is None:
self.m, self.v = {}, {}
for key, val in params.items():
self.m[key] = np.zeros_like(val)
self.v[key] = np.zeros_like(val)
self.iter += 1
lr_t = self.learning_rate * np.sqrt(1.0 - self.beta2 ** self.iter) / (1.0 - self.beta1 ** self.iter)
for key in params.keys():
self.m[key] += (1 - self.beta1) * (grad[key] - self.m[key])
self.v[key] += (1 - self.beta2) * (grad[key] ** 2 - self.v[key])
params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
- 30. 10.AlexNet
2012年のILSVRC(International Large Scale Visual Recognition Challenge)で優勝した「AlexNet」
の紹介をする。5層の畳み込み層及びプーリング層など、それに続く3層の全結合層から構成される。
過学習を防ぐために全結合層の出力にドロップアウトを用いている。また、LeRU関数も用いている。
(論文:imagenet_classification_with_deep_convolutional.pdf (toronto.edu))
入力層
(224×224×1)
畳み込み
11×11 フィルタ
4ストライド
(55×55×96)
Max Pooling
3×3 フィルタ
2ストライド
畳み込み
3×3 フィルタ
1パディング
(13×13×384)
畳み込み
3×3 フィルタ
1パディング
(13×13×384)
全結合
(2048)
出力層
(1000)
全結合
(4096)
AlexNetの構造
Max Pooling
3×3 フィルタ
2ストライド
畳み込み
5×5 フィルタ
2パディング
(27×27×256)
畳み込み
3×3 フィルタ
1パディング
(13×13×256)
Pooling
3×3 フィルタ
2ストライド
上下に分かれているのは、使
用するGPUの1号/2号の違い
- 32. 参考文献
• ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
:オライリージャパン
• はじめてのパターン認識(平井有三):森北出版株式会社
• LeNet(lecun-98.pdf)
• AlexNet( imagenet_classification_with_deep_convolutional.pdf (toronto.edu) )
• 他wikipedia、youtubeなど