系列文章
李沐《動手學深度學習》預備知識 張量操作及數(shù)據(jù)處理
李沐《動手學深度學習》預備知識 線性代數(shù)及微積分
教材:李沐《動手學深度學習》
一、線性回歸
(一)線性回歸的基本元素
- 線性回歸基于的假設:
- 假設自變量和因變量之間的關系是線性的,這里通常允許包含觀測值的一些噪聲;
- 假設任何噪聲都比較正常,如噪聲遵循正態(tài)分布。
- 線性回歸的矩陣向量表示:(這個過程中的求和將使用廣播機制 )
y ^ = X w + b \hat{y}=Xw+b y^?=Xw+b - 線性回歸的損失函數(shù):(回歸問題中最常用的損失函數(shù)是平方誤差函數(shù))
平方誤差的定義為:
l ( i ) ( w , b ) = 1 2 ( y ^ ( i ) ? y ( i ) ) 2 l^{(i)}(w,b)=\frac{1}{2}(\hat{y}^{(i)}-y^{(i)})^2 l(i)(w,b)=21?(y^?(i)?y(i))2
訓練集n個樣本上的損失均值:
L ( w , b ) = 1 n ∑ i = 1 n l ( i ) ( w , b ) = 1 n ∑ i = 1 n 1 2 ( w T x ( i ) + b ? y ( i ) ) 2 L(w,b)=\frac{1}{n}\sum_{i=1}^nl^{(i)}(w,b)=\frac{1}{n}\sum_{i=1}^n\frac{1}{2}(w^Tx^{(i)}+b-y^{(i)})^2 L(w,b)=n1?i=1∑n?l(i)(w,b)=n1?i=1∑n?21?(wTx(i)+b?y(i))2
訓練模型時,希望找到一組參數(shù)最小化所有訓練樣本的損失,即:
w ? , b ? = argmin ? w , b ? L ( w , b ) w^*,b^*={ \underset {w,b} { \operatorname {argmin} } \,L(w,b)} w?,b?=w,bargmin?L(w,b) -
解析解
線性回歸的解可以用一個公式簡單的表達出來,這類解成為解析解。不是所有的問題都存在解析解。
w ? = ( X T X ) ? 1 X T y w^*=(X^TX)^{-1}X^Ty w?=(XTX)?1XTy -
正態(tài)分布與平方損失
在高斯噪聲的假設下,最小化均方誤差等價于對線性模型的極大似然估計。
(二)隨機梯度下降
- 隨機梯度下降方法幾乎可以優(yōu)化所有深度學習模型,它通過不斷地在損失函數(shù)遞減的方向上更新參數(shù)來降低誤差;
- 梯度下降的用法是計算損失函數(shù)關于模型參數(shù)的導數(shù);
- 由于每次更新參數(shù)之前都必須遍歷整個數(shù)據(jù)集,梯度下降法的執(zhí)行可能會非常慢。因此我們通常會采用每次需要計算更新時隨機抽取一小批樣本的方法,即小批量隨機梯度下降法。
隨機梯度下降的公式表示:
(
w
,
b
)
←
(
w
,
b
)
?
η
∣
B
∣
∑
i
∈
B
?
(
w
,
b
)
l
(
i
)
(
w
,
b
)
(w,b)\leftarrow(w,b)-\frac{\eta}{|B|}\sum_{i\in B}\partial_{(w,b)}l^{(i)}(w,b)
(w,b)←(w,b)?∣B∣η?i∈B∑??(w,b)?l(i)(w,b)
在每次迭代中,先隨機抽樣一個小批量 B B B(由固定數(shù)量的訓練樣本組成),然后計算小批量的平均損失的導數(shù)(梯度),最后將梯度乘以一個預定的正數(shù) η \eta η(學習率),并從當前參數(shù)的值中減掉。
批量大小和學習率的值通常是手動預先指定,而不是通過模型訓練得到的。 這些可以調(diào)整但不在訓練過程中更新的參數(shù)稱為超參數(shù)。 調(diào)參(hyperparameter tuning)是選擇超參數(shù)的過程。 超參數(shù)通常是我們根據(jù)訓練迭代結果來調(diào)整的, 而訓練迭代結果是在獨立的驗證數(shù)據(jù)集(validation dataset)上評估得到的。
(三)矢量化加速(實例化說明)
在訓練模型時,會利用線性代數(shù)庫對計算進行矢量化,從而實現(xiàn)整個小批量樣本的同時處理。
對比矢量化和for循環(huán)兩種計算方法,會發(fā)現(xiàn)矢量化方法的計算時間短很多,代碼實現(xiàn)如下:
相關庫的準備:
%matplotlib inline
import math
import time
import numpy as np
import torch
from d2l import torch as d2l
d2l的安裝
定義一個計時器:
class Timer: #@save
"""記錄多次運行時間"""
def __init__(self):
self.times = []
self.start()
def start(self):
"""啟動計時器"""
self.tik = time.time()
def stop(self):
"""停止計時器并將時間記錄在列表中"""
self.times.append(time.time() - self.tik)
return self.times[-1]
def avg(self):
"""返回平均時間"""
return sum(self.times) / len(self.times)
def sum(self):
"""返回時間總和"""
return sum(self.times)
def cumsum(self):
"""返回累計時間"""
return np.array(self.times).cumsum().tolist()
數(shù)據(jù)準備:
n=10000
a=torch.ones([n])
b=torch.ones([n])
用python for循環(huán)進行計算:
該方法花費的時間為’0.16749 sec’
c=torch.zeros(n)
timer=Timer()
for i in range(n):
c[i]=a[i]+b[i]
f'{timer.stop():.5f} sec'
用矢量化進行計算:
該方法花費的時間為’0.00042 sec’
timer.start()
d=a+b
f'{timer.stop():.5f} sec'
結果很明顯,第二種方法比第一種方法快得多。 矢量化代碼通常會帶來數(shù)量級的加速。 另外,可以將更多的數(shù)學運算放到庫中,而無須自己編寫那么多的計算,從而減少了出錯的可能性。
(四)從線性回歸到神經(jīng)網(wǎng)絡
我們可以將線性回歸模型視為僅由單個人工神經(jīng)元組成的神經(jīng)網(wǎng)絡,或稱為單層神經(jīng)網(wǎng)絡:
- 輸入為 x 1 , … , x d x_1,\ldots,x_d x1?,…,xd?, 因此輸入層中的輸入數(shù)為d;
- 輸出為 o 1 o_1 o1?,因此輸出層中的輸出數(shù)是1;
- 由于模型重點在發(fā)生計算的地方,所以通常我們在計算層數(shù)時不考慮輸入層。 也就是說, 圖中神經(jīng)網(wǎng)絡的層數(shù)為1。
對于線性回歸,每個輸入都與每個輸出(在本例中只有一個輸出)相連, 我們將這種變換( 圖中的輸出層) 稱為全連接層(fully-connected layer)。
二、線性回歸的從零開始實現(xiàn)
(一)生成數(shù)據(jù)集
根據(jù)帶有噪聲的線性模型構造一個人造數(shù)據(jù)集:
- 包含1000個樣本
- 線性模型參數(shù): w = [ 2 , ? 3.4 ] T w=[2,-3.4]^T w=[2,?3.4]T、 b = 4.2 b=4.2 b=4.2
- 噪聲項服從均值為0,標準差為0.01的正態(tài)分布
def synthetic_data(w,b,num_examples):
X=torch.normal(0,1,(num_examples,len(w)))
y=torch.matmul(X,w)+b
y+=torch.normal(0,0.01,y.shape)#噪聲
return X,y.reshape((-1,1))
true_w=torch.tensor([2,-3.4])
true_b=4.2
features,labels=synthetic_data(true_w,true_b,1000)
(二)讀取數(shù)據(jù)集
定義一個函數(shù)data_iter, 該函數(shù)能打亂數(shù)據(jù)集中的樣本并以小批量方式獲取數(shù)據(jù)
- 輸入:批量大小、特征矩陣和標簽向量
- 輸出:大小為batch_size的小批量
def data_iter(batch_size,features,labels):
num_examples=len(features)
indices=list(range(num_examples))
random.shuffle(indices)#隨機讀取樣本
for i in range(0,num_examples,batch_size):
batch_indices=torch.tensor(
indices[i:min(i+batch_size,num_examples)])
yield features[batch_indices],labels[batch_indices]
通常,我們利用GPU并行運算的優(yōu)勢,處理合理大小的“小批量”。 每個樣本都可以并行地進行模型計算,且每個樣本損失函數(shù)的梯度也可以被并行計算。 GPU可以在處理幾百個樣本時,所花費的時間不比處理一個樣本時多太多。
(三)初始化模型參數(shù)
從均值為0、標準差為0.01的正態(tài)分布中采樣隨機數(shù)來初始化權重, 并將偏置初始化為0:
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requires_grad=True)
(四)定義模型
def linreg(X,w,b):
return torch.matmul(X,w)+b
(五)定義損失函數(shù)
使用 平方損失函數(shù)。 在實現(xiàn)中,我們需要將真實值y的形狀轉(zhuǎn)換為和預測值y_hat的形狀相同。
def squared_loss(y_hat,y):
return (y_hat-y.reshape(y_hat.shape))**2/2
(六)定義優(yōu)化算法
使用小批量隨機梯度下降法進行優(yōu)化。
def sgd(params,lr,batch_size):
with torch.no_grad():
for param in params:
param -= lr*param.grad/batch_size
param.grad.zero_()
(七)訓練
在每次迭代中,我們讀取一小批量訓練樣本,并通過我們的模型來獲得一組預測。 計算完損失后,我們開始反向傳播,存儲每個參數(shù)的梯度。 最后,我們調(diào)用優(yōu)化算法sgd來更新模型參數(shù)。
在每個迭代周期(epoch)中,使用data_iter函數(shù)遍歷整個數(shù)據(jù)集, 并將訓練數(shù)據(jù)集中所有樣本都使用一次(假設樣本數(shù)能夠被批量大小整除)。 這里的迭代周期個數(shù)num_epochs和學習率lr都是超參數(shù),分別設為3和0.03。 設置超參數(shù)很棘手,需要通過反復試驗進行調(diào)整。文章來源地址http://www.zghlxwxcb.cn/news/detail-810010.html
lr=0.03
num_epochs=3
net=linreg
loss=squared_loss
for epoch in range(num_epochs):
for X,y in data_iter(batch_size,features,labels):
l=loss(net(X,w,b),y)
l.sum().backward()
sgd([w,b],lr,batch_size)
with torch.no_grad():
train_l=loss(net(features,w,b),labels)
print(f'epoch {epoch+1},loss {float(train_l.mean()):f}')
三、線性回歸的簡潔實現(xiàn)
(一)生成數(shù)據(jù)集
根據(jù)帶有噪聲的線性模型構造一個人造數(shù)據(jù)集:
- 包含1000個樣本
- 線性模型參數(shù): w = [ 2 , ? 3.4 ] T w=[2,-3.4]^T w=[2,?3.4]T、 b = 4.2 b=4.2 b=4.2
- 噪聲項服從均值為0,標準差為0.01的正態(tài)分布
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
(二)讀取數(shù)據(jù)集
調(diào)用框架中現(xiàn)有的API來讀取數(shù)據(jù):
- 將features和labels作為API的參數(shù)傳遞
- 通過數(shù)據(jù)迭代器指定batch_size
- 布爾值is_train表示是否希望數(shù)據(jù)迭代器對象在每個迭代周期內(nèi)打亂數(shù)據(jù)。
def load_array(data_arrays,batch_size,is_train=True):
#構造一個數(shù)據(jù)迭代器
# TensorDataset 將輸入的特征數(shù)據(jù)和標簽數(shù)據(jù)打包成一個數(shù)據(jù)集
dataset=data.TensorDataset(*data_arrays)
# DataLoader 用于批量加載數(shù)據(jù),可以選擇是否在每個 epoch 時隨機打亂數(shù)據(jù)
return data.DataLoader(dataset,batch_size,shuffle=is_train)
batch_size=10
data_iter=load_array((features,labels),batch_size)
(三)定義模型
對于標準深度學習模型,我們可以使用框架的預定義好的層。這使我們只需關注使用哪些層來構造模型,而不必關注層的實現(xiàn)細節(jié)。
torch.nn.Sequential 是一個容器模塊,它按順序包含了其他模塊(layers)。這個容器允許將一系列的神經(jīng)網(wǎng)絡層按照順序組合在一起,形成一個更大的網(wǎng)絡模型。Sequential 類提供了一種簡單的方式來構建和組織神經(jīng)網(wǎng)絡模型,尤其適用于順序堆疊的層結構。
將兩個參數(shù)傳遞到nn.Linear中。 第一個指定輸入特征形狀,即2,第二個指定輸出特征形狀,輸出特征形狀為單個標量,因此為1。
from torch import nn
net=nn.Sequential(nn.Linear(2,1))
(四)初始化模型參數(shù)
在使用net之前,我們需要初始化模型參數(shù)。 如在線性回歸模型中的權重和偏置。 深度學習框架通常有預定義的方法來初始化參數(shù)。 在這里,我們指定每個權重參數(shù)應該從均值為0、標準差為0.01的正態(tài)分布中隨機采樣, 偏置參數(shù)將初始化為零。
通過net[0]選擇網(wǎng)絡中的第一個圖層, 然后使用weight.data和bias.data方法訪問參數(shù)。 我們還可以使用替換方法normal_和fill_來重寫參數(shù)值。
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)
(五)定義損失函數(shù)
使用 平方損失函數(shù)。 在實現(xiàn)中,我們需要將真實值y的形狀轉(zhuǎn)換為和預測值y_hat的形狀相同。
loss=nn.MSELoss()
(六)定義優(yōu)化算法
使用小批量隨機梯度下降法進行優(yōu)化。
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
(七)訓練
在每次迭代中,我們讀取一小批量訓練樣本,并通過我們的模型來獲得一組預測。 計算完損失后,我們開始反向傳播,存儲每個參數(shù)的梯度。 最后,我們調(diào)用優(yōu)化算法sgd來更新模型參數(shù)。文章來源:http://www.zghlxwxcb.cn/news/detail-810010.html
在每個迭代周期(epoch)中,使用data_iter函數(shù)遍歷整個數(shù)據(jù)集, 并將訓練數(shù)據(jù)集中所有樣本都使用一次(假設樣本數(shù)能夠被批量大小整除)。 這里的迭代周期個數(shù)num_epochs和學習率lr都是超參數(shù),分別設為3和0.03。 設置超參數(shù)很棘手,需要通過反復試驗進行調(diào)整。
num_epochs=3
for epoch in range(num_epochs):
for X,y in data_iter:
l=loss(net(X),y)
trainer.zero_grad()
l.backward()
trainer.step()
l=loss(net(features),labels)
print(f'epoch {epoch+1}, loss {l:f}')
到了這里,關于李沐《動手學深度學習》線性神經(jīng)網(wǎng)絡 線性回歸的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!