【深度學(xué)習(xí)實踐】01. 線性回歸

線性模型既是機(jī)器學(xué)習(xí)中最基礎(chǔ)的學(xué)習(xí)模型,也是深度神經(jīng)網(wǎng)絡(luò)中的神經(jīng)元基礎(chǔ)。而線性回歸是借助線性模型解決一個或者多個自變量與因變量之間的關(guān)系的問題。在機(jī)器學(xué)習(xí)領(lǐng)域,大多數(shù)任務(wù)通常與預(yù)測有關(guān)。當(dāng)我們預(yù)測一個數(shù)值時,就會涉及到回歸問題。當(dāng)然,并不是所有的預(yù)測都是回歸問題,還有分類。
線性模型的一般表示如下(本質(zhì)就是對 n 維輸入的加權(quán)和,外加偏差):
\hat{y} = w_1 x_1 + ... + w_d x_d + b.
拓展到矩陣空間的形式如下:
{\hat{\mathbf{y}}} = \mathbf{X} \mathbf{w} + b

線性回歸的目標(biāo)是找到一組權(quán)重向量 w 和偏置b:當(dāng)給定從\mathbf{X}的同分布中取樣的新樣本特征時,這組權(quán)重向量和偏置能夠使新樣本預(yù)測標(biāo)簽的誤差盡可能小

線性模型可以看做單層的神經(jīng)網(wǎng)絡(luò)

衡量預(yù)測的質(zhì)量

既然有了預(yù)測模型(線性模型),我們就可以通過線性模型進(jìn)行預(yù)測,那么接踵而至的問題就是如何衡量預(yù)測的質(zhì)量。預(yù)測質(zhì)量即為真實值和預(yù)估值的差距,我們通常將預(yù)測的質(zhì)量稱為損失函數(shù)。在回歸類問題中,我們的損失函數(shù)多使用 MSE(平方誤差)
l^{(i)}(\mathbf{w}, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2.

除了 MSE,深度學(xué)習(xí)中常用的損失函數(shù)還有很多,MAE(L1),CrossEntropyLoss,SmoothL1Loss等,Loss Functions

MSE 的缺點是對于離群點過于敏感,MAE的缺點是中心點不可導(dǎo),不方便求解

由于樣本和標(biāo)簽是已知的既定事實,所以損失函數(shù)是關(guān)于模型參數(shù) b, \mathbf{w}的函數(shù),常數(shù) \frac {1}{2} 不會帶來本質(zhì)上的差別,但在求導(dǎo)時會和平方項相互抵消。為了度量模型在整個數(shù)據(jù)集上的質(zhì)量,我們通常計算在訓(xùn)練集中n個樣本的損失均值:
L(\mathbf{w}, b) =\frac{1}{n}\sum_{i=1}^n l^{(i)}(\mathbf{w}, b) =\frac{1}{n} \sum_{i=1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)^2.

在訓(xùn)練模型時,我們希望尋找一組參數(shù) b, \mathbf{w},這組參數(shù)能最小化在所有訓(xùn)練樣本上的總損失。如下式:
\mathbf{w}^*, b^* = \operatorname*{argmin}_{\mathbf{w}, b}\ L(\mathbf{w}, b).

梯度下降

梯度下降是通過計算模型基于數(shù)據(jù)集的損失函數(shù)(計算其反向梯度,也就是函數(shù)值下降最快的方向,梯度方向為函數(shù)值增長最快的方向,而負(fù)梯度為函數(shù)值減少最快的方向),通過逐次更新(所有參數(shù)同步更新)從而降低損失值的過程。在許多任務(wù)中,梯度下降都是效果較好的優(yōu)化算法,它幾乎可以優(yōu)化所有深度學(xué)習(xí)模型。其中有一點需要注意的,通常深度學(xué)習(xí)的使用場景,數(shù)據(jù)集的量級都非常之大,動輒上G的樣本,如果模型一次遍歷整個數(shù)據(jù)集求出損失均值,然后進(jìn)行更新,計算耗時太長,所以我們在實際的使用中,通常使用梯度下降的變體--小批量隨機(jī)梯度下降(minibatch stochastic gradient descent),顧名思義,每次隨機(jī)抽取一小批樣本用來計算和更新。

在每次迭代中,我們首先隨機(jī)抽樣一個小批量\mathcal{B},它是由固定數(shù)量的訓(xùn)練樣本組成的。然后,我們計算小批量的平均損失關(guān)于模型參數(shù)的導(dǎo)數(shù)(也可以稱為梯度)。最后,我們將梯度乘以一個預(yù)先確定的正數(shù)\eta,并從當(dāng)前參數(shù)的值中減掉。
我們用下面的數(shù)學(xué)公式來表示這一更新過程(\partial表示偏導(dǎo)數(shù)):
(\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b).

|\mathcal{B}|表示每個小批量中的樣本數(shù),這也稱為批量大小(batch size)。 \eta表示學(xué)習(xí)率(learning rate)。 批量大小和學(xué)習(xí)率的值通常是手動預(yù)先指定,而不是通過模型訓(xùn)練得到的。 這些可以調(diào)整但不在訓(xùn)練過程中更新的參數(shù)稱為超參數(shù)(hyperparameter)。 調(diào)參(hyperparameter tuning)是選擇超參數(shù)的過程。 超參數(shù)通常是我們根據(jù)訓(xùn)練迭代結(jié)果來調(diào)整的, 而訓(xùn)練迭代結(jié)果是在獨立的驗證數(shù)據(jù)集(validation dataset)上評估得到的。

批量大小學(xué)習(xí)率 都是調(diào)參玄學(xué)中重要的組成部分,批量大小決定了每一個批次送入模型訓(xùn)練的數(shù)據(jù)集的規(guī)模,過大的批量大小容易導(dǎo)致內(nèi)存爆滿(尤其是在顯存較小的GPU上進(jìn)行訓(xùn)練),過小的批量大小則無法充分利用GPU的矩陣并行計算的能力(GPU的設(shè)計就是為了進(jìn)行并行的計算,其中包含成百上千的并行計算單元)。而學(xué)習(xí)率也是如此,過大的學(xué)習(xí)率會導(dǎo)致邁的步子過大,損失函數(shù)無法邁入山谷,而學(xué)習(xí)率過小則可能在平原處浪費時間,導(dǎo)致模型需要很久的訓(xùn)練過程。

Pytorch 實現(xiàn)

import numpy as np
import torch
from torch.utils import data
from torch import nn

def synthetic_data(w, b, num_examples):
    """構(gòu)造一個線性模型+隨機(jī)噪聲的數(shù)據(jù)集"""
    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, torch.reshape(y, (-1, 1))

def load_array(data_arrays, batch_size, is_train=True):
    """構(gòu)造一個PyTorch數(shù)據(jù)迭代器"""
    dataset = data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset, batch_size, shuffle=is_train)

true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
batch_size = 10
data_iter = load_array((features, labels), batch_size)

# 定義線性模型
net = nn.Sequential(nn.Linear(2, 1))
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)

loss = nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03)

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}')
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容