神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)通過某個(gè)指標(biāo)表示現(xiàn)在的狀態(tài),以這個(gè)指標(biāo)為基準(zhǔn)神經(jīng)網(wǎng)絡(luò) 損失函數(shù)種類,尋找最優(yōu)權(quán)重參數(shù)。神經(jīng)網(wǎng)絡(luò)以某個(gè)指標(biāo)為線索尋找最優(yōu)權(quán)重參數(shù)。神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)中所用的指標(biāo)稱為損失函數(shù)(loss )。損失函數(shù)是表示神經(jīng)網(wǎng)絡(luò)性能的“惡劣程度”的指標(biāo),即當(dāng)前的神經(jīng)網(wǎng)絡(luò)對(duì)監(jiān)督數(shù)據(jù)在多大程度上不擬合。
均方誤差
均方誤差如下所示:
這里,yk是表示神經(jīng)網(wǎng)絡(luò)的輸出,tk表示監(jiān)督數(shù)據(jù),k表示數(shù)據(jù)的維數(shù)。給定兩組數(shù)據(jù):
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
如上式所示,均方誤差會(huì)計(jì)算神經(jīng)網(wǎng)絡(luò)的輸出和正確解監(jiān)督數(shù)據(jù)的各個(gè)元素之差的平方,再求總和。現(xiàn)在,我們用來實(shí)現(xiàn)這個(gè)均方誤差,實(shí)現(xiàn)方式如下所示:
def mean_squared_error(y, t):
return 0.5 * np.sum((y - t) ** 2)
完整程序?qū)崿F(xiàn)如下:
import numpy as np
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]

def mean_squared_error(y, t):
return 0.5 * np.sum((y - t) ** 2)
print(np.argmax(y1)) # 2 argmax表示函數(shù)中會(huì)產(chǎn)生最大output的那個(gè)參數(shù)
print(mean_squared_error(np.array(y1), np.array(t))) # 0.09750000000000003
print(np.argmax(y2)) # 7 argmax表示函數(shù)中會(huì)產(chǎn)生最大output的那個(gè)參數(shù)
print(mean_squared_error(np.array(y2), np.array(t))) # 0.5975
第一個(gè)例子中,正確解是“2”,神經(jīng)網(wǎng)絡(luò)的輸出的最大值是“2”;第二個(gè)例子中,正確解是“2”,神經(jīng)網(wǎng)絡(luò)的輸出的最大值是“7”。如實(shí)驗(yàn)結(jié)果所示,我們發(fā)現(xiàn)第一個(gè)例子的損失函數(shù)的值更小,和監(jiān)督數(shù)據(jù)之間的誤差較小。也就是說,均方誤差顯示第一個(gè)例子的輸出結(jié)果與監(jiān)督數(shù)據(jù)更加吻合。
交叉熵誤差
交叉熵誤差如下式所示:
這里,log表示以e為底數(shù)的自然對(duì)數(shù)(log e)。yk是神經(jīng)網(wǎng)絡(luò)的輸出,tk是正確解標(biāo)簽。并且,tk中只有正確解標(biāo)簽的索引為1,其他均為0(one-hot表示:將正確解標(biāo)簽表示為1,其他標(biāo)簽表示為0的表示方法稱為one-hot表示)。因此,上式實(shí)際上只計(jì)算對(duì)應(yīng)正確解標(biāo)簽的輸出的自然對(duì)數(shù)。比如,假設(shè)正確解標(biāo)簽的索引是“2”,與之對(duì)應(yīng)的神經(jīng)網(wǎng)絡(luò)的輸出是0.6,則交叉熵誤差是?log 0.6 = 0.51;若“2”對(duì)應(yīng)的輸出是0.1,則交叉熵誤差為?log 0.1 = 2.30。也就是說,交叉熵誤差的值是由正確解標(biāo)簽所對(duì)應(yīng)的輸出結(jié)果決定的。下面我們用我們用來實(shí)現(xiàn)這個(gè)均方誤差:
def cross_entropy_error(y, t):
delta = np.array([1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7])
return -np.sum(t * np.log(y + delta))
完整程序?qū)崿F(xiàn)如下:
import numpy as np
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
def cross_entropy_error(y, t):
delta = np.array([1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7])
return -np.sum(t * np.log(y + delta))
print(cross_entropy_error(y1, t)) # 0.510825457099338
print(cross_entropy_error(y2, t)) # 2.302584092994546
第一個(gè)例子中,正確解標(biāo)簽對(duì)應(yīng)的輸出為0.6,此時(shí)的交叉熵誤差大約為0.51。第二個(gè)例子中,正確解標(biāo)簽對(duì)應(yīng)的輸出為0.1的低值,此時(shí)的交叉熵誤差大約為2.3。由此可以看出,這些結(jié)果與我們前面討論的內(nèi)容是一致的。
mini-batch版交叉熵誤差
這里,我們來實(shí)現(xiàn)一個(gè)可以同時(shí)處理單個(gè)數(shù)據(jù)和批量數(shù)據(jù)(數(shù)據(jù)作為batch集中輸入)兩種情況的函數(shù)。
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
這里,y是神經(jīng)網(wǎng)絡(luò)的輸出,t是監(jiān)督數(shù)據(jù)。y的維度為1時(shí)神經(jīng)網(wǎng)絡(luò) 損失函數(shù)種類,即求單個(gè)數(shù)據(jù)的交叉熵誤差時(shí),需要改變數(shù)據(jù)的形狀。并且,當(dāng)輸入為mini-batch時(shí),要用batch的個(gè)數(shù)進(jìn)行正規(guī)化,計(jì)算單個(gè)數(shù)據(jù)的平均交叉熵誤差。程序完整實(shí)現(xiàn)如下:
import numpy as np
t = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])
y1 = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
y2 = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])
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
print(cross_entropy_error(y1, t)) # 0.510825457099338
print(cross_entropy_error(y2, t)) # 2.302584092994546
此外,當(dāng)監(jiān)督數(shù)據(jù)是標(biāo)簽形式(非one-hot表示,而是像“2”“7”這樣的標(biāo)簽)時(shí),交叉熵誤差可通過如下代碼實(shí)現(xiàn):
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]
print(np.arange(batch_size))
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
實(shí)現(xiàn)的要點(diǎn)是,由于one-hot表示中t為0的元素的交叉熵誤差也為0,因此針對(duì)這些元素的計(jì)算可以忽略。換言之,如果可以獲得神經(jīng)網(wǎng)絡(luò)在正確解標(biāo)簽處的輸出,就可以計(jì)算交叉熵誤差。因此,t為one-hot表示時(shí)通過t * np.log(y)計(jì)算的地方,在t為標(biāo)簽形式時(shí),可用np.log( y[np. (), t] )實(shí)現(xiàn)相同的處理(為了便于觀察,這里省略了微小值1e-7)。
作為參考,簡(jiǎn)單介紹一下np.log(y[np.(), t] )。np. ()會(huì)生成一個(gè)從0到-1的數(shù)組。比如當(dāng)為4時(shí),np.()會(huì)生成一個(gè)NumPy 數(shù)組[0, 1, 2, 3]。因?yàn)閠中標(biāo)簽是以[2, 2, 2, 2,]的形式存儲(chǔ)的,所以y[np.(), t]能抽出各個(gè)數(shù)據(jù)的正確解標(biāo)簽對(duì)應(yīng)的神經(jīng)網(wǎng)絡(luò)的輸出(在這個(gè)例子中,y[np.(), t] 會(huì)生成 NumPy 數(shù) 組 [y[0,2], y[1,2], y[2,2], y[3,2]])。完整程序?qū)崿F(xiàn)如下:
import numpy as np

t = np.array([2])
y1 = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
y2 = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])
y3 = np.array([[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0],
[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0],
[0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0],
[0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]])
t2 = np.array([2, 2, 2, 2])
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
print(cross_entropy_error(y1, t)) # 0.510825457099338
print(cross_entropy_error(y2, t)) # 2.302584092994546
print(cross_entropy_error(y3, t2)) # 1.406704775046942