神經(jīng)網(wǎng)絡(luò)的典型處理如下所示:
- 定義可學習參數(shù)的網(wǎng)絡(luò)結(jié)構(gòu)(堆疊各層和層的設(shè)計)笛园;
- 數(shù)據(jù)集的制作和輸入块促;
- 對輸入進行處理(由定義的網(wǎng)絡(luò)層進行處理),主要體現(xiàn)在網(wǎng)絡(luò)的前向傳播论巍;
- 計算loss 抢蚀,由Loss層計算渠旁;
- 反向傳播求梯度拓巧;
- 根據(jù)梯度改變參數(shù)值,最簡單的實現(xiàn)方式(SGD)為:
weight = weight - learning_rate * gradient
使用pytorch和auto_grad(torch自動求導功能):
import torch
#import numpy
#from torch.autograd import Variable
EPOCH = 500
LEARNING_RATE = 1e-6
N , D_in , H , D_out = 64 , 1000, 100 , 10
# N代表的是樣本個數(shù),D_in是樣本的維度一死,H是隱藏層的維度,D_out是輸出層的維度
X = torch.randn(N,D_in)
Y = torch.randn(N,D_out)
# 先用隨機值初始化兩層神經(jīng)網(wǎng)絡(luò)的權(quán)重
w1 = torch.randn(D_in,H,requires_grad=True)
w2 = torch.randn(H,D_out,requires_grad=True)
"""h = w1 * x
h_relu = relu(h)
y = w2 * x"""
for step in range(EPOCH):
#前向傳播
h = torch.mm(X, w1) # 隱層 h = w1 * x
h_relu = h.clamp(min=0) # relu 將小于0的部分修正為0 大于0的部分則不變
y_pred = torch.mm(h_relu, w2) # 輸出層 y = w2 * h_relu
# 損失函數(shù)計算誤差
loss = (y_pred - Y).pow(2).sum()
if step % 100 == 0:
print('epoch: {} loss: {:.5f}'.format(step, loss.item()))#loss為(1,)的tensor
# 反向傳播 計算導數(shù)
loss.backward() # 會自動計算所有參數(shù)的導數(shù)(包括W1肛度、W2、X)
#更新參數(shù)
with torch.no_grad():
#隨機梯度下降
w1 -= LEARNING_RATE * w1.grad
w2 -= LEARNING_RATE * w2.grad
#更新完梯度之后要手動置0投慈。不置0會一直疊加
w1.grad.zero_()
w2.grad.zero_()
使用pytorch(反向傳播要自己求導):
import torch
EPOCH = 500
LEARNING_RATE = 1e-6
#超參數(shù)初始化
N , D_in , H , D_out = 64 , 1000, 100 , 10 # N代表的是樣本個數(shù)承耿,D_in是樣本的維度,H是隱藏層的維度,D_out是輸出層的維度
#訓練數(shù)據(jù)和參數(shù)初始化
X = torch.randn(N,D_in)
Y = torch.randn(N,D_out)
# 先用隨機值初始化兩層神經(jīng)網(wǎng)絡(luò)的權(quán)重
w1 = torch.randn(D_in,H)
w2 = torch.randn(H,D_out)
#print("X:",X,"Y:",Y,w1,w2)
for step in range(500):
#前向傳播
h = X.mm(w1) #(N,H)
h_relu = h.clamp(min=0)#(N,H)
y_pred = h_relu.mm(w2) #(N,D_out)
#定義損失函數(shù)
loss = (y_pred - Y).pow(2).sum().item()
if step % 100 == 0:
print('epoch: {} loss: {:.5f}'.format(step, loss))#loss為(1,)的tensor
#反向傳播
grad_y_pred = 2.0 * (y_pred - Y)#(N,D_out)
grad_w2 = h_relu.t().mm(grad_y_pred)#(H,D_out)
grad_h_relu = grad_y_pred.mm(w2.t())#(N,H)
grad_h[h > 0] = grad_h_relu[h > 0].clone()#大于0時導數(shù)不變
grad_h[h < 0] = 0#小于0時導數(shù)變0
grad_w1 = X.t().mm(grad_h)#要grad_w1的矩陣維度和w1維度相同伪煤,才能相減
#參數(shù)更新
w1 -= LEARNING_RATE * grad_w1
w2 -= LEARNING_RATE * grad_w2
這種寫法加袋,反向傳播的求導是最大的難點。需要理解正向傳播和反向傳播來推導公式抱既,再把公式用代碼實現(xiàn)职烧。最好需要看一下吳恩達的機器學習視頻的前三章(代價函數(shù)和梯度求導)和神經(jīng)網(wǎng)絡(luò)部分,理解反向傳播的計算方法防泵。但是它的視頻的激勵函數(shù)不同蚀之,我們需要針對本代碼中的relu函數(shù)來實現(xiàn)反向傳播。
這里我貼出了手寫的推導過程:
推導過程.jpg
下面是對神經(jīng)網(wǎng)絡(luò)里面的一些tensor進行輸出捷泞,從維度來理解
import torch
lr = 1e-6
EPOCH = 500
LEARNING_RATE = 1e-6
#超參數(shù)初始化
N , D_in , H , D_out = 3 , 4, 2 ,1 # N代表的是樣本個數(shù)足删,D_in是樣本的維度,H是隱藏層的維度,D_out是輸出層的維度
#訓練數(shù)據(jù)和參數(shù)初始化
X = torch.randn(N,D_in)
Y = torch.randn(N,D_out)
# 先用隨機值初始化兩層神經(jīng)網(wǎng)絡(luò)的權(quán)重
w1 = torch.randn(D_in,H)
w2 = torch.randn(H,D_out)
print("X:",X)#3樣本 4特征
print("Y:",Y)#3結(jié)果
print("w1:",w1)
print("w2",w2)
h = X.mm(w1)
print("h:",h)
h_relu = h.clamp(min=0)#(N,h_dim)
print("h_relu",h_relu)
附上運行結(jié)果和個人理解:
X: tensor([[ 1.3393, -0.3668, -0.3531, 1.4490],
[-0.2834, 0.3056, 1.0691, 1.7448],
[ 0.1956, 0.9079, 0.4525, -1.1220]])
Y: tensor([[-1.8117],
[-0.4406],
[ 1.1850]])
w1: tensor([[ 1.4459, -0.1429],
[-0.8366, -0.5614],
[-1.4148, -0.4373],
[ 0.4911, -1.1529]])
w2 tensor([[-0.6083],
[-0.2623]])
h: tensor([[ 3.4545, -1.5016],
[-1.3210, -2.6101],
[-1.6679, 0.5581]])
h_relu tensor([[3.4545, 0.0000],
[0.0000, 0.0000],
[0.0000, 0.5581]])
- 神經(jīng)網(wǎng)絡(luò)的示意圖是以一個特征(維度)為一個單元锁右,而不是變量失受。
- X有三個變量讶泰,每個變量有四個特征(維度)。W1分別對四個特征的每個特征有兩種權(quán)值
- 隱藏層有三個變量拂到,兩個單元(維度)
- 將變量的4種特征×權(quán)值1相加之后痪署,就得到了隱藏層單元里這個對應變量的特征值1
- 將變量的4種特征×權(quán)值2相加之后,就得到了隱藏層單元里這個對應變量的特征值2
參考:
- 吳恩達機器學習視頻:https://www.bilibili.com/video/av50747658?from=search&seid=8008773056378130405
- https://blog.csdn.net/qq_30057549/article/details/103018003
- 個人的針對吳恩達機器學習視頻的筆記(參考修改自黃海廣博士)