PyTorch60分鐘教程學(xué)習(xí)筆記

基本概念

Tensor

tensor是的含義是張量稼跳,簡(jiǎn)單的理解可以將其當(dāng)成三維矩陣妄帘,pytorch中的張量是對(duì)數(shù)據(jù)的一種封裝懂傀,也是數(shù)據(jù)結(jié)構(gòu)中最核心的部分之一慎玖。對(duì)于pytorch中的張量,數(shù)組可能是更好的理解方法呻待。

Tensor的定義

  • 直接定義矩陣打月,使用torch.Tensor(shape)方法定義未初始化的張量,使用torch.rand(shape)torch.randn(shape)定義隨機(jī)張量
import torch as pt
x = pt.Tensor(2,4)
print(x)
# 1.00000e-23 *
#  0.0000  0.0000  1.2028  0.0000
#  0.0000  0.0000  1.1517  0.0000
# [torch.FloatTensor of size 2x4]
x = pt.rand(5,3)
# 0.7609  0.5925  0.5840
# 0.1949  0.6366  0.3763
# 0.1802  0.8529  0.9373
# 0.6013  0.9685  0.9945
# 0.6555  0.1740  0.9884
# [torch.FloatTensor of size 5x3]
print(x,x.size()[0])
# 5
y = pt.rand(5,3)
  • 從numpy 中定義tensor蚕捉,使用torch.from_numpy(ndarray)的方法奏篙,需要注意的是,這種情況下numpy矩陣和tensor會(huì)“綁定”,即修改任何一個(gè)的值秘通,另一個(gè)的值也會(huì)發(fā)生變化
a = np.ones(5)
b = pt.from_numpy(a)
print(a,b)
#[ 1.  1.  1.  1.  1.] 
 #1
 #1
 #1
 #1
 #1
#[torch.DoubleTensor of size 5]

Tensor的基本操作

Tensor和numpy中的ndarray相似为严,可以完成加減乘除等運(yùn)算,常見(jiàn)的操作方法通常為Tensor.操作(參數(shù))torch.操作(參數(shù),out=輸出tensor)肺稀,以加法為例

result = pt.Tensor(5,3)
test = pt.add(x,y,out=result)
# print(result,test)

y.add_(x)

兩種方法test = pt.add(x,y,out=result)y.add_(x)都是相加第股,前者是相加后將結(jié)果交給一個(gè)新的Tensorresult,而后者可以理解為y自加x
Tensor還可以轉(zhuǎn)換為numpy的對(duì)象ndarray话原,可以使用Tensor.numpy()獲得與Tensor綁定的ndarray對(duì)象夕吻,修改Tensor時(shí),ndarray對(duì)象也發(fā)生變化

a = pt.ones(5)
b = a.numpy()
# print(a,b)
a.add_(1)
# print(a,b)

使用GPU加速

使用Tensor = Tensor.cuda()的方法可以講Tensor放到GPU上稿静,通常的運(yùn)算不支持從CPU到GPU的變換梭冠,因此若要在GPU上進(jìn)行網(wǎng)絡(luò)運(yùn)算,網(wǎng)絡(luò)聲明完成后也要調(diào)用網(wǎng)絡(luò)和輸入的.cuda()方法將網(wǎng)絡(luò)和輸入放在GPU上

a,b = pt.Tensor(2,2),pt.Tensor(2,2)
a = a.cuda()
b = b.cuda()

Variable

Variable正向傳播

Variable與TensorFlow中的Variable一樣改备,是構(gòu)建神經(jīng)網(wǎng)絡(luò)和訓(xùn)練的核心類(lèi)控漠,使用Variable可以構(gòu)建計(jì)算圖,并在圖中計(jì)算結(jié)果(正向傳播)和微分(反向傳播)悬钳,Variable的一些運(yùn)算符重載過(guò)盐捷,因此可以直接使用+-*/運(yùn)算符

x = Variable(pt.ones(2,2),requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()
# Variable containing:
#27
#[torch.FloatTensor of size 1]

Variable反向傳播

以上構(gòu)建了一個(gè)計(jì)算圖并計(jì)算了out的值,完成前向傳播默勾,使用out.backward()可以執(zhí)行反向傳播碉渡,就是計(jì)算微分。

out.backward()
print(x.grad)
#Variable containing:
# 4.5000  4.5000
# 4.5000  4.5000
#[torch.FloatTensor of size 2x2]

網(wǎng)絡(luò)構(gòu)建

網(wǎng)絡(luò)結(jié)構(gòu)構(gòu)建

class Net(nn.Module):
    """docstring for Net"""
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1,6,5)# input channel,6 output channel,5x5
        self.conv2 = nn.Conv2d(6,16,5)
        self.fc1 = nn.Linear(16*5*5,120)#input 16*5*5,output120
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self,x):
        x = F.max_pool2d(F.relu(self.conv1(x)),(2,2)) #input,poolcore shape
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) #(2,2) => 2 because 2=2
        x = x.view(-1, self.num_flat_features(x)) #reshape
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self,x):
        size = x.size()[1:] #remove batch size
        num_f = 1
        for s in size:
            num_f *= s
        return num_f

以上為構(gòu)建一個(gè)簡(jiǎn)單的CNN的例子母剥,其中

  • nn來(lái)自import torch.nn as nn這其中封裝各種各樣的網(wǎng)絡(luò)層
  • F來(lái)自import torch.nn.functional as F滞诺,這其中封裝了各種各樣的神經(jīng)網(wǎng)絡(luò)需要使用的函數(shù)

在網(wǎng)絡(luò)結(jié)構(gòu)中

  • nn.Linear(input_size,output_size)為線(xiàn)性連接層,為MLP的線(xiàn)性部分
    -nn.Conv2d(input_channel,output_channel,shape)表示卷積核

函數(shù)中

  • F.max_pool2d(input,core_shape)為池化層
  • F.relu(input)為ReLu激活函數(shù)

另外环疼,Variable.view()為變形函數(shù)习霹,其中的-1表示不關(guān)心batch,而函數(shù)self.num_flat_features(x)是為了獲得x的元素?cái)?shù)量炫隶,這一步直接將x拍扁成向量

網(wǎng)絡(luò)的前向傳播

定義網(wǎng)絡(luò)后(以上的類(lèi))后淋叶,聲明后可以直接調(diào)用

net = Net().cuda()
print(net)
#Net (
# (conv1): Conv2d(1, 6, kernel_size=(5, 5), #stride=(1, 1))
# (conv2): Conv2d(6, 16, kernel_size=(5, 5), #stride=(1, 1))
# (fc1): Linear (400 -> 120)
# (fc2): Linear (120 -> 84)
# (fc3): Linear (84 -> 10)
#)

其中.cuda()是將整個(gè)網(wǎng)絡(luò)放到GPU上,如果直接使用net = Net()網(wǎng)絡(luò)位置在CPU上伪阶,將無(wú)法使用GPU加速煞檩。
定義網(wǎng)絡(luò)后,直接傳入輸入即可完成前向傳播

net.zero_grad() # Zero the gradient buffers of all parameters 

inputdata = Variable(pt.randn(1,1,32,32)) #?(1,1,32,32) nSamples x nChannels x Height x Width
inputdata = inputdata.cuda()
# 1-batch 1-input channel 32,32
# print(inputdata)
# print(inputdata.unsqueeze(0)) #[torch.FloatTensor of size 1x1x1x32x32]
out = net(inputdata)
print(out)

其中net.zero_grad()是為了清除梯度栅贴,起類(lèi)似于初始化的作用斟湃。pytorch要求數(shù)據(jù)與網(wǎng)絡(luò)的位置相同,因此若是網(wǎng)絡(luò)聲明在GPU上檐薯,數(shù)據(jù)也必須要GPU上加速桐早。

網(wǎng)絡(luò)的反向傳播(權(quán)值更新)

網(wǎng)絡(luò)的反向傳播可以直接使用預(yù)先定義的代價(jià)函數(shù)的.backward()方法實(shí)現(xiàn)

net.zero_grad()
print(net.conv1.bias.grad)

loss.backward()
print(net.conv1.bias.grad)

在更新權(quán)值的時(shí)候,可以手動(dòng)指定更新的方法

for f in net.parameters():
    f.data.sub_(f.grad.data * 0.01)

其中:

  • net.parameters()是個(gè)生成器,可以遍歷net中的所有參數(shù)
  • f.grad.data為輸出(代價(jià)函數(shù))到這一參數(shù)的梯度

除了手動(dòng)制定哄酝,也可以從import torch.optim as optim中調(diào)用優(yōu)化器

optimizer = optim.SGD(net.parameters(),lr=0.01)
optimizer.zero_grad()
out = net(inputdata)
loss = criterion(out,target)
loss.backward()
optimizer.step()

其中criterion()為代價(jià)函數(shù),loss為代價(jià)函數(shù)的輸出值祷膳,optimizer.step()為調(diào)用一次優(yōu)化

代價(jià)函數(shù)

代價(jià)函數(shù)表示當(dāng)前結(jié)果距離期望輸出的“距離”陶衅,torch.nn封裝了一些代價(jià)函數(shù),可以在訓(xùn)練的時(shí)候直接調(diào)用

target = Variable(pt.arange(1,11)).cuda()
# print(target)
criterion = nn.MSELoss().cuda()
loss = criterion(out,target) #out shape = 1*10 target shape = 10

這里調(diào)用的代價(jià)函數(shù)是MSELoss()平方平均函數(shù)

分類(lèi)網(wǎng)絡(luò)搭建直晨,訓(xùn)練與測(cè)試

分類(lèi)網(wǎng)絡(luò)數(shù)據(jù)準(zhǔn)備

教程提供的范例的訓(xùn)練集是CIFAR10數(shù)據(jù)集搀军,該數(shù)據(jù)集提供了10種不同類(lèi)型的圖片,引入代碼如下圖

import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim


transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                         shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

這部分僅僅是下載并提供數(shù)據(jù)集勇皇,不必深究罩句,需要注意的是從testloader中獲得數(shù)據(jù)即可

分類(lèi)網(wǎng)絡(luò)搭建

分類(lèi)網(wǎng)絡(luò)搭建使用兩層conv+pool后接3層mlp層的結(jié)構(gòu),是個(gè)基本的卷積神經(jīng)網(wǎng)絡(luò)敛摘,構(gòu)建類(lèi)如下

class Net(nn.Module):
    """docstring for Net"""
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3,6,5)
        self.pool = nn.MaxPool2d(2,2)
        self.conv2 = nn.Conv2d(6,16,5)
        self.fc1 = nn.Linear(16*5*5,120)
        self.fc2 = nn.Linear(120,84)        
        self.fc3 = nn.Linear(84, 10)

    def forward(self,x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1,16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

net = Net().cuda()

這里將組件的定義放在了構(gòu)造函數(shù)中门烂,而將網(wǎng)絡(luò)前饋部分放在了單獨(dú)的forward()函數(shù)中。另外兄淫,使用net = Net().cuda()將網(wǎng)絡(luò)放在了GPU上

分類(lèi)網(wǎng)絡(luò)的訓(xùn)練

分類(lèi)網(wǎng)絡(luò)的訓(xùn)練需要定義優(yōu)化器和代價(jià)函數(shù)屯远,剩下的就是將數(shù)據(jù)丟進(jìn)神經(jīng)網(wǎng)絡(luò)中了,代碼如下

criterion = nn.CrossEntropyLoss()
#聲明使用交叉熵函數(shù)作為代價(jià)函數(shù)
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
#聲明使用學(xué)習(xí)率0.001的SGD優(yōu)化器

for epoch in range(2):
    running_loss = 0
    for i,data in enumerate(trainloader,0):
        inputs,labels = data
        inputs,labels = Variable(inputs).cuda(),Variable(labels).cuda()
        #獲得數(shù)據(jù)并將其放在GPU上
        optimizer.zero_grad()
        #初始化梯度

        outputs = net(inputs)
        #前饋
        loss = criterion(outputs,labels)
        loss.backward()
        optimizer.step()
        #反饋計(jì)算梯度并更新權(quán)值

        running_loss += loss.data[0]
        if i % 200 == 0:
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0
            #打印平均代價(jià)函數(shù)值
print('Finished Training')

總結(jié)一下捕虽,該部分代碼總共做了以下幾件事

  • 定義優(yōu)化器與代價(jià)函數(shù)
  • 執(zhí)行網(wǎng)絡(luò)訓(xùn)練

執(zhí)行網(wǎng)絡(luò)訓(xùn)練部分慨丐,每次迭代包括以下操作

  1. 獲取batch數(shù)據(jù)并將其放在GPU上
    2.初始化梯度
    3.執(zhí)行前饋計(jì)算代價(jià)函數(shù)
    4.執(zhí)行反饋計(jì)算梯度并更新權(quán)值

分類(lèi)網(wǎng)絡(luò)的測(cè)試

網(wǎng)絡(luò)測(cè)試部分就是將所有的訓(xùn)練數(shù)據(jù)再投入網(wǎng)絡(luò)中訓(xùn)練一次,看真實(shí)結(jié)果與預(yù)測(cè)結(jié)果是否相同泄私,代碼如下

corret,total = 0,0
for images,labels in testloader:
    images = images.cuda()
    labels = labels.cuda()
    outputs = net(Variable(images))
    _,predicted = torch.max(outputs.data,1)
    total += labels.size(0)
    corret += (predicted == labels).sum()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * corret / total))

前饋得到預(yù)測(cè)結(jié)果后房揭,使用_,predicted = torch.max(outputs.data,1)在第一維看取出最大的數(shù)(丟棄)和最大數(shù)的位置(保留)后再與label相比即可進(jìn)行測(cè)試

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市晌端,隨后出現(xiàn)的幾起案子捅暴,更是在濱河造成了極大的恐慌,老刑警劉巖斩松,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伶唯,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡惧盹,警方通過(guò)查閱死者的電腦和手機(jī)乳幸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钧椰,“玉大人粹断,你說(shuō)我怎么就攤上這事〉障迹” “怎么了瓶埋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我养筒,道長(zhǎng)曾撤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任晕粪,我火速辦了婚禮挤悉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巫湘。我一直安慰自己装悲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布尚氛。 她就那樣靜靜地躺著诀诊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阅嘶。 梳的紋絲不亂的頭發(fā)上属瓣,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音奈懒,去河邊找鬼奠涌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛磷杏,可吹牛的內(nèi)容都是我干的溜畅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼极祸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼慈格!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起遥金,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤浴捆,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后稿械,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體选泻,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年美莫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了页眯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厢呵,死狀恐怖窝撵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情襟铭,我是刑警寧澤碌奉,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布短曾,位于F島的核電站,受9級(jí)特大地震影響赐劣,放射性物質(zhì)發(fā)生泄漏嫉拐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一魁兼、第九天 我趴在偏房一處隱蔽的房頂上張望椭岩。 院中可真熱鬧,春花似錦璃赡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谦炒。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間熔恢,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工穿铆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留艺演,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓贱傀,卻偏偏與公主長(zhǎng)得像惨撇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子府寒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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