Steam Deck預購導致平臺擁堵 大量使用者遭遇報錯
線性迴歸
標籤(空格分隔): 深度學習
我們舉一個實際的例子:我們希望根據房屋的面積和房齡來預計房屋價格。為了開發一個能夠預測房價的模型,我們需要收集一個真實的資料集。
-
該資料集包括:房屋的銷售價格,房齡和麵積。在機器學習的術語中,該資料整合為訓練資料集或訓練集,每一行資料被稱為樣本,也可成為資料點或者資料樣本。我們預測的目標(在這個例子中是房屋價格)成為標籤或目標。預測所根據的自變數成為特徵或者協變數。
-
通常我們使用\(n\)來表示資料集中的樣本數量。對搜因為\(i\)的樣本,其輸入表示為\(X^{(i)}=[x_{1}^{(i)},x_2^{(2)}]^T\),其輸出對應的標籤是\(y^{(i)}\)
線性模型
線性假設是指目標可以表示為特徵的加權和,如下面的式子:$$price = \omega_{area}\cdot area+\omega_{age}\cdot age +b \tag1$$
中的\(\omega_{area}\)和\(\omega_{age}\)稱為權重,\(b\)稱為偏置(bias),或稱為偏移量(offset)、截距(intercept)。權重決定了每個特徵對我們預測值的影響,偏執是指當所有特徵都取為0時,預測值應該為多少。即使現實中不會有任何房子的面積是0 或者房齡正好為0年,我們仍然需要偏置項。如果沒有偏置項,我們模型表的能力將受到限制。嚴格的講\(公式(1)\)*是輸入特徵的一個仿射變換**。仿射變換的特點就是通過加u去哪和特徵進行線性變換,並通過偏置項來進行平移。
給定一個數據集,我們的目標是尋找模型的權重\(W\)和偏置\(b\),使得根據模型做出的預測答題符合資料裡的真實價格。輸出的預測值由輸入特徵通過線性模型的仿射變換決定,仿射變換由所選權重和偏置決定。
- 有些學科往往只關注有少量特徵的資料集,在這些學科中,建模時經常想這樣通過長形式顯示地表達。而在機器學習領域,我們通常使用的是高維資料集,建模時採用線性代數表示法會比較方便。當我們的輸入包含\(d\)個特徵時、我們將預測結果\(\hat{y}\)(通常使用“尖號”符號表示估計值)表示為:$$\hat{y}=\omega_1x_1+\dots+\omega_dx_d+b \tag2$$
將特徵向量放到\(x\in\mathbb{R}^d\)中,並將所有權重放到\(w\in\mathbb{R}^d\)中,我們可以用點積形式來簡潔的表達模型:$$\hat{y}=w^Tx+b\tag3$$
在公式3中,向量\(x\)對用於單個數據特徵的樣本。用符號表示的矩陣\(X\in\mathbb{R}^{x\times{d}}\)可以很方便的引用我們整個資料集的n個樣本。其中,X的每一行是一個樣本,每一列是一種特徵。
對於特徵集合\(X\),預測值\(\hat{y}\in\mathbb{R}^n\)可以通過\(矩陣-向量\)乘法表示為:\(\hat{y}=Xw+b\tag4\)
損失函式
在我們開始考慮如何用模型擬合數據之前,我們需要確定一個擬合程度的度量。損失函式能夠量化目標的實際值和預測值之間的差距。通常我們回選擇非負數作為損失,且數值越小表示損失越小,完美與測試的損失為0,迴歸問題中最常用的損失函式是平方誤差數。當樣本\(i\)的預測值為\(\hat{y}^i\)其對應的真是標籤為\(y^{(i)}\)時,平方誤差可以定義為以下公式:$$l{(i)}(\boldsymbol{w},b)=\frac{1}{2}(\hat{y}{(i)}-y{i})2\tag5$$
常數\(\frac{1}{2}\)不會帶來本質的差別,但這樣在形式上稍微簡單一些,表現為我們對損失函式求導後常數係數為1. 此處的平方時因為 較大的差異值可以帶來更大的損失函式。為了度量模型在整個資料集上的質量,我們需要計算在訓練集n個樣本上的損失均值。$$L(\boldsymbol{w},b)=\frac{1}{n}\sum_{i=1}nl{(i)}(\boldsymbol{w},b)=\frac{1}{2n}\sum_{i=1}n(wTx{(i)}+b-y{(i)})^2\tag6$$
在訓練模型的時候,我們希望能夠尋找一組引數,這組引數可以最小換在所有訓練樣本上的總損失$$(\boldsymbol{w}*,b*)=argmin L(w,b)\tag7$$
解析解
線性迴歸剛好是一個很簡單的優化問題。線性迴歸的解可以用一個公式簡單的表達出來,這類解叫做解析解(analytical solution)。首先,我們將偏置b合併到引數w中。合併方法是在包含所有引數的矩陣中附加一列。我們預測的問題是最小化\(\Vert y-Xw\Vert^2\tag8\)。在這個損失平面上有一個臨界點,這個臨界點對應於整個區域的損失最小值。將損失關於\(\boldsymbol{w}\)的倒數設為0,得到解析解:\(w^*=(X^TX)^{-1}X^Ty\tag9\)像線性迴歸這樣的解析問題存在解析解,但並不是所有的問題都存在解析解。解析解可以很好的進行數學分析,但解析解的限制很嚴格,導致它無法應用在深度學習裡面。
小批量隨機梯度下降
即使在我們無法得到解析解的情況下,我們仍然可以有效的訓練模型。在許多工上,那些難以優化的模型效果要更好。因此,弄清楚如何訓練這些難以優化的模型是非常重要的。
本書中我們用到一種名梯度下降(gradient descent)的方法,這種方法幾乎可以優化所有深度學習模型。它通過不斷的在損失函式的遞減的方向更新引數來降低誤差。
梯度下降最簡單的用法是計算損失函式(資料集中所有樣本的損失均值)關於模型引數的導數(在這裡也可以稱為梯度)。但是在實際的執行中可能會非常慢:因為在每一次更新引數之前,我們必須便利整個資料集。因此我們通常會在每次需要計算更新的時候隨機抽取一批小樣本,這種變體叫做小樣本隨機梯度下降(minibatch stochastic gradient descent)。
在每次迭代中,我們首先隨機抽取一個小批量\(\beta\),它是由固定數量的訓練樣本組成的。然後,我們計算小批量的平均損失關於模型引數的導數(也稱之為梯度)。最後,我們將梯度乘以一個預先確定正數\(\eta\),並從當前引數的值中減掉。
- 根據權重\(\omega\)和偏置\(\beta\)生成num_example個人造資料。其中x是訓練集的資料,y是標籤,在標籤上加上一點標準差為0.01的噪音,
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
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))
生成每批大小為batch_size的資料進行小樣本訓練,獲取總的樣本數量,然後將其打亂。返回batch_size大小的特徵和標籤。
def data_iter(batch_size, features, labels):
num_example = len(features) # 特徵數量
indices = list(range(num_example))
random.shuffle(indices) # 洗牌 特徵順序打亂。
for i in range(0, num_example, batch_size):
batch_indices = torch.tensor(indices[i:min(i + batch_size, num_example)])
yield features[batch_indices], labels[batch_indices]
在開始下批量隨機梯度下賤優化我們的模型引數之前,我們需要一些引數,在下面的程式碼當中,我們從均值為0,標準差為0.01的正態分佈中隨機取樣隨機數來初始化權重,並將偏置初始化為0.
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
在初始引數之後,我們的任務是更新這些引數,直到這些引數足夠你和我們的資料,每次更新都需要計算損失函式關於模型引數的梯度,有了這個梯度,我們就可以向減小損失的方向更新每個引數。
- w 預設的均值為0, 標準差為0.01
- b 預設的初值為0
- x 有大量(n)的已知資料
- y 有大量(n)的已知資料
目標$$L(\boldsymbol{w},b)=\frac{1}{n}\sum_{i=1}nl{(i)}(\boldsymbol{w},b)=\frac{1}{2n}\sum_{i=1}n(wTx{(i)+b}-y{(i)})^2\tag6$$通過改變\(\boldsymbol{w},b\)儘量降低\(L\).
定義模型
def linreg(x,w,b):
return torch.matmul(x,w)+b
損失函式
def squared_loss(y_hat, y):
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
優化演算法
介紹小批量隨機梯度下降的工作示例。
在每一步中,使用從資料集中隨機抽取的一個小批量,然後根據引數計算損失的梯度。接下來,朝著減少損失的方向更新我們的引數。下面的函式實現小批量隨機梯度下降更新。該函式接受模型引數集合,學習速率和批量大小作為輸入。每一步的更新大小由學習速率\(lr\)決定。因為我們計算的損失是一個批量樣本的綜合,所以我們用批量大小來歸一化步長,這樣步長大小就不會取決於我們對批量大小的選擇。
def sgd(params,lr,batch_size):
with torch.no_grad():
for param in params:
param -= lr* param.grad/batch_size
param.grad.zero_()
訓練
在每次迭代中,我們讀取一個小批量訓練樣本,並通過我們的模型來獲取一組預測。計算完損失之後,我們開始反向傳播,儲存每個引數的梯度。最後我們呼叫sgd來更新模型引數。
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}')