實作深層神經網路
本章我們將編碼完成全連接神經網路,并使用CIFAR-10資料集進行測驗,在本章練習中我們將完成:
- 1.仿射層傳播
- 2.ReLU層傳播
- 3.組合單層神經元
- 4.實作淺層全連接神經網路
- 5.實作深層全連接神經網路
# -*- coding: utf-8 -*-
import time
import numpy as np
import matplotlib.pyplot as plt
from classifiers.chapter3 import *
from utils import *
%matplotlib inline
plt.rcParams['figure.figsize'] =(10.0, 8.0) # 設定默認繪圖尺寸
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
%load_ext autoreload
%autoreload 2
def rel_error(x, y):
#計算相對錯誤
return np.max(np.abs(x - y) /(np.maximum(1e-8, np.abs(x) + np.abs(y))))
# 將CIFAR10資料集的匯入,切片,預處理操作進行封裝
data = get_CIFAR10_data() #獲取資料
# 訓練資料
X_train =data['X_train']
y_train =data['y_train']
# 驗證資料
X_val = data['X_val']
y_val = data['y_val']
# 測驗資料
X_test = data['X_test']
y_test = data['y_test']
for k, v in data.items():
print('%s: ' % k, v.shape)
X_train: (49000, 3, 32, 32)
y_train: (49000,)
X_val: (1000, 3, 32, 32)
y_val: (1000,)
X_test: (1000, 3, 32, 32)
y_test: (1000,)
仿射層前向傳播
仿射(affine)傳播就是將各個輸入特征進行加權求和,如果下一層有m個神經元,那就相當于線性代數中的m組線性方程式,
進行測驗:
# 測驗affine_forward 函式
# np.linspaces,規定起點、終點(包含)、回傳array的長度,回傳一個兩端點間數值平均分布的array,
num_inputs = 2
input_shape =(4, 5, 6)
output_dim = 3 #輸出維度
# 2*4*5*6
input_size = num_inputs * np.prod(input_shape)
# 3*4*5*6
weight_size = output_dim * np.prod(input_shape)
# 初始化輸入引數
x = np.linspace(-0.1, 0.5, num=input_size).reshape(num_inputs, *input_shape)
w = np.linspace(-0.2, 0.3, num=weight_size).reshape(np.prod(input_shape), output_dim)
b = np.linspace(-0.3, 0.1, num=output_dim)
# 測驗affine_forward函式
out, _ = affine_forward(x, w, b)
correct_out = np.array([[ 1.49834967, 1.70660132, 1.91485297],
[ 3.25553199, 3.5141327, 3.77273342]])
# 比較你的實作結果和正確結果,該誤差應該小于1e-9,
print('測驗 affine_forward 函式:')
print('誤差: ', rel_error(out, correct_out))
測驗 affine_forward 函式:
誤差: 9.769847728806635e-10
仿射層反向傳播
在前向傳播中,實作的啟示就是out=x1w1+x2w2+b這個函式,那仿射層的反向傳播,其實就是將x,w,b各自對應的梯度求出即可,需要注意的是,在快取中我們存盤的是原始資料的四維影像資料,因此,同前向傳播一樣,首先將資料轉換為二維資料后,再進行求解,
# 測驗 affine_backward 函式
from utils.gradient_check import *
x = np.random.randn(10, 2, 3)
w = np.random.randn(6, 5)
b = np.random.randn(5)
dout = np.random.randn(10, 5)
dx_num = eval_numerical_gradient_array(lambda x: affine_forward(x, w, b)[0], x, dout)
dw_num = eval_numerical_gradient_array(lambda w: affine_forward(x, w, b)[0], w, dout)
db_num = eval_numerical_gradient_array(lambda b: affine_forward(x, w, b)[0], b, dout)
_, cache = affine_forward(x, w, b)
dx, dw, db = affine_backward(dout, cache)
# 相對誤差應該小于1e-10
print('測驗 affine_backward 函式:')
print('dx 誤差: ', rel_error(dx_num, dx))
print('dw 誤差: ', rel_error(dw_num, dw))
print('db 誤差: ', rel_error(db_num, db))
測驗 affine_backward 函式:
dx 誤差: 2.6581417320273106e-08
dw 誤差: 2.2266239834308258e-11
db 誤差: 3.035949501360111e-11
ReLU層前向傳播
ReLU激活函式的公式為max(0, x),我們直接使用NumPy提供的內置公式即可,實作 relu_forward 激活函式的前向傳播,并使用下列代碼進行測驗:
# 測驗relu_forward 函式
x = np.linspace(-0.5, 0.5, num=12).reshape(3, 4)
out, _ = relu_forward(x)
correct_out = np.array([[ 0., 0., 0., 0., ],
[ 0., 0., 0.04545455, 0.13636364,],
[ 0.22727273, 0.31818182, 0.40909091, 0.5, ]])
# 比較輸出結果. 其誤差大約為 1e-8
print('測驗 relu_forward 函式:')
print('誤差: ', rel_error(out, correct_out))
測驗 relu_forward 函式:
誤差: 4.999999798022158e-08
ReLU層反向傳播
實作 relu_backward函式并使用數值梯度進行檢驗:
x = np.random.randn(10, 10)
dout = np.random.randn(*x.shape)
dx_num = eval_numerical_gradient_array(lambda x: relu_forward(x)[0], x, dout)
_, cache = relu_forward(x)
dx = relu_backward(dout, cache)
# 其相對誤差大約為1e-12
print('測驗 relu_backward 函式:')
print('dx 誤差: ', rel_error(dx_num, dx))
測驗 relu_backward 函式:
dx 誤差: 3.2756356627391068e-12
完整的神經元層
接下來我們將上述的affine傳播,和ReLU傳播組合在一起,形成一層完整的神經元層,
在你實作affine_relu_forward和affine_relu_backward函式之后,運行下面的代碼進行梯度檢驗:
#初始化,
x = np.random.randn(2, 3, 4)
w = np.random.randn(12, 10)
b = np.random.randn(10)
dout = np.random.randn(2, 10)
#執行ReLU,獲取分析梯度,
out, cache = affine_relu_forward(x, w, b)
dx, dw, db = affine_relu_backward(dout, cache)
#獲取數值梯度,
dx_num = eval_numerical_gradient_array(lambda x: affine_relu_forward(x, w, b)[0], x, dout)
dw_num = eval_numerical_gradient_array(lambda w: affine_relu_forward(x, w, b)[0], w, dout)
db_num = eval_numerical_gradient_array(lambda b: affine_relu_forward(x, w, b)[0], b, dout)
#比較相對誤差,
print('測驗 ReLU神經元相對誤差:')
print('dx 誤差: ', rel_error(dx_num, dx))
print('dw 誤差: ', rel_error(dw_num, dw))
print('db 誤差: ', rel_error(db_num, db))
測驗 ReLU神經元相對誤差:
dx 誤差: 6.029307341263184e-11
dw 誤差: 4.873523095375596e-10
db 誤差: 4.284094461510698e-11
輸出層:Softmax
運行下列代碼以確認我們的實作是正確的:
num_classes, num_inputs = 10, 50
x = 0.001 * np.random.randn(num_inputs, num_classes)
y = np.random.randint(num_classes, size=num_inputs)
dx_num = eval_numerical_gradient(lambda x: softmax_loss(x, y)[0], x, verbose=False)
loss, dx = softmax_loss(x, y)
# 測驗 softmax_loss 函式. 損失值大約為 2.3 dx 誤差大約為 1e-8
print('\n測驗 softmax_loss:')
print('loss: ', loss)
print('dx error: ', rel_error(dx_num, dx))
測驗 softmax_loss:
loss: 2.3026391824439414
dx error: 9.528882883490555e-09
淺層神經網路
現在我們將實作淺層全連接神經網路,打開chapter3\shallow_layer_net.py檔案,閱讀內容完成相應任務后,執行下面代碼進行驗證,
N, D, H, C = 3, 5, 50, 7
X = np.random.randn(N, D)
y = np.random.randint(C, size=N)
std = 1e-2
model = ShallowLayerNet(input_dim=D, hidden_dim=H, num_classes=C, weight_scale=std)
print('測驗初始化 ... ')
W1_std = abs(model.params['W1'].std() - std)
b1 = model.params['b1']
W2_std = abs(model.params['W2'].std() - std)
b2 = model.params['b2']
# assert(W1_std < std / 10, '第一層權重初始化有問題')
# assert(np.all(b1 == 0), '第一層偏置初始化有問題')
# assert(W2_std < std / 10, '第二層權重初始化有問題')
# assert(np.all(b2 == 0), '第二層偏置初始化有問題')
print('測驗前向傳播程序 ... ')
model.params['W1'] = np.linspace(-0.7, 0.3, num=D*H).reshape(D, H)
model.params['b1'] = np.linspace(-0.1, 0.9, num=H)
model.params['W2'] = np.linspace(-0.3, 0.4, num=H*C).reshape(H, C)
model.params['b2'] = np.linspace(-0.9, 0.1, num=C)
X = np.linspace(-5.5, 4.5, num=N*D).reshape(D, N).T
scores = model.loss(X)
correct_scores = np.asarray(
[[11.53165108, 12.2917344, 13.05181771, 13.81190102, 14.57198434, 15.33206765, 16.09215096],
[12.05769098, 12.74614105, 13.43459113, 14.1230412, 14.81149128, 15.49994135, 16.18839143],
[12.58373087, 13.20054771, 13.81736455, 14.43418138, 15.05099822, 15.66781506, 16.2846319 ]])
scores_diff = np.abs(scores - correct_scores).sum()
# assert(scores_diff < 1e-6, '前向傳播有問題')
# print('測驗訓練損失(無正則化)')
y = np.asarray([0, 5, 1])
loss, grads = model.loss(X, y)
correct_loss = 3.4702243556
# assert(abs(loss - correct_loss) < 1e-10, '訓練階段的損失值(無正則化)有問題')
print('測驗訓練損失(正則化0.1)')
model.reg = 1.0
loss, grads = model.loss(X, y)
correct_loss = 26.5948426952
# assert(abs(loss - correct_loss) < 1e-10, '訓練階段的損失值(有正則化)有問題')
for reg in [0.0, 0.7]:
print('梯度檢驗,正則化系數 = ', reg)
model.reg = reg
loss, grads = model.loss(X, y)
for name in sorted(grads):
f = lambda _: model.loss(X, y)[0]
grad_num = eval_numerical_gradient(f, model.params[name], verbose=False)
print('%s 相對誤差: %.2e' %(name, rel_error(grad_num, grads[name])) )
測驗初始化 ...
測驗前向傳播程序 ...
測驗訓練損失(正則化0.1)
梯度檢驗,正則化系數 = 0.0
W1 相對誤差: 1.52e-08
W2 相對誤差: 3.48e-10
b1 相對誤差: 6.55e-09
b2 相對誤差: 4.33e-10
梯度檢驗,正則化系數 = 0.7
W1 相對誤差: 8.18e-07
W2 相對誤差: 2.85e-08
b1 相對誤差: 1.09e-09
b2 相對誤差: 9.09e-10
訓練淺層全連接網路
閱讀 ShallowLayerNet.train()以及predict()函式,確保自己了解整個流程
input_size = 32 * 32 * 3
hidden_size = 100
num_classes = 10
net = ShallowLayerNet(input_size, hidden_size, num_classes)
# 訓練網路
stats = net.train(X_train, y_train, X_val, y_val,
num_iters=2000, batch_size=500,
learning_rate=1e-3, learning_rate_decay=0.95,
reg=0.6, verbose=True)
# 驗證結果
val_acc =(net.predict(X_val) == y_val).mean()
print('最終驗證正確率: ', val_acc)
print('歷史最佳驗證正確率: ', stats['best_val_acc'])
迭代次數 0 / 2000: 損失值 2.394240
迭代次數 100 / 2000: 損失值 1.933027
迭代次數 200 / 2000: 損失值 1.765465
迭代次數 300 / 2000: 損失值 1.647589
迭代次數 400 / 2000: 損失值 1.582696
迭代次數 500 / 2000: 損失值 1.606909
迭代次數 600 / 2000: 損失值 1.512944
迭代次數 700 / 2000: 損失值 1.545821
迭代次數 800 / 2000: 損失值 1.487011
迭代次數 900 / 2000: 損失值 1.611031
迭代次數 1000 / 2000: 損失值 1.502333
迭代次數 1100 / 2000: 損失值 1.413480
迭代次數 1200 / 2000: 損失值 1.604284
迭代次數 1300 / 2000: 損失值 1.431850
迭代次數 1400 / 2000: 損失值 1.334827
迭代次數 1500 / 2000: 損失值 1.464982
迭代次數 1600 / 2000: 損失值 1.335481
迭代次數 1700 / 2000: 損失值 1.418904
迭代次數 1800 / 2000: 損失值 1.367120
迭代次數 1900 / 2000: 損失值 1.418279
最終驗證正確率: 0.512
歷史最佳驗證正確率: 0.512
# 繪制損失函式變化曲線
plt.subplot(2, 1, 1)
plt.plot(stats['loss_history'])
plt.title('Loss history')
plt.xlabel('Iteration')
plt.ylabel('Loss')
plt.subplot(2, 1, 2)
plt.plot(stats['train_acc_history'], label='train')
plt.plot(stats['val_acc_history'], label='val')
plt.plot([0.5] * len(stats['val_acc_history']), 'k--')
plt.title('Classification accuracy history')
plt.xlabel('Epoch')
plt.ylabel('Clasification accuracy')
# 添加圖示
plt.legend()
# 控制布局
plt.tight_layout()
plt.show()
?

?
深層全連接網路
接下來我們將實作深層的全連接網路,由于我們以及實作了淺層網路,深層網路的實作將變得很簡單,
深層神經網路相比于淺層神經網路,雖然僅僅是隱藏層數量變多而已,但它卻具有了淺層網路沒有的強大能力,由于我們已經實作了淺層網路,深層網路的實作將變得非常簡單,現在要做的僅僅是將淺層網路中固定的單隱藏層變成任意多層即可,在深層全連接神經網路,隱藏層使用ReLU作為激活函式,輸出層使用Softmax作為分類器,
N, D, H1, H2,H3, C = 2, 15, 20, 30, 20, 10
X = np.random.randn(N, D)
y = np.random.randint(C, size=(N,))
for reg in [0, 0.11, 3.14]:
print('權重衰減系數= ', reg)
model = FullyConnectedNet(input_dim=D,hidden_dims=[H1, H2,H3],num_classes=C,reg=reg, weight_scale=5e-2)
loss, grads = model.loss(X, y)
print('初始化化損失值: ', loss)
for name in sorted(grads):
f = lambda _: model.loss(X, y)[0]
grad_num = eval_numerical_gradient(f, model.params[name], verbose=False, h=1e-5)
print('%s 相對誤差: %.2e' %(name, rel_error(grad_num, grads[name])))
權重衰減系數= 0
初始化化損失值: 2.302395002878659
W1 相對誤差: 7.33e-06
W2 相對誤差: 2.52e-07
W3 相對誤差: 1.21e-06
W4 相對誤差: 3.73e-07
b1 相對誤差: 5.57e-07
b2 相對誤差: 1.47e-08
b3 相對誤差: 1.74e-06
b4 相對誤差: 1.38e-10
權重衰減系數= 0.11
初始化化損失值: 2.5387725473271425
W1 相對誤差: 1.22e-07
W2 相對誤差: 8.56e-07
W3 相對誤差: 1.27e-07
W4 相對誤差: 7.80e-08
b1 相對誤差: 7.76e-08
b2 相對誤差: 4.06e-07
b3 相對誤差: 3.10e-09
b4 相對誤差: 9.36e-11
權重衰減系數= 3.14
初始化化損失值: 8.877932640499402
W1 相對誤差: 1.11e-08
W2 相對誤差: 9.18e-08
W3 相對誤差: 5.11e-08
W4 相對誤差: 4.26e-08
b1 相對誤差: 3.60e-07
b2 相對誤差: 9.61e-08
b3 相對誤差: 2.56e-08
b4 相對誤差: 3.55e-10
# 在小資料集上測驗訓練效果,正常情況下應該出現嚴重過擬合現象
input_size = 32 * 32 * 3
num_classes = 10
num_train = 50
X_train_small= X_train[:num_train]
y_train_small= y_train[:num_train]
w= 1e-1
l = 1e-3
net = FullyConnectedNet(input_size ,[100,100,100,100,100] , num_classes, weight_scale=w ,reg=0.6)
# 訓練網路
stats = net.train(X_train_small, y_train_small, X_val, y_val,
num_iters=20, batch_size=25,
learning_rate=l, learning_rate_decay=0.95,
verbose=True)
plt.subplot(2, 1, 1)
plt.plot(stats['loss_history'],'o')
plt.title('Loss history')
plt.xlabel('Iteration')
plt.ylabel('Loss')
plt.subplot(2, 1, 2)
plt.plot(stats['train_acc_history'], label='train')
plt.plot(stats['val_acc_history'], label='val')
plt.title('Classification accuracy history')
plt.xlabel('Epoch')
plt.ylabel('Clasification accuracy')
# 添加圖示
plt.legend()
# 控制布局
plt.tight_layout()
plt.show()
iteration 0 / 20: loss 1107.251324

input_size = 32 * 32 * 3
num_classes = 10
net = FullyConnectedNet(input_size,[100,100],num_classes,reg=0.6,weight_scale=2e-2)
# 訓練網路
stats = net.train(X_train, y_train, X_val, y_val,
num_iters=2000, batch_size=500,
learning_rate=8e-3, learning_rate_decay=0.95,
verbose=False)
# 測驗性能
val_acc =(net.predict(X_val) == y_val).mean()
print('驗證精度: ', val_acc)
print('最佳驗證精度: ', stats['best_val_acc'])
plt.subplot(2, 1, 1)
plt.plot(stats['loss_history'],'o')
plt.title('Loss history')
plt.xlabel('Iteration')
plt.ylabel('Loss')
plt.subplot(2, 1, 2)
plt.plot(stats['train_acc_history'], label='train')
plt.plot(stats['val_acc_history'], label='val')
plt.title('Classification accuracy history')
plt.xlabel('Epoch')
plt.ylabel('Clasification accuracy')
# 添加圖示
plt.legend()
# 控制布局
plt.tight_layout()
plt.show()
驗證精度: 0.478
最佳驗證精度: 0.487

best_net = None
##########################################################################
# 任務:盡可能訓練一個最佳的深層神經網路 #
##########################################################################
input_size = 32 * 32 * 3
num_classes = 10
# 進行探查
lr = np.logspace(-9, 0, num=5)
ws = np.logspace(-9, 0, num=5)
# 記錄最好的引數
best_lr = 0.0
best_ws = 0.0
best_val_acc = 0.0
for l in lr:
for w in ws:
net = FullyConnectedNet(input_size, [32*32, 320, 160, 32], num_classes, reg=0.6,weight_scale=w)
stats = net.train(X_train, y_train, X_val, y_val,
num_iters=1000, batch_size=500,
learning_rate=l, learning_rate_decay=0.95,
verbose=False)
# 測驗性能
val_acc =(net.predict(X_val) == y_val).mean()
if val_acc > best_val_acc:
best_net = net
best_lr = l
best_ws = w
best_val_acc = val_acc
print('驗證精度: ', val_acc)
print('最佳驗證精度: ', stats['best_val_acc'])
##########################################################################
# 結束編碼 #
##########################################################################
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/344104.html
標籤:AI
上一篇:【知識圖譜】知識表示
