【深度學習】神經網路的學習過程
神經網路的學習
線上性可分的與非門、或門的感知機模型中,我們可以根據真值表人工設定引數來實現,而此時的引數只有3個。然而,在實際的神經網路中,引數的數量成千上萬,甚至上億,很顯然,人工設定引數是不可能的。從資料中學習就成了解決上面問題的關鍵。
- “學習”就是指從訓練資料中自動獲取最優權重引數的過程
- 為了能夠進行學習,需要引入損失函式
- 學習的目的:使損失函式達到最小值的權重引數
- 學習過程可以使用梯度法
損失函式
神經網路的學習需要通過某個指標來表現現在的狀態,然後,以這個指標為基準,尋找最優權重引數。這個指標便是“損失函式”,這個損失函式可以死任意函式,但一般用均方誤差和交叉熵誤差。
損失函式是表示神經網路效能的“惡劣程度”的指標,即當前的神經網路對監督資料在多大程度上不擬合,在多大程度上不一致。
- 均方誤差
其中, 表示神經網路的輸出, 表示監督資料(標籤資料), 表示資料的維度
# 均方誤差損失函式
def mean_squared_error(y, t):
return 0.5 * np.sum((y-t)**2)
# 測試
# 假設數字"2"為正確解
t = [0,0,1,0,0,0,0,0,0,0]
# 預測為"2"的概率最高
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
# 預測為"7"的概率最高
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
# 求均方誤差
print(mean_squared_error(np.array(y1),np.array(t)))
print(mean_squared_error(np.array(y2),np.array(t)))
輸出為:
0.09750000000000003
0.5975
結果我們發現, 的損失函式的值更小,和監督資料之間的誤差較小,也就是 的輸出結果與監督資料更吻合。
- 交叉熵誤差
其中, 表示神經網路的輸出, 表示正確解標籤, 表示資料的維度
中只有正確解標籤的索引為1,其他為0(one-hot表示)
# 交叉熵誤差
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
# 在計算log時,加上了一個微小值,防止出現計算np.log(0)變為負無窮大
# 測試
# 設"2"為正確解
t = [0,0,1,0,0,0,0,0,0,0]
# "2"的概率最高
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
# "7"的概率最高
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
# 求交叉熵誤差
print(cross_entropy_error(np.array(y1),np.array(t)))
print(cross_entropy_error(np.array(y2),np.array(t)))
輸出為:
0.510825457099338
2.302584092994546
此結果與前面均方誤差討論的內容一樣
mini-batch學習(小批量學習)
使用訓練資料進行學習,就是針對訓練資料計算損失函式的值,找到是該值儘可能小的引數,因此計算損失函式的值的時候必須將所有訓練資料作為物件,也就是要把所有訓練資料的損失函式值的總和作為學習的指標。
前面提到的均方誤差和交叉熵誤差都是針對單個數據的損失函式,如果要求所有孫訓練資料的損失函式的總和,這裡僅以交叉熵誤差為例,數學表示式可以寫為:
其中,假設資料有 個, 表示第n個數據的第k個元素的值,是監督資料, 是神經網路的輸出
在資料量特別大的時候,如果我們以全部資料為物件來計算,計算過程需要花費很長的時間
因此,我們需要從全部資料中選出一部分,作為全部資料的“近似”
比如,從60000個訓練資料中隨機選擇100個數據,再用這100個數據進行學習,這種學習方式就稱為mini-batch學習
- 如何選出小批量資料
import numpy as np
import mnist
# load_mnist用於讀入MNIST資料集函式
# 讀入時設定one_hot_label=True,可以得到one-hot表示(即僅正確解標籤為1,其他為0)
(X_train, T_train),(X_test, T_test) = mnist.load_mnist(normalize=False, one_hot_label=True)
print(X_train.shape) # (60000, 784)
print(T_train.shape) # (60000, 10)
train_size = X_train.shape[0] # 訓練資料的數量
batch_size = 10 # 設定批量數為10
# 使用np.random.choice()可以從指定數字中隨機選擇想要的數字
# 比如,np.random.choice(60000, 10)會從0-59999之間隨機選擇10個數字
batch_mask = np.random.choice(train_size, batch_size)
x_batch = X_train[batch_mask]
t_batch = T_train[batch_mask]
- 同時處理單個數據和批量資料的交叉熵誤差的實現
# 可以同時處理單個數據和批量資料
# 監督資料為非one-hot表示
def cross_entropy_error(y, t):
# y為1維時,即
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
# 監督資料是one-hot-vector的情況下,轉換為正確解標籤的索引
if t.size == y.size:
t = t.argmax(axis=1)
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
np.arange(5)表示生成一個NumPy陣列[0, 1, 2, 3, 4],假設監督資料為[2, 7, 0, 9, 4]
y[np.arange(5), t]會生成[y[0, 2], y[1, 7], y[2, 0], y[3, 9], y[4, 4]]
導數、數值微分和偏導數
- 導數數學表示式如下:
關於導數,可自行參考高等數學
- 數值微分
def numerical_diff(f,x):
h = 1e-4 # 0.0001
return (f(x+h) - f(x-h)) / (2 * h) # 這邊使用的是中心差分
根據導數的定義,我們可以向h中賦入一個微小值,讓h無限接近0,但是不能太小,太小可能會導致舍入誤差(指因省略小數的精細部分的數值,小數點第8位以後的數值),導致最終結果的計算上的誤差
- 舉例
import numpy as np
import matplotlib.pylab as plt
def function_1(x):
return 0.01*x**2 + 0.1*x
x = np.arange(0.0, 20.0, 0.1)
y = function_1(x)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.plot(x, y)
plt.show()
print(numerical_diff(function_1, 5)) # 0.1999999999990898
print(numerical_diff(function_1, 10)) # 0.2999999999986347
上面函式的導數為:
在x=5和10處,“真的導數為”0.2和0.3,和上面的結果相比,誤差很小。
- 偏導數
上面我們只是針對單一變數的函式的導數,如果有多個變數的函式的導數,我們稱為偏導數。
用數學式表示為: