深度學(xué)習(xí)
一掌呜、神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
1.感知機(jī)
w1 和 w2是控制輸入信號(hào)的重要性的參數(shù),而偏置是調(diào)整神經(jīng)元被激活的容易程度(輸出信號(hào)為 1 的程度)的參數(shù)嘹朗。
單層感知機(jī)的局限性:只能表示由一條直線分割的空間。
# 與門
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.7
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
# 與非門
def NAND(x1, x2):
x = np.array([x1, x2])
w = np.array([-0.5, -0.5]) # 僅權(quán)重和偏置與AND不同诲侮!
b = 0.7
a = np.sum(w * x) + b
if a <= 0:
return 0
else:
return 1
# 或門
def OR(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5]) # 僅權(quán)重和偏置與AND不同镀虐!
b = -0.2
a = np.sum(w * x) + b
if a <= 0:
return 0
else:
return 1
# 異或門(多層感知機(jī))
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
2.神經(jīng)網(wǎng)絡(luò)
激活函數(shù)
①sigmoid 函數(shù)
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
x = np.linspace(-5, 5, 100)
y = 1 / (1 + np.exp(-x))
plt.plot(x, y)
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.show()
②tanh函數(shù)(雙曲正切函數(shù))
③ReLU 函數(shù)(修正線性單元)
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
x = np.linspace(-5, 5, 100)
y = np.maximum(0, x)
plt.plot(x, y)
# plt.axhline(y=0, color='k')
# plt.axvline(x=0, color='k')
plt.show()
④Leaky ReLU(帶泄露的修正線性單元)
⑤PReLU(Parameteric Rectified Linear Unit,參數(shù)化修正線性單元)
⑥RReLU(Randomized Leaky Rectified Linear Unit沟绪,隨機(jī)帶泄露的修正線性單元)
⑦ELU(Exponential Linear Unit刮便,指數(shù)修正線性單元)
更多激活函數(shù)見:https://www.cnblogs.com/CJT-blog/p/10421822.html
3.矩陣乘法
np.dot(X, W)
4.神經(jīng)網(wǎng)絡(luò)前向傳播算法
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def identity_function(x):
return x
X = np.array([1.0, 0.5])
W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])
A1 = np.dot(X, W1) + B1
Z1 = sigmoid(A1)
W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
B2 = np.array([0.1, 0.2])
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
B3 = np.array([0.1, 0.2])
A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3)
- 模塊化
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def identity_function(x):
return x
def init_network():
network = {}
network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
network['b1'] = np.array([0.1, 0.2, 0.3])
network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
network['b2'] = np.array([0.1, 0.2])
network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
network['b3'] = np.array([0.1, 0.2])
return network
def forward(network, x):
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
z2 = sigmoid(a2)
a3 = np.dot(z2, W3) + b3
y = identity_function(a3)
return y
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
5.恒等函數(shù)與softmax函數(shù)
(1)恒等函數(shù)
恒等函數(shù)會(huì)將輸入按原樣輸出,對(duì)于輸入的信息绽慈,不加以任何改動(dòng)地直接輸出恨旱。
def identity_function(x):
return x
恒等函數(shù)一般用于回歸問(wèn)題。
(2)softmax函數(shù)
softmax函數(shù)返回的是每個(gè)類別的概率坝疼。
def softmax(a):
exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
缺陷:exp()為指數(shù)函數(shù)搜贤,exp(a)可能為一個(gè)很大的值,導(dǎo)致溢出(inf)钝凶。
-
溢出缺陷改進(jìn)
def softmax(a):
c = np.max(a)
exp_a = np.exp(a - c) # 溢出對(duì)策
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
softmax函數(shù)一般作為輸出層的激活函數(shù)入客。
二、神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)算法
1.損失函數(shù)(loss function)
(1)均方誤差(mean squared error腿椎,MSE)
yk 是表示神經(jīng)網(wǎng)絡(luò)的輸出桌硫,tk 表示監(jiān)督數(shù)據(jù),k 表示數(shù)據(jù)的維數(shù)啃炸。
def mean_squared_error(y, t):
return 0.5 * np.sum((y-t)**2)
(2)交叉熵(cross entropy error)
log 表示以 e為底數(shù)的自然對(duì)數(shù)ln(loge)铆隘。yk 是神經(jīng)網(wǎng)絡(luò)的輸出,tk 是正確解標(biāo)簽南用。并且膀钠,tk 中只有正確解標(biāo)簽的索引為 1,其他均為 0(one-hot 表示)裹虫。
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
2. mini-batch學(xué)習(xí)
mini-batch給訓(xùn)練過(guò)程引入了隨機(jī)性肿嘲,使得訓(xùn)練過(guò)程不致陷入局部最優(yōu)。
- 獨(dú)熱編碼
def cross_entropy_error(y, t):
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
batch_size = y.shape[0]
return -np.sum(t * np.log(y + 1e-7)) / batch_size
- 非獨(dú)熱編碼
def cross_entropy_error(y, t):
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
3.梯度下降法
-
求導(dǎo)數(shù)
def numerical_diff(f, x):
h = 1e-4 # 0.0001
return (f(x+h) - f(x-h)) / (2*h)
-
求梯度
函數(shù)z=f(x,y)在點(diǎn)P(x筑公,y)的梯度雳窟,記作gradf(x,y)或▽f(x,y)。gradf(x,y)=
def numerical_gradient(f, x):
h = 1e-4 # 0.0001
# 生成和x形狀相同的數(shù)組
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
# f(x+h)的計(jì)算
x[idx] = tmp_val + h
fxh1 = f(x)
# f(x-h)的計(jì)算
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2*h)
# 還原值
x[idx] = tmp_val
return grad
- 梯度下降算法
def gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
for i in range(step_num):
grad = numerical_gradient(f, x)
x -= lr * grad
return x
- 梯度下降法可視化
def function_2(x):
return x[0]**2 + x[1]**2
def draw_gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
x_history = []
for i in range(step_num):
x_history.append(x.copy())
# 計(jì)算梯度
grad = numerical_gradient(f, x)
x -= lr * grad
return x, np.array(x_history)
init_x = np.array([-3.0, 4.0])
lr = 0.1
step_num = 20
x, x_history = draw_gradient_descent(function_2, init_x, lr=lr, step_num=step_num)
plt.plot([-5, 5], [0, 0], '--b')
plt.plot([0, 0], [-5, 5], '--b')
plt.plot(x_history[:, 0], x_history[:, 1], 'o')
plt.xlabel('X0')
plt.ylabel('X1')
plt.show()
三匣屡、神經(jīng)網(wǎng)絡(luò)反向傳播算法
1.計(jì)算圖
計(jì)算圖將計(jì)算過(guò)程用圖形表示出來(lái)封救。這里說(shuō)的圖形是數(shù)據(jù)結(jié)構(gòu)圖,通過(guò)多個(gè)節(jié)點(diǎn)和邊表示(連接節(jié)點(diǎn)的直線稱為“邊”)捣作。
2.鏈?zhǔn)椒▌t
反向傳播將局部導(dǎo)數(shù)向正方向的反方向(從右到左)傳遞誉结,傳遞這個(gè)局部導(dǎo)數(shù)的原理,是基于鏈?zhǔn)椒▌t(chain rule)的券躁。
3.激活函數(shù)層實(shí)現(xiàn)
4.Affine/Softmax層實(shí)現(xiàn)
(1)Affine層(仿射層)
class Affine:
def __init__(self, W, b):
self.W = W
self.b = b
self.x = None
self.dW = None
self.db = None
def forward(self, x):
self.x = x
out = np.dot(x, self.W) + self.b
return out
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis=0)
return dx
(2)Softmax-with-Loss 層
class SoftmaxWithLoss:
def __init__(self):
self.loss = None # 損失
self.y = None # softmax的輸出
self.t = None # 監(jiān)督數(shù)據(jù)(one-hot vector)
def forward(self, x, t):
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
def backward(self, dout=1):
batch_size = self.t.shape[0]
dx = (self.y - self.t) / batch_size
return dx
四惩坑、神經(jīng)網(wǎng)絡(luò)最優(yōu)化
1.參數(shù)更新
(1)隨機(jī)梯度下降法(stochastic gradient descent掉盅,SGD)
class SGD:
def __init__(self, lr=0.01):
self.lr = lr
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
SGD缺點(diǎn):在某些情況下效率低
(2)Momentum算法
W 表示要更新的權(quán)重參數(shù),?L/?W表示損失函數(shù)關(guān)于 W 的梯度以舒,η 表示學(xué)習(xí)率怔接。
這里新出現(xiàn)了一個(gè)變量 v,對(duì)應(yīng)物理上的速度稀轨。
class Momentum:
def __init__(self, lr=0.01, momentum=0.9):
self.lr = lr
self.momentum = momentum
self.v = None
def update(self, params, grads):
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.lr*grads[key]
params[key] += self.v[key]
(3)AdaGrad算法
在神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)中扼脐,學(xué)習(xí)率(數(shù)學(xué)式中記為 η)的值很重要。學(xué)習(xí)率過(guò)小奋刽,會(huì)導(dǎo)致學(xué)習(xí)花費(fèi)過(guò)多時(shí)間瓦侮;反過(guò)來(lái),學(xué)習(xí)率過(guò)大佣谐,則會(huì)導(dǎo)致學(xué)習(xí)發(fā)散而不能正確進(jìn)行肚吏。
在關(guān)于學(xué)習(xí)率的有效技巧中,有一種被稱為學(xué)習(xí)率衰減(learning rate decay)的方法狭魂,即隨著學(xué)習(xí)的進(jìn)行罚攀,使學(xué)習(xí)率逐漸減小。實(shí)際上雌澄,一開始“多”學(xué)斋泄,然后逐漸“少”學(xué)的方法,在神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)中經(jīng)常被使用镐牺。
逐漸減小學(xué)習(xí)率的想法炫掐,相當(dāng)于將“全體”參數(shù)的學(xué)習(xí)率值一起降低。而 AdaGrad [6] 進(jìn)一步發(fā)展了這個(gè)想法睬涧,針對(duì)“一個(gè)一個(gè)”的參數(shù)募胃,賦予其“定制”的值。
AdaGrad 會(huì)為參數(shù)的每個(gè)元素適當(dāng)?shù)卣{(diào)整學(xué)習(xí)率畦浓,與此同時(shí)進(jìn)行學(xué)習(xí)(AdaGrad 的 Ada 來(lái)自英文單詞 Adaptive痹束,即“適當(dāng)?shù)摹钡囊馑迹?br>
這里新出現(xiàn)了變量 h,如式 (6.5) 所示讶请,它保存了以前的所有梯度值的平方和(式(6.5)中的⊙表示對(duì)應(yīng)矩陣元素的乘法)祷嘶。
class AdaGrad:
def __init__(self, lr=0.01):
self.lr = lr
self.h = None
def update(self, params, grads):
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] += grads[key] * grads[key]
params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
2.權(quán)重初始值
權(quán)重初始化不能為全0初始化,否則會(huì)導(dǎo)致梯度下降法失效秽梅。
也不能將權(quán)重初始值設(shè)成一樣的值抹蚀,否則在誤差反向傳播法中,所有的權(quán)重值都會(huì)進(jìn)行相同的更新企垦,導(dǎo)致多結(jié)點(diǎn)無(wú)意義。
為了防止“權(quán)重均一化”(嚴(yán)格地講晒来,是為了瓦解權(quán)重的對(duì)稱結(jié)構(gòu))钞诡,必須隨機(jī)生成初始值。
(1)Xavier初始值
node_num = 100 # 前一層的節(jié)點(diǎn)數(shù)
w = np.random.randn(node_num, node_num) / np.sqrt(node_num)
sigmoid函數(shù)、tanh函數(shù)等S形函數(shù)作為激活函數(shù)時(shí)適用Xavier初始值荧降。
(2)He初始值
當(dāng)激活函數(shù)使用 ReLU 時(shí)接箫,一般推薦使用 ReLU 專用的初始值,也就是 Kaiming He 等人推薦的初始值朵诫,也稱為“He 初始值”辛友。
當(dāng)前一層的節(jié)點(diǎn)數(shù)為 n 時(shí),He 初始值使用標(biāo)準(zhǔn)差為√(2/n)的高斯分布剪返。
node_num = 100 # 前一層的節(jié)點(diǎn)數(shù)
w = np.random.randn(node_num, node_num) * np.sqrt(2 / node_num)
ReLu函數(shù)作為激活函數(shù)時(shí)適用He初始值废累。
3.批標(biāo)準(zhǔn)化(Batch Normalization)
這里對(duì) mini-batch 的 m 個(gè)輸入數(shù)據(jù)的集合 B={x1, x2···, xm}求均值μB和方差σB^2。然后脱盲,對(duì)輸入數(shù)據(jù)進(jìn)行均值為 0邑滨、方差為 1(合適的分布)的正規(guī)化。ε 為一個(gè)極小值钱反,防止分母為0掖看。
Batch Norm 層會(huì)對(duì)正規(guī)化后的數(shù)據(jù)進(jìn)行縮放和平移的變換。
4.正則化
(1)過(guò)擬合
過(guò)擬合原因
- 模型擁有大量參數(shù)面哥、表現(xiàn)力強(qiáng)哎壳。
- 訓(xùn)練數(shù)據(jù)少。
(2)權(quán)值衰減
權(quán)值衰減是一直以來(lái)經(jīng)常被使用的一種抑制過(guò)擬合的方法尚卫。該方法通過(guò)在學(xué)習(xí)的過(guò)程中對(duì)大的權(quán)重進(jìn)行懲罰耳峦,來(lái)抑制過(guò)擬合。很多過(guò)擬合原本就是因?yàn)闄?quán)重參數(shù)取值過(guò)大才發(fā)生的焕毫。
在求權(quán)重梯度的計(jì)算中蹲坷,要為之前的誤差反向傳播法的結(jié)果加上正則化項(xiàng)的導(dǎo)數(shù)λW。
(3)Dropout(隨機(jī)失活)
Dropout 是一種在學(xué)習(xí)的過(guò)程中隨機(jī)刪除神經(jīng)元的方法邑飒。訓(xùn)練時(shí)循签,隨機(jī)選出隱藏層的神經(jīng)元,然后將其刪除疙咸。被刪除的神經(jīng)元不再進(jìn)行信號(hào)的傳遞县匠,如下圖所示。訓(xùn)練時(shí)撒轮,每傳遞一次數(shù)據(jù)乞旦,就會(huì)隨機(jī)選擇要?jiǎng)h除的神經(jīng)元。然后题山,測(cè)試時(shí)兰粉,雖然會(huì)傳遞所有的神經(jīng)元信號(hào),但是對(duì)于各個(gè)神經(jīng)元的輸出顶瞳,要乘上訓(xùn)練時(shí)的刪除比例后再輸出玖姑。
class Dropout:
def __init__(self, dropout_ratio=0.5):
self.dropout_ratio = dropout_ratio
self.mask = None
def forward(self, x, train_flg=True):
if train_flg:
self.mask = np.random.rand(*x.shape) > self.dropout_ratio
return x * self.mask
else:
return x * (1.0 - self.dropout_ratio)
def backward(self, dout):
return dout * self.mask
5.超參數(shù)驗(yàn)證
- 步驟 0:設(shè)定超參數(shù)的范圍愕秫。
- 步驟 1:從設(shè)定的超參數(shù)范圍中隨機(jī)采樣。
- 步驟 2:使用步驟 1 中采樣到的超參數(shù)的值進(jìn)行學(xué)習(xí)焰络,通過(guò)驗(yàn)證數(shù)據(jù)評(píng)估識(shí)別精度(但是要將 epoch 設(shè)置得很写魉Α)。
- 步驟3:重復(fù)步驟 1 和步驟 2(100 次等)闪彼,根據(jù)它們的識(shí)別精度的結(jié)果甜孤,縮小超參數(shù)的范圍。