自己動手學(xué)深度學(xué)習(xí)(P4)線性回歸問題

參考網(wǎng)站:http://zh.gluon.ai/

從0開始的線性回歸

雖然強大的深度學(xué)習(xí)框架可以減少很多重復(fù)性工作,但如果你過于依賴它提供的便利抽象针贬,那么你可能不會很容易的理解到底深度學(xué)習(xí)是如何工作的击费。所以我們的第一個教程是如何只利用ndarray和autograd來實現(xiàn)一個線性回歸的訓(xùn)練。

線性回歸

給定一個數(shù)據(jù)點集合X和對應(yīng)的目標(biāo)值y桦他,線性模型的目標(biāo)是找一根線蔫巩,其由向量w和位移b組成,來最好的近似每個樣本X[i]y[i]快压。用數(shù)學(xué)符號來表示就是我們將學(xué)wb來預(yù)測圆仔,

并最小化所有數(shù)據(jù)點上的平方誤差

你可能會對我們把古老的線性回歸作為深度學(xué)習(xí)的一個樣例表示很奇怪。實際上線性模型是最簡單但也可能是最有用的神經(jīng)網(wǎng)絡(luò)蔫劣。一個神經(jīng)網(wǎng)絡(luò)就是一個由節(jié)點(神經(jīng)元)和有向邊組成的集合坪郭。我們一般把一些節(jié)點組成層,每一層使用下一層的節(jié)點作為輸入拦宣,并輸出給上面層使用截粗。為了計算一個節(jié)點值,我們將輸入節(jié)點值做加權(quán)和鸵隧,然后再加上一個激活函數(shù)。對于線性回歸而言意推,它是一個兩層神經(jīng)網(wǎng)絡(luò)豆瘫,其中第一層是(下圖橙色點)輸入,每個節(jié)點對應(yīng)輸入數(shù)據(jù)點的一個維度菊值,第二層是單輸出節(jié)點(下圖綠色點)外驱,它使用身份函數(shù)(f(x)=x)作為激活函數(shù)育灸。

創(chuàng)建數(shù)據(jù)集

這里我們使用一個人工數(shù)據(jù)集來把事情弄簡單些,因為這樣我們將知道真實的模型是什么樣的昵宇。具體來首我們使用如下方法來生成數(shù)據(jù)

y[i] = 2 * X[i][0] - 3.4 * X[i][1] + 4.2 + noise

這里噪音服從均值0和方差為0.1的正態(tài)分布磅崭。

from mxnet import ndarray as nd
from mxnet import autograd

num_inputs = 2
num_examples = 1000

true_w = [2, 3.4]
true_b = 4.2

X = nd.random_normal(shape=(num_examples, num_inputs))
y = true_w[0] * X[:, 0] - true_w[1] * X[:, 1] + true_b
y += .01 * nd.random_normal(shape=y.shape)

注意到X的每一行是一個長度為2的向量,而y的每一行是一個長度為1的向量(標(biāo)量)瓦哎。

print(X[0], y[0])

[ 2.21220636  1.16307867]
[ 4.6620779]

數(shù)據(jù)讀取

當(dāng)我們開始訓(xùn)練神經(jīng)網(wǎng)絡(luò)的時候砸喻,我們需要不斷的讀取數(shù)據(jù)塊。這里我們定義一個函數(shù)它每次返回batch_size個隨機的樣本和對應(yīng)的目標(biāo)蒋譬。我們通過python的yield來構(gòu)造一個迭代器割岛。

import random
batch_size = 10
def data_iter():
    # 產(chǎn)生一個隨機索引
    idx = list(range(num_examples))
    random.shuffle(idx)
    for i in range(0, num_examples, batch_size):
        j = nd.array(idx[i:min(i+batch_size,num_examples)])
        yield nd.take(X, j), nd.take(y, j)

下面代碼讀取第一個隨機數(shù)據(jù)塊

for data, label in data_iter():
    print(data, label)
    break
[[ 0.24021588 -0.53960389]
 [ 0.01106104  0.36940244]
 [-0.21115878 -0.64478874]
 [-0.73600543  1.56812   ]
 [-0.73192883 -0.50927299]
 [-0.48362762  0.27216455]
 [-0.60159451  0.29670078]
 [-0.88538933  0.09512273]
 [ 0.19420861 -0.91510016]
 [ 0.00955429 -0.35396427]]

[ 6.49492311  2.97613215  5.98414278 -2.6195066   4.46368217  2.31007123
  1.97259736  2.08594513  7.70643806  5.41053724]

初始化模型參數(shù)

下面我們隨機初始化模型參數(shù)

w = nd.random_normal(shape=(num_inputs, 1))
b = nd.zeros((1,))
params = [w, b]

之后訓(xùn)練時我們需要對這些參數(shù)求導(dǎo)來更新它們的值,所以我們需要創(chuàng)建它們的梯度犯助。

for param in params:
    param.attach_grad()

定義模型

線性模型就是將輸入和模型做乘法再加上偏移:

def net(X):
    return nd.dot(X, w) + b

損失函數(shù)

我們使用常見的平方誤差來衡量預(yù)測的目標(biāo)和真實目標(biāo)之間的差距癣漆。

def square_loss(yhat, y):
    # 注意這里我們把y變形成yhat的形狀來避免自動廣播
    return (yhat - y.reshape(yhat.shape)) ** 2

優(yōu)化

雖然線性回歸有顯試解,但絕大部分模型并沒有剂买。所以我們這里通過隨機梯度下降來求解惠爽。每一步,我們將模型參數(shù)沿著梯度的反方向走特定距離瞬哼,這個距離一般叫學(xué)習(xí)率疆股。(我們會之后一直使用這個函數(shù),我們將其保存在utils.py倒槐。)

def SGD(params, lr):
    for param in params:
        param[:] = param - lr * param.grad

訓(xùn)練

現(xiàn)在我們可以開始訓(xùn)練了旬痹。訓(xùn)練通常需要迭代數(shù)據(jù)數(shù)次,一次迭代里讨越,我們每次隨機讀取固定數(shù)個數(shù)據(jù)點两残,計算梯度并更新模型參數(shù)。

epochs = 5
learning_rate = .001
for e in range(epochs):
    total_loss = 0
    for data, label in data_iter():
        with autograd.record():
            output = net(data)
            loss = square_loss(output, label)
        loss.backward()
        SGD(params, learning_rate)

        total_loss += nd.sum(loss).asscalar()
    print("Epoch %d, average loss: %f" % (e, total_loss/num_examples))
Epoch 0, average loss: 7.941256
Epoch 1, average loss: 0.100285
Epoch 2, average loss: 0.001379
Epoch 3, average loss: 0.000120
Epoch 4, average loss: 0.000103

訓(xùn)練完成后我們可以比較學(xué)到的參數(shù)和真實參數(shù)

true_w, w

([2, 3.4],
 [[ 1.99963176]
  [-3.40014362]])

true_b, b

(4.2,
 [ 4.19964504])

結(jié)論

我們現(xiàn)在看到僅僅使用NDArray和autograd我們可以很容易的實現(xiàn)一個模型把跨。有興趣的話人弓,可以嘗試用不同的學(xué)習(xí)率查看誤差下降速度(收斂率)。

使用Gluon的線性回歸

前面我們僅僅使用了ndarray和autograd來實現(xiàn)線性回歸着逐,現(xiàn)在我們?nèi)匀粚崿F(xiàn)同樣的模型崔赌,但是使用高層抽象包gluon

創(chuàng)建數(shù)據(jù)集

我們生成同樣的數(shù)據(jù)集

from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import gluon

num_inputs = 2
num_examples = 1000

true_w = [2, 3.4]
true_b = 4.2

X = nd.random_normal(shape=(num_examples, num_inputs))
y = true_w[0] * X[:, 0] - true_w[1] * X[:, 1] + true_b
y += .01 * nd.random_normal(shape=y.shape)

數(shù)據(jù)讀取

但這里使用data模塊來讀取數(shù)據(jù)耸别。

batch_size = 10
dataset = gluon.data.ArrayDataset(X, y)
data_iter = gluon.data.DataLoader(dataset, batch_size, shuffle=True)

讀取跟前面一致:

for data, label in data_iter:
    print(data, label)
    break
[[ 1.66524243 -0.790555  ]
 [ 2.73936391  0.73395604]
 [-0.82552391  0.60547197]
 [ 0.18361944 -1.8479687 ]
 [-1.11130977 -0.30177692]
 [-0.23753072 -0.68533319]
 [ 0.02715491 -0.26509324]
 [-1.07131875  0.9324615 ]
 [ 0.6325348  -0.19508815]
 [ 0.82890278 -0.25843123]]

[ 10.22668362   7.193501     0.48110276  10.85089588   3.0170579
   6.05681705   5.15688562  -1.11165142   6.12516403   6.74039841]

定義模型

當(dāng)我們手寫模型的時候健芭,我們需要先聲明模型參數(shù),然后再使用它們來構(gòu)建模型秀姐。但gluon提供大量提前定制好的層慈迈,使得我們只需要主要關(guān)注使用哪些層來構(gòu)建模型。例如線性模型就是使用的對應(yīng)Dense層省有。

雖然我們之后會介紹如何構(gòu)造任意結(jié)構(gòu)的神經(jīng)網(wǎng)絡(luò)痒留,構(gòu)建模型最簡單的辦法是利用Sequential來所有層串起來谴麦。首先我們定義一個空的模型:

net = gluon.nn.Sequential()

然后我們加入一個Dense層,它唯一必須要定義的參數(shù)就是輸出節(jié)點的個數(shù)伸头,在線性模型里面是1.

net.add(gluon.nn.Dense(1))

(注意這里我們并沒有定義說這個層的輸入節(jié)點是多少匾效,這個在之后真正給數(shù)據(jù)的時候系統(tǒng)會自動賦值。我們之后會詳細(xì)介紹這個特性是如何工作的恤磷。)

初始化模型參數(shù)

在使用net前我們必須要初始化模型權(quán)重面哼,這里我們使用默認(rèn)隨機初始化方法(之后我們會介紹更多的初始化方法)。

net.initialize()

損失函數(shù)

gluon提供了平方誤差函數(shù):

square_loss = gluon.loss.L2Loss()

優(yōu)化

同樣我們無需手動實現(xiàn)隨機梯度下降碗殷,我們可以用創(chuàng)建一個Trainer的實例精绎,并且將模型參數(shù)傳遞給它就行。

trainer = gluon.Trainer(
    net.collect_params(), 'sgd', {'learning_rate': 0.1})

訓(xùn)練

這里的訓(xùn)練跟前面沒有太多區(qū)別锌妻,唯一的就是我們不再是調(diào)用SGD代乃,而是trainer.step來更新模型。

epochs = 5
batch_size = 10
learning_rate = .01
for e in range(epochs):
    total_loss = 0
    for data, label in data_iter:
        with autograd.record():
            output = net(data)
            loss = square_loss(output, label)
        loss.backward()
        trainer.step(batch_size)
        total_loss += nd.sum(loss).asscalar()
    print("Epoch %d, average loss: %f" % (e, total_loss/num_examples))
Epoch 0, average loss: 0.905177
Epoch 1, average loss: 0.000052
Epoch 2, average loss: 0.000052
Epoch 3, average loss: 0.000052
Epoch 4, average loss: 0.000052

比較學(xué)到的和真實模型仿粹。我們先從net拿到需要的層搁吓,然后訪問其權(quán)重和位移。

dense = net[0]
true_w, dense.weight.data()

([2, 3.4],
 [[ 2.00046849 -3.40106511]])

true_b, dense.bias.data()

(4.2,
 [ 4.20045042])

結(jié)論

可以看到gluon可以幫助我們更快更干凈的實現(xiàn)模型吭历。在訓(xùn)練的時候堕仔,為什么我們用了比前面要大10倍的學(xué)習(xí)率呢?運行 help(trainer.step)可以知道晌区,學(xué)習(xí)率的數(shù)值一般設(shè)置為1/batch_size摩骨。我們?nèi)绾文苣玫絯eight的梯度呢?運行 help(dense.weight)可知朗若,dense.weight.grad()能查看梯度恼五。善用help命令,能讓我們更好的理解我們的程序哭懈。
下一Part我們將討論如何解決邏輯回歸的問題灾馒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市遣总,隨后出現(xiàn)的幾起案子睬罗,更是在濱河造成了極大的恐慌,老刑警劉巖旭斥,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件容达,死亡現(xiàn)場離奇詭異,居然都是意外死亡琉预,警方通過查閱死者的電腦和手機董饰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圆米,“玉大人卒暂,你說我怎么就攤上這事÷μ” “怎么了也祠?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長近速。 經(jīng)常有香客問我诈嘿,道長,這世上最難降的妖魔是什么削葱? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任奖亚,我火速辦了婚禮,結(jié)果婚禮上析砸,老公的妹妹穿的比我還像新娘昔字。我一直安慰自己,他們只是感情好首繁,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布作郭。 她就那樣靜靜地躺著,像睡著了一般弦疮。 火紅的嫁衣襯著肌膚如雪夹攒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天胁塞,我揣著相機與錄音咏尝,去河邊找鬼。 笑死啸罢,一個胖子當(dāng)著我的面吹牛编检,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伺糠,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼蒙谓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了训桶?” 一聲冷哼從身側(cè)響起累驮,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舵揭,沒想到半個月后谤专,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡午绳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年置侍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜡坊,死狀恐怖杠输,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秕衙,我是刑警寧澤蠢甲,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站据忘,受9級特大地震影響鹦牛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜勇吊,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一曼追、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汉规,春花似錦礼殊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至悟民,卻和暖如春坝辫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背射亏。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工近忙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人智润。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓及舍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窟绷。 傳聞我的和親對象是個殘疾皇子锯玛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容