Pytorch 入門系列(一)

前言

本文旨在介紹Pytorch的入門知識。在第一部分,我們簡單介紹了當前的主流深度學習框架,并介紹了選擇Pytorch的理由及其安裝方法。在第二部分,我們給出了Pytorch的一個簡單入門,包括張量的使用,如何借助Cuda在Pytorch中使用GPU進行計算,以及Pytorch中的求導(dǎo)運算等。最后在第三部分,我們對文中講到的關(guān)鍵操作進行了總結(jié)。

1. 深度學習框架的簡單介紹

1.1 主流深度學習框架

PyTorch是一個基于Python的庫,用來提供一個具有靈活性的深度學習開發(fā)平臺。PyTorch的工作流程非常接近Python的科學計算庫numpy。

當前主流的深度學習框架有兩種,一種是以Tensorflow為代表的靜態(tài)圖框架,另一種就是以Pytorch為代表的動態(tài)圖框架。靜態(tài)圖框架要求我們先定義好模型結(jié)構(gòu)再運行模型,而動態(tài)圖框架意味著程序?qū)凑彰铐樞驁?zhí)行,這種機制使得我們調(diào)試更加容易。用編程語言做類比,Tensorflow更像C++,而Pytorch更像Python。

Pytorch在近年來發(fā)展迅速,下圖對比了Pytorch和Tensorflow在論文中的使用情況:

從圖中可以看到,2019年1月到6月底,在arXiv.org上發(fā)表的論文中,提及TensorFlow和PyTorch的數(shù)量相差無幾,PyTorch僅稍稍落后。但最關(guān)鍵的在于增長速度:與2018年1月到6月相比,PyTorch增長了194%,相比之下,TensorFlow的增長幅度僅為23%。從當前的數(shù)據(jù)可以看出,Pytorch因其簡單易用而越來越受到大家的青睞。

1.2 為什么選擇Pytorch

首先不得不提Tensorflow的反人類設(shè)計。Tensorflow的邏輯有兩種,一種是建graph時的邏輯,另一種是運行時的邏輯。當要實現(xiàn)的算法比較復(fù)雜的時候就會很麻煩,一不小心就會出錯。

其次,Pytorch可以和Python無縫銜接,學習成本很低,給人的直觀感受就是用著順手、舒服。

最后,Pytorch代碼簡潔易懂。因此,作為深度學習的入門工具來說,Pytorch再合適不過了。

1.3 Pytorch 的安裝

Pytorch 安裝起來十分簡單,只要三步即可完成,

(1) 進入 Pytorch 官網(wǎng)

(2) 選擇合適的操作系統(tǒng)和版本</br>

在YourOs一欄選擇你的操作系統(tǒng)。在CUDA一欄是選擇是否安裝GPU版本,如果要安裝GPU版本,首先要安裝上CUDA,然后選擇CUDA的版本。

(3) 拷貝 Run this Command 一欄中的命令

將命令拷貝到終端執(zhí)行,即可自動安裝。

2. Pytorch 的簡單入門

2.1 張量的概念

簡單的說,張量概念是矢量概念和矩陣概念的推廣。標量是零階張量,矢量是一階張量,矩陣(方陣)是二階張量,而三階張量則好比是立體矩陣,更高階的張量用圖形無法表達。機器學習中的數(shù)據(jù)往往以張量形式表達。

2.2 張量的創(chuàng)建

Pytorch 中張量的創(chuàng)建主要有以下幾種形式:

(1) torch.empty 函數(shù)

import torch

x = torch.empty(5,3) #創(chuàng)建一個5*3的矩陣
print(x)
y = torch.empty(2,2,2) #創(chuàng)建一個2*2*2的張量
print(y)

輸出:

tensor([[1.1210e-44, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00]])

tensor([[[8.4078e-45, 0.0000e+00],
         [1.2708e-31, 1.4013e-45]],

        [[0.0000e+00, 0.0000e+00],
         [0.0000e+00, 0.0000e+00]]])

empty函數(shù)返回填充有未初始化數(shù)據(jù)的張量,在我們不需要初始化具有特定分布的數(shù)據(jù)時可以使用。

(2) torch.rand 函數(shù)

x = torch.rand(5,3) #創(chuàng)建一個5*3的矩陣
print(x)
y = torch.rand(2,2,2) #創(chuàng)建一個2*2*2的張量
print(y)

輸出:

tensor([[0.1413, 0.5294, 0.6538],
        [0.4040, 0.0293, 0.7876],
        [0.8263, 0.2070, 0.5927],
        [0.4749, 0.7163, 0.4874],
        [0.2791, 0.3276, 0.1504]])

tensor([[[0.2636, 0.9148],
         [0.9117, 0.9742]],

        [[0.4946, 0.6069],
         [0.5841, 0.6050]]])

torch.rand 建立一個張量,默認將數(shù)據(jù)初始化為[0,1)的均勻分布。類似的函數(shù)有 torch.randn 將數(shù)據(jù)初始化為均值為0,方差為1的標準正態(tài)分布;torch.normal 可以生成指定均值和方差的正態(tài)分布。

(3) torch.ones 函數(shù)

x = torch.ones(5,3)
print(x)

輸出:

tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])

torch.ones 建立一個張量,并將值初始化為1。

(4) torch.zeros 函數(shù)

x = torch.zeros(5,3)
print(x)

輸出:

tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])

torch.zeros 建立一個張量,并將矩陣值初始化為0。

(5) 直接從數(shù)組建立一個張量

x = torch.tensor([2,3,4,5])
print(x)

輸出:

tensor([2, 3, 4, 5])

(6) new_ones,new_zeros,new_empty

x = torch.zeros(2,3,dtype=torch.int32) #新建一個張量
print(x)
y = x.new_ones(1,2)      #從x中創(chuàng)建一個新的張量,數(shù)據(jù)類型不變
print(y)

輸出:

tensor([[0, 0, 0],
        [0, 0, 0]], dtype=torch.int32)
        
tensor([[1, 1]], dtype=torch.int32)

這些函數(shù)可以從已有張量建立一個新的張量。

(7) ones_like,zeros_like,empty_like

x = torch.ones(4,4)
print(x)
y = torch.rand_like(x)
print(y)

輸出:

tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])

tensor([[0.5023, 0.7911, 0.3639, 0.3315],
        [0.8617, 0.0388, 0.1612, 0.2071],
        [0.1755, 0.3988, 0.8381, 0.5835],
        [0.9588, 0.3950, 0.8371, 0.5337]])

這些函數(shù)可以創(chuàng)建一個和目標張量形狀相同的張量。

2.3 張量的運算

張量常用的計算操作主要有張量的加法,張量乘法,張量形狀改變。

(1) 張量加法

主要有三種方式:

  • x+y
  • torch.add(x,y,out=result)
  • y.add_(x)是將x增加到y(tǒng)上并改變y的值,運算符加“_”是將運算結(jié)果賦值給左邊的變量。
y = torch.rand(3,5)
x = torch.ones(5)
result = torch.empty(3,5) 
print(x+y) #第一種方式
print(torch.add(x,y,out=result)) #第二種方式
y.add_(x) #第三種方式
print(y)

輸出:

tensor([[1.8442, 1.9501, 1.8182, 1.0880, 1.7674],
        [1.5743, 1.5252, 1.8656, 1.2426, 1.4136],
        [1.9056, 1.3625, 1.8482, 1.6156, 1.7287]])

tensor([[1.8442, 1.9501, 1.8182, 1.0880, 1.7674],
        [1.5743, 1.5252, 1.8656, 1.2426, 1.4136],
        [1.9056, 1.3625, 1.8482, 1.6156, 1.7287]])

tensor([[1.8442, 1.9501, 1.8182, 1.0880, 1.7674],
        [1.5743, 1.5252, 1.8656, 1.2426, 1.4136],
        [1.9056, 1.3625, 1.8482, 1.6156, 1.7287]])

(2) 張量乘法

  • mm 只能是矩陣乘法,也就是輸入的兩個tensor維度只能是(n,m)和(m,p)
  • bmm 是兩個三維張量相乘,兩個tensor維度是(b,m,p)和(b,p,n),b一般是batch_size
  • matmul 可以進行張量乘法,輸入可以是高維的

mm 操作示例:

x = torch.ones(3,2)
y = torch.ones(2,3)
x.mm(y)

輸出:

tensor([[2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.]])

bmm 操作示例:

x = torch.ones(2,3,2)
y = torch.ones(2,2,3)
x.bmm(y)

輸出:

tensor([[[2., 2., 2.],
         [2., 2., 2.],
         [2., 2., 2.]],

        [[2., 2., 2.],
         [2., 2., 2.],
         [2., 2., 2.]]])

(3) Resize 操作

view函數(shù)實現(xiàn)了torch中張量的Resize操作。

x = torch.rand(2,2)
y = x.view(-1) # 從x生成一維向量,長度自動計算
print(y)
z = y.view(2,-1) #從y生成行數(shù)為2的矩陣,列的長度自動計算
print(z)

輸出:

tensor([[0.2995, 0.2133],
        [0.6413, 0.7581]])

tensor([0.2995, 0.2133, 0.6413, 0.7581])

tensor([[0.2995, 0.2133],
        [0.6413, 0.7581]])

Resize操作在很多時候都有用,例如我們進行圖像識別時,卷積層是n個方陣,要將卷積核輸出為類別,通常是先將它們展成一維,再帶入softmax函數(shù)計算進行分類。

(4) 轉(zhuǎn)置操作 t.()

x = torch.empty(3,4)
print(x)
print(x.t())

輸出:

tensor([[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]])

tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])

2.4 Pytorch 中張量和 NumPy Array 的相互轉(zhuǎn)化

在Torch Tensor和NumPy array之間相互轉(zhuǎn)化非常容易。Torch Tensor和NumPy array共享內(nèi)存,所以改變其中一項也會改變另一項。

把Torch Tensor轉(zhuǎn)變成NumPy Array:

a = torch.ones(5)
print(a)
b = a.numpy()
print(b)

輸出:

tensor([1., 1., 1., 1., 1.])

[1. 1. 1. 1. 1.]

把上面的a增加1:

a.add_(1)
print(a)
print(b)

輸出:

tensor([2., 2., 2., 2., 2.])

[2. 2. 2. 2. 2.]

把NumPy Array轉(zhuǎn)變成Torch Tensor:

import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
print(a)
print(b)
np.add(a,1,out=a)
print(a)
print(b)

輸出:

[1. 1. 1. 1. 1.]

tensor([1., 1., 1., 1., 1.], dtype=torch.float64)

[2. 2. 2. 2. 2.]

tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

2.5 Pytorch 中使用GPU計算

在Pytorch 中,使用GPU計算是很方便的,可以在創(chuàng)建張量的時候指定張量計算位置,也可以將張量轉(zhuǎn)移到GPU上計算。

if torch.cuda.is_available():
    device = torch.device("cuda")
    y = torch.ones(2,3,device=device) #在GPU上創(chuàng)建張量
    x = torch.empty(4,5) 
    x.to(device) #將張量x轉(zhuǎn)移到GPU上
    z = x+y

2.6 Pytorch 中的求導(dǎo)運算

我們在進行模型訓(xùn)練的時候,常常需要用梯度下降法,所以求導(dǎo)是很重要的,在Pytorch中,求導(dǎo)非常方便。例如對Y = WX + B,我們計算Y關(guān)于W和B的導(dǎo)數(shù)。不難發(fā)現(xiàn),Y關(guān)于W的導(dǎo)數(shù)是X的轉(zhuǎn)置,Y關(guān)于B的導(dǎo)數(shù)是1。

操作示例:

w = torch.zeros((3,1),requires_grad=True) # 聲明W的形狀,以及可導(dǎo)性(默認不可導(dǎo))
x = torch.ones(1,3) # 聲明X形狀
b = torch.tensor([1.],requires_grad=True)
y = x.mm(w) + b     # Y = wx + b
y.backward()       # 求導(dǎo)操作
print(w.grad)
print(b.grad)

輸出:

tensor([[1.],
        [1.],
        [1.]])
        
tensor([1.])

3. 總結(jié)

本文我們簡單介紹了Pytorch基本知識,包括安裝方法,基本的張量操作。張量操作我們主要說明了Pytorch中張量的幾種創(chuàng)建方法,張量的運算。然后我們學習了如何在GPU上進行計算,最后我們介紹了Pytorch上的求導(dǎo)操作。

最后,要記住以下重要操作哦:

  1. 張量創(chuàng)建
    • torch.ones(), torch.empty(), torch.zeros()
    • x.new_ones(), x.new_rand()..
    • torch.empty_like(),torch.zeros_like()
  2. 張量操作
    • 加法 torch.add(x,y,result=z),add_(),"+"
    • 乘法 mm(),bmm(),matmul()
    • 和numpy的相互轉(zhuǎn)化 a.numpy(), torch.from_numpy()
  3. GPU計算
    • 記住函數(shù) torch.cuda.is_available(),
    • torch.device("cuda")
    • to(device)
  4. 求導(dǎo)運算
    • 記得在創(chuàng)建張量時加一個requires_grad=True
    • loss.backward()函數(shù)
    • 導(dǎo)數(shù)在W.grad中取得

下期我們將以房價預(yù)測為例,來搭建一個簡單的線性模型!

最后編輯于
?著作權(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)容