1 在多個(gè)位置復(fù)用權(quán)重
1、神經(jīng)網(wǎng)絡(luò)最大的挑戰(zhàn)是過擬合。過擬合指的是神經(jīng)網(wǎng)絡(luò)試圖記憶一個(gè)數(shù)據(jù)集,而不是從中學(xué)習(xí)可以泛化到還沒見過的數(shù)據(jù)的有用抽象姻乓。換句話說,神經(jīng)網(wǎng)絡(luò)學(xué)會的是基于數(shù)據(jù)集中的噪聲進(jìn)行預(yù)測眯牧,而不是依賴于基本信號
2蹋岩、過擬合的產(chǎn)生通常是由于當(dāng)前網(wǎng)絡(luò)參數(shù)的數(shù)量多于學(xué)習(xí)特定數(shù)據(jù)集所需要的參數(shù)數(shù)量。這種情況下学少,網(wǎng)絡(luò)有足夠多的參數(shù)剪个,以至于它可以記住訓(xùn)練集中的每一個(gè)細(xì)節(jié),而不是高層次的抽象進(jìn)行學(xué)習(xí)
3版确、網(wǎng)絡(luò)結(jié)構(gòu)是一種很好的防止過擬合的方法扣囊。網(wǎng)絡(luò)結(jié)構(gòu)指的是,在神經(jīng)網(wǎng)絡(luò)中绒疗,因?yàn)槲覀兿嘈拍軌蛟诙鄠€(gè)位置檢測到相同的模式侵歇,所以可以有選擇地重復(fù)用針對多個(gè)目標(biāo)的權(quán)重。正如所見吓蘑,這可以顯著地減少過擬合惕虑,并導(dǎo)致模型的精度更高,因?yàn)樗档土藱?quán)重?cái)?shù)量與數(shù)據(jù)量的比例
4磨镶、在神經(jīng)網(wǎng)絡(luò)中溃蔫,最著名且最廣泛使用的網(wǎng)絡(luò)結(jié)構(gòu)叫作卷積,當(dāng)作為一層使用時(shí)叫作卷積層
2 卷積層(Convolutional Layer)
1琳猫、化整為零伟叛,將許多小線性神經(jīng)元層在各處重用。卷積層背后的思想是脐嫂,它不是一個(gè)大的统刮、稠密的線性神經(jīng)元層紊遵,在其中從每個(gè)輸入到每個(gè)輸出都有連接,而是由很多非常小的線性層構(gòu)成侥蒙,每個(gè)線性層通常擁有少于25個(gè)輸入和一個(gè)輸出暗膜,我們可以在任意輸入位置使用它。每個(gè)小神經(jīng)元層都被稱為卷積核辉哥,但它實(shí)際上只是一個(gè)很小的線性層桦山,含有weights和激活函數(shù)功能攒射,接受少量的輸入并作為單一輸出
2醋旦、圖片底部是4個(gè)不同的卷積核,它們處理相同的8×8的數(shù)字2的圖像会放。每個(gè)卷積核的結(jié)果是是一個(gè)6×6(8-3卷積核長度+1)的預(yù)測矩陣饲齐。你可以對這些矩陣求和(求和池化),取它們的均值(平均池化)咧最,或者按元素計(jì)算最大值(最大池化)
3捂人、最大池化方式是使用最多的:對于每個(gè)位置,查看4個(gè)卷積核各自的輸出矢沿,找到最大值滥搭,并將它復(fù)制到一個(gè)6×6的最終矩陣中,如圖2右下角所示捣鲸。當(dāng)所有運(yùn)算完成后瑟匆,這個(gè)最終矩陣(且僅有這個(gè)最終矩陣)將信號向前傳播到下一層。需要注意的是這4個(gè)卷積核的學(xué)習(xí)模式不同栽惶,右下角的卷積核沒有識別出被訓(xùn)練來預(yù)測的任何模式
4愁溜、網(wǎng)絡(luò)的訓(xùn)練過程允許每個(gè)卷積核學(xué)習(xí)特定的模式,然后在圖像的某個(gè)地方尋找該模式的存在外厂。每個(gè)小巧的卷積核都在多數(shù)數(shù)據(jù)上進(jìn)行了多次向前傳播冕象,從而改變了權(quán)重?cái)?shù)量與訓(xùn)練這些權(quán)重的數(shù)量比例。這對網(wǎng)絡(luò)產(chǎn)生了顯著影響汁蝶,極大地降低了過擬合現(xiàn)象渐扮,提高了網(wǎng)絡(luò)的泛化能力
3 代碼實(shí)現(xiàn)
1、layer_0是一批大小為28×28的圖像掖棉,現(xiàn)在將每個(gè)圖像切成3×3的小圖像席爽,一張圖像可以分割成幾百個(gè)子區(qū)域。通過線性層的一個(gè)輸出神經(jīng)元對它們進(jìn)行正向傳播這一過程啊片,與每批圖像在各個(gè)子區(qū)域上基于線性層進(jìn)行預(yù)測是一樣的
2只锻、具有 n 個(gè)輸出神經(jīng)元的線性層,與n個(gè)卷積核(線性層)在每個(gè)輸入位置進(jìn)行預(yù)測的輸出是一樣的紫谷。這樣做可以使代碼更簡單齐饮,也會更快
import sys,numpy as np
np.random.seed(1)
from keras.datasets import mnist
(x_train,y_train),(x_test,y_test) = mnist.load_data()
#維度分別為(60000,28,28),((60000,)
x_train.shape,y_train.shape
#維度分別為(1000,28*28),((1000,)
#功能:降維捐寥,進(jìn)行標(biāo)準(zhǔn)化
images,labels = (x_train[0:1000].reshape(1000,28*28)/255,y_train[0:1000])
#維度是(1000,10),將一個(gè)最終的數(shù)字祖驱,擴(kuò)充到0-9上的比例
one_hot_labels = np.zeros((len(labels),10))
#這個(gè)是結(jié)果的維度(1000,10),在0-9的的對應(yīng)位置上標(biāo)記為1握恳,其余位置標(biāo)記為0
for i,l in enumerate(labels):
one_hot_labels[i][l] = 1
labels = one_hot_labels
#將像素值降到0-1之間
test_images = x_test.reshape(len(x_test),28*28)/255
test_labels = np.zeros((len(y_test),10))
for i,l in enumerate(y_test):
test_labels[i][l] = 1
#relu = lambda x:(x>0) * x
#relu2deriv = lambda x:x>0
#激活函數(shù),將數(shù)值變換到(-1,1)之間
#隱藏層激活函數(shù)
def tanh(x):
return np.tanh(x)
#反向傳播捺僻,tanh再求導(dǎo)
def tanh2deriv(output):
return 1-(output**2)
#沿著第一維進(jìn)行求和乡洼,保留數(shù)組的維度
#輸出層激活函數(shù)
def softmax(x):
temp = np.exp(x)
return temp/np.sum(temp,axis=1,keepdims=True)
alpha,interations = (2,10)
pixels_per_image,num_labels = (784,10)
#進(jìn)行批訓(xùn)練的時(shí)候,batch_size 為 128
batch_size = 128
#圖片的行匕坯、列個(gè)數(shù)
input_rows = 28
input_cols = 28
#卷積核的行束昵、列數(shù)
kernel_rows = 3
kernel_cols = 3
#使用的卷積核的個(gè)數(shù)
num_kernels = 16
#10000
#隱藏層的size
hidden_size = ((input_rows - kernel_rows)*(input_cols - kernel_cols)) * num_kernels
#維度(9,16), 初始的kernels 權(quán)重,相當(dāng)于weights_0_1
kernels = 0.02*np.random.random((kernel_rows*kernel_cols,num_kernels)) - 0.01
#維度(1000,10),輸出層的維度
weights_1_2 = 0.2*np.random.random((hidden_size,num_labels)) - 0.1
#在一批圖像中選擇子區(qū)域葛峻,選擇了一批輸入圖像的一小部分
def get_image_section(layer,row_from,row_to,col_from,col_to):
#對layer數(shù)據(jù)進(jìn)行切片
section = layer[:,row_from:row_to,col_from:col_to]
#重塑切片后的shape
#reshape 用于修改數(shù)組的形狀锹雏,不會改變數(shù)組的數(shù)據(jù)和數(shù)量,只會改變其維度
#-1 表示讓Numpy自動(dòng)計(jì)算這一維度的大小.是reshape之后的行數(shù)
return section.reshape(-1,1,row_to-row_from,col_to-col_from)
for j in range(interations):
correct_cnt = 0
#按照 batch_size 分批進(jìn)行訓(xùn)練
for i in range(int(len(images)/batch_size)):
batch_start,batch_end = ((i * batch_size),((i+1)*batch_size))
#在圖像的每個(gè)位置對它進(jìn)行多次調(diào)用
#維度(128,784)
layer_0 = images[batch_start:batch_end]
#維度(128,28,28)术奖,這里是將其升維到 28*28 行列的矩陣
layer_0 = layer_0.reshape(layer_0.shape[0],28,28)
sects = list()
#0-24
for row_start in range(layer_0.shape[1]-kernel_rows):
#0-24
for col_start in range(layer_0.shape[2]-kernel_cols):
#依次選取128個(gè)images的卷積kernels礁遵,維度應(yīng)該是(128,1,3,3)
sect = get_image_section(layer_0,row_start,row_start+kernel_rows,col_start,col_start+kernel_cols)
sects.append(sect)
#將眾多小的卷積數(shù)據(jù)進(jìn)行匯總
expanded_input = np.concatenate(sects,axis=1)
es = expanded_input.shape
#降維
flattened_input = expanded_input.reshape(es[0]*es[1],-1)
#是在layer0之間加了許多線性卷積核,乘以kernels權(quán)重
kernel_output = flattened_input.dot(kernels)
layer_1 = tanh(kernel_output.reshape(es[0],-1))
dropout_mask = np.random.randint(2,size=layer_1.shape)
layer_1 *= dropout_mask*2
#最終的預(yù)測結(jié)果
layer_2 = softmax(np.dot(layer_1,weights_1_2))
for k in range(batch_size):
labelset = labels[batch_start+k:batch_start+k+1]
_inc = int(np.argmax(layer_2[k:k+1])==np.argmax(labelset))
correct_cnt += _inc
#反向傳播步驟
layer_2_delta = (labels[batch_start:batch_end]-layer_2)/(batch_size*layer_2.shape[0])
layer_1_delta = layer_2_delta.dot(weights_1_2.T)*tanh2deriv(layer_1)
layer_1_delta *= dropout_mask
weights_1_2 += alpha*layer_1.T.dot(layer_2_delta)
#對kernel進(jìn)行更新采记,相當(dāng)于更新的 weights_0_1
l1d_reshape = layer_1_delta.reshape(kernel_output.shape)
k_update = flattened_input.T.dot(l1d_reshape)
kernels -= alpha*k_update
test_correct_cnt = 0
for i in range(len(test_images)):
layer_0 = test_images[i:i+1]
layer_0 = layer_0.reshape(layer_0.shape[0],28,28)
layer_0.shape
sects = list()
for row_start in range(layer_0.shape[1] - kernel_rows):
for col_start in range(layer_0.shape[2]-kernel_cols):
sect = get_image_section(layer_0,row_start,row_start+kernel_rows,col_start,col_start+kernel_cols)
sects.append(sect)
expanded_input = np.concatenate(sects,axis=1)
es = expanded_input.shape
flattened_input = expanded_input.reshape(es[0]*es[1],-1)
kernel_output = flattened_input.dot(kernels)
layer_1 = tanh(kernel_output.reshape(es[0],-1))
layer_2 = np.dot(layer_1,weights_1_2)
test_correct_cnt += int(np.argmax(layer_2)==np.argmax(test_labels[i:i+1]))
if(j %1 ==0):
sys.stdout.write("\n" + "I:" + str(j) + " Test-Acc:" +str(test_correct_cnt/float(len(test_images))) + \
" Train-Acc:" +str(correct_cnt/float(len(images))))
4 總結(jié)
1佣耐、卷積層的大多數(shù)用法是多層疊加在一起,這樣每個(gè)卷積都將前一層的輸出作為輸入
2唧龄、層疊卷積層是促成非常深的神經(jīng)網(wǎng)絡(luò)以及深度學(xué)習(xí)流行的主要進(jìn)展之一
3兼砖、復(fù)用權(quán)重是深度學(xué)習(xí)中最重要的創(chuàng)新之一
4、當(dāng)神經(jīng)網(wǎng)絡(luò)需要在多處使用相同想法時(shí)选侨,應(yīng)試著在這些地方使用相同的權(quán)重掖鱼,這樣做會使那些權(quán)重有更多的樣本可以學(xué)習(xí)并提高泛化能力,從而讓權(quán)重更智能
5 參考資料
《深度學(xué)習(xí)圖解》