pytorch實(shí)現(xiàn)線性回歸,Softmax與分類模型,多層感知機(jī)

1.線性回歸的簡(jiǎn)潔實(shí)現(xiàn)

實(shí)踐中,我們通常可以用比上分段更簡(jiǎn)潔的代碼來(lái)實(shí)現(xiàn)同樣的模型屁倔。在本節(jié)中,我們將介紹如何使用PyTorch更方便地實(shí)現(xiàn)線性回歸的訓(xùn)練暮胧。

1.1生成數(shù)據(jù)集

我們生成與上一級(jí)中相同的數(shù)據(jù)集锐借。其中features是訓(xùn)練數(shù)據(jù)特征问麸,labels是標(biāo)簽。

num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2
features = torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)

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

PyTorch提供了data包來(lái)讀取數(shù)據(jù)钞翔。由于data經(jīng)常使用變量名严卖,我們將導(dǎo)入的data模塊用代替Data。在每一次重復(fù)中布轿,我們將隨機(jī)讀取包含10個(gè)數(shù)據(jù)樣本的小批量哮笆。

import torch.utils.data as Data

batch_size = 10
# 將訓(xùn)練數(shù)據(jù)的特征和標(biāo)簽組合
dataset = Data.TensorDataset(features, labels)
# 隨機(jī)讀取小批量
data_iter = Data.DataLoader(dataset, batch_size, shuffle=True)

讓我們讀取并打印第一個(gè)小批量數(shù)據(jù)樣本。

for X, y in data_iter:
    print(X, y)
    break

輸出:

tensor([[-2.7723, -0.6627],
        [-1.1058,  0.7688],
        [ 0.4901, -1.2260],
        [-0.7227, -0.2664],
        [-0.3390,  0.1162],
        [ 1.6705, -2.7930],
        [ 0.2576, -0.2928],
        [ 2.0475, -2.7440],
        [ 1.0685,  1.1920],
        [ 1.0996,  0.5106]]) 
 tensor([ 0.9066, -0.6247,  9.3383,  3.6537,  3.1283, 17.0213,  5.6953, 17.6279,
         2.2809,  4.6661])

1.3定義模型

首先汰扭,引入torch.nn模塊稠肘。實(shí)際上,“ nn”是神經(jīng)網(wǎng)絡(luò)(神經(jīng)網(wǎng)絡(luò))的縮寫萝毛。顧名思義项阴,該模塊定義了串聯(lián)神經(jīng)網(wǎng)絡(luò)的層。nn就是利用autograd來(lái)定義模型珊泳。nn的核心數(shù)據(jù)結(jié)構(gòu)是Module鲁冯,它是一個(gè)抽象概念,既可以表示神經(jīng)網(wǎng)絡(luò)中的某個(gè)層(layer)色查,也可以表示一個(gè)包含很多層的神經(jīng)網(wǎng)絡(luò)薯演。在實(shí)際使用中,最常見(jiàn)的做法是繼承nn.Module秧了,編寫自己的網(wǎng)絡(luò)/層跨扮。一個(gè)nn.Module實(shí)例應(yīng)該包含一些層以及返回輸出的前向傳播(forward)方法。下面先來(lái)看看如何用nn.Module實(shí)現(xiàn)一個(gè)線性回歸模型验毡。

class LinearNet(nn.Module):
    def __init__(self, n_feature):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(n_feature, 1)
    # forward 定義前向傳播
    def forward(self, x):
        y = self.linear(x)
        return y

net = LinearNet(num_inputs)
print(net) # 使用print可以打印出網(wǎng)絡(luò)的結(jié)構(gòu)

輸出:

LinearNet(
  (linear): Linear(in_features=2, out_features=1, bias=True)
)

我們也可以用nn.Sequential來(lái)更加網(wǎng)求方便地搭建網(wǎng)絡(luò)衡创,Sequential是一個(gè)有序的容器,層網(wǎng)絡(luò)將按照在傳入Sequential的順序依次被添加到計(jì)算圖產(chǎn)品中晶通。

# 寫法一
net = nn.Sequential(
    nn.Linear(num_inputs, 1)
    # 此處還可以傳入其他層
    )

# 寫法二
net = nn.Sequential()
net.add_module('linear', nn.Linear(num_inputs, 1))
# net.add_module ......

# 寫法三
from collections import OrderedDict
net = nn.Sequential(OrderedDict([
          ('linear', nn.Linear(num_inputs, 1))
          # ......
        ]))

print(net)
print(net[0])

輸出:

Sequential(
  (linear): Linear(in_features=2, out_features=1, bias=True)
)
Linear(in_features=2, out_features=1, bias=True)

可以通過(guò)net.parameters()來(lái)查看模型所有的可學(xué)習(xí)參數(shù)璃氢,此函數(shù)將返回一個(gè)生成器。

for param in net.parameters():
    print(param)

輸出:

Parameter containing:
tensor([[-0.0277,  0.2771]], requires_grad=True)
Parameter containing:
tensor([0.3395], requires_grad=True)

回顧圖1.1中線性回歸在神經(jīng)網(wǎng)絡(luò)圖中的表示狮辽。作為一個(gè)單層神經(jīng)網(wǎng)絡(luò)一也,線性回歸輸出層中的神經(jīng)元和輸入層中各個(gè)輸入完全連接。因此喉脖,線性回歸的輸出層又叫全連接層椰苟。

注意:僅torch.nn支持輸入一個(gè)批處理的樣本不支持樣本樣本輸入,如果只有單個(gè)樣本树叽,可使用input.unsqueeze(0)來(lái)添加一維舆蝴。

1..4初始化模型參數(shù)

在使用net前,我們需要初始化模型參數(shù),如線性回歸模型中的權(quán)重和偏差洁仗。PyTorch在init模塊中提供了多種參數(shù)初始化方法层皱。這里的initinitializer的縮寫形式。我們init.normal_將權(quán)重參數(shù)每個(gè)元素初始化為隨機(jī)采樣于均值0京痢,標(biāo)準(zhǔn)差為0.01的正態(tài)分布奶甘。偏差會(huì)初始化為零。

from torch.nn import init

init.normal_(net[0].weight, mean=0, std=0.01)
init.constant_(net[0].bias, val=0)  # 也可以直接修改bias的data: net[0].bias.data.fill_(0)

注:如果這里的net是用3.3.3節(jié)一開(kāi)始的代碼自定義的祭椰,那么上面代碼會(huì)報(bào)錯(cuò)臭家,net[0].weight應(yīng)替換net.linear.weightbias亦然方淤。因?yàn)?code>net[0]這樣根據(jù)下標(biāo)訪問(wèn)子模塊的寫法只有當(dāng)net是一個(gè)ModuleList或者Sequential實(shí)例時(shí)才可以钉赁,詳見(jiàn)4.1節(jié)。

1.5定義損失函數(shù)

PyTorch在nn模塊中提供了各種損失函數(shù)携茂,這些損失函數(shù)可稱為是一種特殊的層你踩,PyTorch也將這些損失函數(shù)實(shí)現(xiàn)為nn.Module的子類。函數(shù)讳苦。

loss = nn.MSELoss()

1.6 定義優(yōu)化算法

同樣带膜,我們也無(wú)須自己實(shí)現(xiàn)小批量隨機(jī)梯度下降算法。torch.optim模塊提供了很多常用的優(yōu)化算法比如SGD鸳谜,亞當(dāng)和RMSProp等膝藕。我們下面創(chuàng)建33一個(gè)用于優(yōu)化net所有參數(shù)的優(yōu)化器實(shí)例,并指定學(xué)習(xí)率為0.03的小批量隨機(jī)梯度下降(SGD)為優(yōu)化算法咐扭。

import torch.optim as optim

optimizer = optim.SGD(net.parameters(), lr=0.03)
print(optimizer)

輸出:

SGD (
Parameter Group 0
    dampening: 0
    lr: 0.03
    momentum: 0
    nesterov: False
    weight_decay: 0
)

我們還可以為不同子網(wǎng)絡(luò)設(shè)置不同的學(xué)習(xí)率芭挽,這在finetune時(shí)經(jīng)常用到。

optimizer =optim.SGD([
                # 如果對(duì)某個(gè)參數(shù)不指定學(xué)習(xí)率蝗肪,就使用最外層的默認(rèn)學(xué)習(xí)率
                {'params': net.subnet1.parameters()}, # lr=0.03
                {'params': net.subnet2.parameters(), 'lr': 0.01}
            ], lr=0.03)

有時(shí)候我們不想讓學(xué)習(xí)率固定成一個(gè)常數(shù)袜爪,那如何調(diào)整學(xué)習(xí)率呢?主要有兩種做法薛闪。一種是修改optimizer.param_groups中對(duì)應(yīng)的學(xué)習(xí)率辛馆,另一種是更簡(jiǎn)單也是推薦的做法-新建優(yōu)化器,由于optimizer極其輕量級(jí)豁延,體積很小怀各,故而可以構(gòu)建新的optimizer。震蕩等情況术浪。

# 調(diào)整學(xué)習(xí)率
for param_group in optimizer.param_groups:
    param_group['lr'] *= 0.1 # 學(xué)習(xí)率為之前的0.1倍

1.7訓(xùn)練模型

在使用Gluon訓(xùn)練模型時(shí),我們通過(guò)調(diào)用optim實(shí)例的step函數(shù)來(lái)轉(zhuǎn)換模型參數(shù)寿酌。按照小批量隨機(jī)遞減的定義胰苏,我們?cè)?code>step函數(shù)中指定尺寸大小,從而對(duì)批量中樣本梯度求平均醇疼。

num_epochs = 3
for epoch in range(1, num_epochs + 1):
    for X, y in data_iter:
        output = net(X)
        l = loss(output, y.view(-1, 1))
        optimizer.zero_grad() # 梯度清零硕并,等價(jià)于net.zero_grad()
        l.backward()
        optimizer.step()
    print('epoch %d, loss: %f' % (epoch, l.item()))

輸出:

epoch 1, loss: 0.000457
epoch 2, loss: 0.000081
epoch 3, loss: 0.000198

下面我們分別比較比較到到模型參數(shù)和真實(shí)的模型參數(shù)法焰。我們從net獲得需要的層,并訪問(wèn)其權(quán)重(weight)和偏差(bias)倔毙。學(xué)到的參數(shù)和真實(shí)的參數(shù)很接近埃仪。

dense = net[0]
print(true_w, dense.weight)
print(true_b, dense.bias)

輸出:

[2, -3.4] tensor([[ 1.9999, -3.4005]])
4.2 tensor([4.2011])

小結(jié)

  • 使用PyTorch可以更簡(jiǎn)潔地實(shí)現(xiàn)模型。
  • torch.utils.data模塊提供了有關(guān)數(shù)據(jù)處理的工具陕赃,torch.nn模塊定義了神經(jīng)網(wǎng)絡(luò)的層卵蛉,torch.nn.init模塊定義了各種初始化方法,torch.optim模塊提供了很多常用的優(yōu)化算法么库。

2 softmax回歸的簡(jiǎn)潔實(shí)現(xiàn)

(線性回歸的簡(jiǎn)潔實(shí)現(xiàn))中已經(jīng)了解了使用Pytorch實(shí)現(xiàn)模型的便利傻丝。下面,讓我們?cè)俅问褂肞ytorch來(lái)實(shí)現(xiàn)一個(gè)softmax回歸模型诉儒。首先引入所需的包或模塊葡缰。

import torch
from torch import nn
from torch.nn import init
import numpy as np
import sys
sys.path.append("..") 
import d2lzh_pytorch as d2l

2.1獲取和讀取數(shù)據(jù)

我們?nèi)匀皇褂肍ashion-MNIST數(shù)據(jù)集和上段中設(shè)置的批量大小。

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

2.2定義和初始化模型

softmax回歸的輸出層是一個(gè)全連接層忱反,所以我們用一個(gè)線性模塊就可以了泛释。因?yàn)榍懊嫖覀償?shù)據(jù)返回的每個(gè)批量樣本x的形狀為(batch_size,1温算, 28怜校,28),所以我們要先用view()x的形狀轉(zhuǎn)換成(batch_size米者,784)才送入全連接層韭畸。

num_inputs = 784
num_outputs = 10

class LinearNet(nn.Module):
    def __init__(self, num_inputs, num_outputs):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(num_inputs, num_outputs)
    def forward(self, x): # x shape: (batch, 1, 28, 28)
        y = self.linear(x.view(x.shape[0], -1))
        return y

net = LinearNet(num_inputs, num_outputs)

我們將對(duì)x的形狀轉(zhuǎn)換的這個(gè)功能自定義一個(gè)FlattenLayer并記錄在d2lzh_pytorch中方便后面使用。

# 本函數(shù)已保存在d2lzh_pytorch包中方便以后使用
class FlattenLayer(nn.Module):
    def __init__(self):
        super(FlattenLayer, self).__init__()
    def forward(self, x): # x shape: (batch, *, *, ...)
        return x.view(x.shape[0], -1)

這樣我們就可以更方便地定義我們的模型:

from collections import OrderedDict

net = nn.Sequential(
    # FlattenLayer(),
    # nn.Linear(num_inputs, num_outputs)
    OrderedDict([
        ('flatten', FlattenLayer()),
        ('linear', nn.Linear(num_inputs, num_outputs))
    ])
)

然后蔓搞,我們使用均值0胰丁,標(biāo)準(zhǔn)差為0.01的正態(tài)分布隨機(jī)初始化模型的權(quán)重參數(shù)。

init.normal_(net.linear.weight, mean=0, std=0.01)
init.constant_(net.linear.bias, val=0) 

2.3 softmax和交叉熵?fù)p失函數(shù)

因此喂分,PyTorch提供了一個(gè)包括softmax計(jì)算和交叉熵計(jì)算的函數(shù)锦庸。它的數(shù)值穩(wěn)定性更好。

loss = nn.CrossEntropyLoss()

2.4定義優(yōu)化算法

我們使用學(xué)習(xí)逐步0.1的小批量隨機(jī)梯度下降作為優(yōu)化算法蒲祈。

optimizer = torch.optim.SGD(net.parameters(), lr=0.1)

2.5訓(xùn)練模型

接下來(lái)甘萧,我們使用上一級(jí)中定義的訓(xùn)練函數(shù)來(lái)訓(xùn)練模型。

num_epochs = 5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)

輸出:

epoch 1, loss 0.0031, train acc 0.745, test acc 0.790
epoch 2, loss 0.0022, train acc 0.812, test acc 0.807
epoch 3, loss 0.0021, train acc 0.825, test acc 0.806
epoch 4, loss 0.0020, train acc 0.832, test acc 0.810
epoch 5, loss 0.0019, train acc 0.838, test acc 0.823

小結(jié)

  • PyTorch提供的函數(shù)往往具有更好的數(shù)值穩(wěn)定性梆掸。
  • 可以使用PyTorch更簡(jiǎn)潔地實(shí)現(xiàn)softmax回歸扬卷。

3 多層感知機(jī)的簡(jiǎn)潔實(shí)現(xiàn)

下面我們使用PyTorch來(lái)實(shí)現(xiàn)上分段中的多層感知機(jī)。首先引入所需的包或模塊酸钦。

import torch
from torch import nn
from torch.nn import init
import numpy as np
import sys
sys.path.append("..") 
import d2lzh_pytorch as d2l

3.1定義模型

和softmax回歸唯一的不同在于怪得,我們多加了一個(gè)全連接層作為隱藏層。它的隱藏單元個(gè)數(shù)為256,并使用ReLU函數(shù)作為激活函數(shù)徒恋。

num_inputs, num_outputs, num_hiddens = 784, 10, 256

net = nn.Sequential(
        d2l.FlattenLayer(),
        nn.Linear(num_inputs, num_hiddens),
        nn.ReLU(),
        nn.Linear(num_hiddens, num_outputs), 
        )

for params in net.parameters():
    init.normal_(params, mean=0, std=0.01)

3.2讀取數(shù)據(jù)并訓(xùn)練模型

我們使用與3.7節(jié)中訓(xùn)練softmax回歸幾乎相同的步驟來(lái)讀取數(shù)據(jù)并訓(xùn)練模型蚕断。

注:由于這里使用的是PyTorch的SGD而不是d2lzh_pytorch里面的sgd,所以就不存在3.9節(jié)那樣學(xué)習(xí)率看起來(lái)很大的問(wèn)題了入挣。

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
loss = torch.nn.CrossEntropyLoss()

optimizer = torch.optim.SGD(net.parameters(), lr=0.5)

num_epochs = 5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)

輸出:

epoch 1, loss 0.0030, train acc 0.712, test acc 0.744
epoch 2, loss 0.0019, train acc 0.823, test acc 0.821
epoch 3, loss 0.0017, train acc 0.844, test acc 0.842
epoch 4, loss 0.0015, train acc 0.856, test acc 0.842
epoch 5, loss 0.0014, train acc 0.864, test acc 0.818

小結(jié)

  • 通過(guò)PyTorch可以更簡(jiǎn)潔地實(shí)現(xiàn)多層感知機(jī)亿乳。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市径筏,隨后出現(xiàn)的幾起案子葛假,更是在濱河造成了極大的恐慌,老刑警劉巖匠璧,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桐款,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡夷恍,警方通過(guò)查閱死者的電腦和手機(jī)魔眨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酿雪,“玉大人遏暴,你說(shuō)我怎么就攤上這事≈咐瑁” “怎么了朋凉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)醋安。 經(jīng)常有香客問(wèn)我杂彭,道長(zhǎng),這世上最難降的妖魔是什么吓揪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任亲怠,我火速辦了婚禮,結(jié)果婚禮上柠辞,老公的妹妹穿的比我還像新娘团秽。我一直安慰自己,他們只是感情好叭首,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布习勤。 她就那樣靜靜地躺著,像睡著了一般焙格。 火紅的嫁衣襯著肌膚如雪图毕。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天眷唉,我揣著相機(jī)與錄音吴旋,去河邊找鬼损肛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛荣瑟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播摩泪,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼笆焰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了见坑?” 一聲冷哼從身側(cè)響起嚷掠,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荞驴,沒(méi)想到半個(gè)月后不皆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡熊楼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年霹娄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲫骗。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡犬耻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出执泰,到底是詐尸還是另有隱情枕磁,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布术吝,位于F島的核電站计济,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏排苍。R本人自食惡果不足惜沦寂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望纪岁。 院中可真熱鬧凑队,春花似錦、人聲如沸幔翰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遗增。三九已至叫惊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間做修,已是汗流浹背霍狰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工抡草, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔗坯。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓康震,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親宾濒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子腿短,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359