【pytorch】pytorch學習筆記(一)

原文地址:https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.htmlhtml

 什麼是pytorch?python

  pytorch是一個基於python語言的的科學計算包,主要分爲兩種受衆:數組

  • 可以使用GPU運算取代NumPy
  • 提供最大靈活度和速度的深度學習研究平臺

開始網絡

Tensors框架

  Tensors與numpy的ndarray類似,且Tensors能使用GPU進行加速計算。dom

  

  建立5 * 3的未初始化矩陣:ide

  

  建立並隨機初始化矩陣:函數

  

  建立一個類型爲long且值全爲0的矩陣:oop

  

  直接賦值建立tensor:學習

  

  使用已有的tensor建立一個tensor,這個方法能使用已有tensor的屬性如類型:

  new_* 方法的參數是張量形狀大小

  

  重寫類型,結果具備相同的形狀大小

  

  獲取張量的尺寸大小:

  

  注:torch.Size其實是一個元組,因此它支持全部的元組操做。

Operations(運算)

  pytorch有多種運算的語法。在下列例子中,咱們看一下加法運算:

  加法1

  

  加法2:

  

  加法:提供一個輸出tensor做爲參數

  

  加法:in-place ( 至關於+= ,將結果直接賦值到左側的變量)

  

  注:任何方法名中使用「_」的都是in-place操做,好比x.copy_(y),x.t_(),都會使x的值發生改變。

  同時,你也可使用標準NumPy風格的索引操做:

  

  Resizing:若是你想要resize或reshape一個張量,可使用方法 torch.view :

  

  若是張量只有一個元素,可使用.item()來獲取一個python數值

  

NumPy Bridge

  Torch的張量和NumPy數組的相互轉換,他們共享底層的內存位置,更改一個另外一個也會改變。

  張量轉換爲NumPy數組

  

  當張量的值改變時,numpy數組的值也同時改變:

  

  Numpy數組轉換爲張量

  

  除了字符張量,全部在CPU上的張量都能與NumPy數組相互轉換。

CUDA Tensors

  張量可以被轉移到任何設備經過使用 .to 方法。

  

AUTOGRAD: AUTOMATIC DIFFERENTIATION

  autograd包在pytorch中是全部神經網絡的核心,咱們先看一下而後將會訓練本身的神經網絡。

  autograd包給全部張量運算提供了自動微分。他是一個運行定義框架(define-by-run framework),意爲着被你的代碼如何運行所定義,每次的單個迭代都是不一樣的。

  讓咱們用簡單的術語和一些例子來看下:

Tensor

  torch.Tensor是核心類。若是你設置了它的屬性 .requires_grad爲True, 它就開始跟蹤全部的運算。當完成全部的計算能夠經過 .backward() 而後就能夠自動進行全部的梯度計算。該張量的全部梯度將會累加到.grad() 屬性。

  經過調用 .detach() 方法能夠中止一個張量對計算記錄的追蹤。

  另外一種阻止張量計算追蹤的方法是,將代碼塊寫入 with torch.no_grad(): ,這在訓練中評價測試一個模型的時候尤爲有用,由於咱們設置了requires_grad =True,而此時並不須要梯度。

  自動微分的另外一個重要實現是類Function。

  Tensor和Function是相互聯繫的並創建了一個非循環圖,記錄了計算的完整歷史。每一個張量有.grad_fn屬性,這個屬性與建立張量的Function相關聯(除了用戶本身建立張量,該屬性grad_fn is None)

  若是你想要計算導數,你能夠調用張量的.backward()方法,若是張量是一個標量,如只有一個元素的數據,則backward()不須要指定任何參數;若是其有更多參數,則須要指定一個具備匹配張量大小的gradient參數。

  建立一個張量並設置 requires_grad = True來追蹤計算:

  

  張量運算:

  

  y是做爲運算的結果所建立的,因此它有屬性 grad_fn。

  

  y的更多運算:

  

  .require_grad_()方法能夠改變張量requires_grad的值,若是沒指定的話,默認值爲False。

  

  

Gradients

  開始反向傳播。由於 out 包含一個單一的標量,out.backward() 至關於 out.backward((torch.tensor(1.))) 。  

  打印梯度d(out)/dx:

x = [ [1, 1], [1, 1] ]

y = x + 2

 z =  y * y * 3

out = z.mean

d(out)/dx = 3/2(x + 2)

 

  

  

  

  當.requires_grad=True 時,你也能夠經過寫入代碼塊with torch.no_grad()中止追蹤歷史和自動微分:

  

NEURAL NETWORKS

  torch.nn能夠建立神經網絡,nn依賴於 autograd 來定義模型和微分。nn.Moudle包括各類層和返回output的方法forward(input)。

  例如,如下爲對數字圖片進行分類的網絡:

  

  一個簡單的前饋網絡,得到輸入並通過一個個網絡層,最終獲得輸出。

  如下是一個神經網絡的訓練步驟:

  • 定義一個具備可學習參數或權重的神經網絡;
  • 對一個數據集的輸入進行迭代;
  • 經過網絡處理輸入;
  • 計算損失
  • 將梯度反向傳播給網絡參數
  • 更新網絡參數,一般的更新方法爲 weight weight learning_rategradien

Define the network

#encoding:utf-8
import torch
import torch.nn as nn
import torch.nn.functional as F
 
class Net(nn.Module):
 
    def __init__(self):
        super(Net,self).__init__()
        #定義2個卷積層
        self.conv1=nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5)
        self.conv2=nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5)
        #定義了3個線性層,即y=wx+b
        self.fc1=nn.Linear(in_features=16*5*5,out_features=120)
        self.fc2=nn.Linear(120,84)
        self.fc3=nn.Linear(84,10)
 
    def forward(self, x):
        #在第一層卷積網絡和第二層之間增長了relu激活函數和池化層
        x=F.max_pool2d(input=F.relu(input=self.conv1(x)),kernel_size=(2,2))
        #若是池化層是方塊形的能夠用一個number指定
        x=F.max_pool2d(input=F.relu(input=self.conv2(x)),kernel_size=2)
        x=x.view(-1,self.num_flat_features(x))
        x=F.relu(input=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:]#切片0裏面放的是當前訓練batch的number,不是特徵信息
        num_features=1
        for s in size:
            num_features*=s
        return num_features
net=Net()
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(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)

  你只要定義前向函數,當你使用 autograd 時,後向傳播函數將會自動定義。在前向函數中你可使用任何張量運算。

  模型的可學習參數由 net.parameters() 返回。

params = list(net.parameters())
print(len(params))
print(params[0].size())  # conv1's .weight

  這個網絡適合32*32的數據集(1*32*32通過一個核心爲5的卷積層,大小變爲6*28*28;通過一個核心爲2的池化層,大小變爲6*14*14;再通過一個核心爲5的卷積層,大小變爲16*10*10;池化層,16*5*5,正好是下一個線性層的輸入特徵數),咱們隨機一個輸入數據集,運行一下咱們的模型吧:

input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
tensor([[-8.2934e-03, -1.9684e-02, -7.6836e-02,  5.3187e-02,  1.1083e-01,
         -2.5156e-02, -6.1870e-05, -8.3843e-03,  4.1401e-02, -5.8330e-02]],
       grad_fn=<AddmmBackward>)

  將全部參數的梯度設爲0,使用隨機梯度進行反向傳播:

net.zero_grad()
out.backward(torch.randn(1, 10))

  注:torch.nn只支持批量數據的處理,而不是單個樣本。例如,nn.Conv2d 將會使用 4D張量,nSamples nChannels Height Width,若是隻有單個樣本,可使用input.unsqueeze(0)來增長一個假的batch維度。

  回顧下剛學到的幾個類:

  • torch.Tensor- 多維數組並支持自動微分運算如backward()
  • nn.Moudle-神經網絡模型,幫助咱們封裝參數,移植到GPU,導出和加載等
  • nn.Parameter-張量,當你給Module定義屬性時,參數會自動生成
  • autograd.Function-實現前向和反向定義的自動微分運算。每一個張量運算至少建立一個Function結點,來鏈接建立張量和記錄歷史的函數

Loss Function

  損失函數計算輸出和目標之間的值,來衡量二者的差距。在nn中有多種不一樣的損失函數,一個簡單的損失函數是:nn.MSELoss,它返回的是均方差,即每個份量相減的平方累計最後除份量的個數。

output = net(input)
target = torch.randn(10)  # a dummy target, for example
target = target.view(1, -1)  # make it the same shape as output
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)
tensor(0.9531, grad_fn=<MseLossBackward>)

  若是你沿着loss反向傳播的方向,用.grad_fn屬性能夠看到計算圖:

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
      -> view -> linear -> relu -> linear -> relu -> linear
      -> MSELoss
      -> loss

  因此,當你調用loss.backward()時,在整個計算圖都會進行微分,全部requires_grad=True的張量的.grad屬性都會累加。

  爲了說明,打印以下少數幾步的反向傳播:

print(loss.grad_fn)  # MSELoss
print(loss.grad_fn.next_functions[0][0])  # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU
<MseLossBackward object at 0x7f6e48d5ee48>
<AddmmBackward object at 0x7f6e48d5eac8>
<AccumulateGrad object at 0x7f6e48d5eac8>

Backprop

  爲了反向傳播偏差咱們須要作的只要使用 loss.backward() ,同時也須要清除已有的梯度,不然梯度會累加到已經存在的梯度。

  調用 loss.backward() ,觀察conv1 層bias的梯度反向傳播先後的變化  

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

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)
conv1.bias.grad before backward
tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward
tensor([-0.0022,  0.0022, -0.0139,  0.0072,  0.0029,  0.0035])

   如今咱們已經知道了如何使用損失函數。

Update the weights

  在實際中使用的最簡單的更新規則是隨即梯度降低SGD:

weight = weight - learning_rate * gradient

  咱們能夠簡單地使用python代碼進行實現:

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

  若是須要使用其餘的更新規則,好比SGD,Nesterov-SGD, Adam, RMSProp等等,pytorch也提供了相關的包:torch.optim ,實現了這些方法。

  使用實例:

import torch.optim as optim

# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)

# in your training loop:
optimizer.zero_grad()   # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()    # Does the update

  注:代碼中咱們手動將梯度設置爲0,optimizer.zero_grad(),這是由於梯度不置0的話將會累加之前的值,在反向傳播那一節咱們也提到過。

TRAINING A CLASSIFIER

  咱們已經知道了如何定義網絡,計算損失和更新網絡權重,那咱們將會思考,那數據呢?

  一般來說,當你處理圖片,文本,語音和視頻數據,可使用標準的python包來加載數據爲numpy數組,而後轉換爲張量torch.*Tensor。

  • 圖片,一般可使用Pillow, OpenCV
  • 語音,使用scipy 和 librosa
  • 文本,純python或Cython,也可使用NLTK和SpaCy

  對於視覺,咱們專門建立了一個名爲 torchvision 的包,其擁有加載普通數據集(Imagenet, CIFAR10, MNIST)的加載器和圖片數據轉換器,即torchvision.datasets 和 torch.utils.data.DataLoader。

  在本教程中,咱們將使用CIFAR10數據集。它有10個類別:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’. CIFAR10中的圖像的大小爲3*32*32,即大小爲32*32的有3個通道的彩色圖像。  

Training an image classifier

  接下來咱們要作一步步完成如下內容:

  1. 使用torchvision加載和歸一化CIFAR10的訓練和測試數據集
  2. 定義一個卷積神經網絡
  3. 定義一個損失函數
  4. 在訓練數據上訓練數據
  5. 在測試集上測試網絡

1. Loading and normalizing CIFAR10

import torch
import torchvision
import torchvision.transforms as transforms

  torchvision數據集的輸出是在[0,1]範圍的]PILImage,咱們將其轉化爲歸一化範圍[-1, 1]的張量。

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')
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
Files already downloaded and verified

   使用matplotlib庫查看訓練數據:

import matplotlib.pyplot as plt
import numpy as np

# functions to show an image


def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()

# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

frog  bird truck  ship

2. Define a Convolutional Neural Network

  複製神經網絡那一節的代碼,而後將輸入圖像的通道改成3個,

import torch.nn as nn
import torch.nn.functional as F
 
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.conv1=nn.Conv2d(3,6,5)
        self.pool=nn.MaxPool2d(kernel_size=2,stride=2)
        self.conv2=nn.Conv2d(6,16,5)
        self.fc1=nn.Linear(16*5*5,120)
        self.fc2=nn.Linear(in_features=120,out_features=84)
        self.fc3 = nn.Linear(in_features=84, out_features=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()
print(net)
Net(
  (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
  (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
) 

3. Define a Loss function and optimizer

   使用分類的交叉熵損失函數和帶動量的隨機梯度降低。

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

4. Train the network  

for epoch in range(2):#循環整個數據集多少遍
 
    running_loss=0.0
    for i,data in enumerate(trainloader,start=0):
        #get the inputs
        inputs, labels = data
 
        # 梯度清0
        optimizer.zero_grad()
 
        #forward + backword + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
 
        #打印統計信息
        running_loss += loss.item()
        if i % 2000 == 1999: #每2000個mini-batches打印一次
            print("[%d, %d] loss: %.3f" %
                  (epoch+1, i+1, running_loss/2000))
            running_loss=0.0
print('Finished Training')
相關文章
相關標籤/搜索