Pytorch學習(2)- tensor

Tensor:張量,可以是標量(一個數)、向量(一維數組)、矩陣(二維數組)或者更高維的數組。

它與numpy和ndarrays相似,但是PyTorch的tensor支持GPU加速。

一、tensor分類

  • 從接口的角度分類

        

torch.function 如torch.save()
tensor.function 如tensor.view()
  • 從存儲的角度分類
不會修改自身的數據 如a.add(b),加法的結果會返回一個新的tensor
會修改自身的數據 如a.add_(b),加法的結果仍然存儲在a中,a被修改了

二、創建Tensor

在PyTorch中新建tensor的方法有很多,具體如下:

函數 功能
Tensor(*sizes) 基礎構造函數
ones(*sizes) 全1Tensor
zeros(*sizes) 全0Tensor
eye(*sizes) 對角線爲1,其他爲0
arange(s,e,step) 從s到e,步長爲step
linspace(s,e,steps) 從s到e,均勻切分成steps份
rand/randn(*sizes) 均勻/標準分佈
normal(mean,std)/uniform(from,to) 正態分佈/均勻分佈
randperm(m) 隨機排列

三、常用Tensor操作

       通過tensor.view方法調整tensor的形狀,但必須保證調整前後元素總數一致。view不會修改自身的數據,

返回的新tensor與源tensor共享內存,即更改其中一個,另一個也隨之改變。

主要用在經常需要添加或者減少某一維度,這時就需要squeeze和unsqueeze這兩個函數。

       resize是另一種可以用來調整size的方法,但與view不同,它可以修改tensor的尺寸。如果新尺寸超過了原尺寸,會自動分配新的內存空間,但如果新尺寸小於原尺寸,則之前的數據依舊會被保存。

      Tensor支持numpy.ndarray類似的索引操作,語法也類似。如無特殊說明,索引出來的結果與原tensor共享內存。

from __future__ import print_function
import torch as t

a = t.randn(3, 4)
print(a)
print(a[0])  # 第0行(下標從0開始)
print(a[:, 0])  # 第0列

結果如下:

四、常用的選擇函數

函數 功能
index_select(input,dim,index) 在指定維度dim上選取,例如選取某些行或列
masked_select(input,mask) 例a[a>0],使用ByteTensor進行選取
non_zero(input) 非0元素的下標
gather(input,dim,index) 根據index,在dim維度上選取數據,輸出的size與index一樣

五、常見的逐元素操作

函數 功能
abs//sqrt/div/exp/fmod/log/pow 絕對值/平方根/除法/指數/求餘/求冪
cos/sin/asin/atan2/cosh 三角函數
clamp(input,min,max) 超過min和max部分截斷
ceil/round/floor/trunc 上取整/四捨五入/下取整/只保留整數部分
sigmod/tanh 激活函數

     clamp常用在某些需要比較大小的地方,如取一個tensor的每個元素與另一個數的較大值。

a = t.arange(0, 6).view(2, 3)
print(a)
# 不轉換爲float,則會報錯:RuntimeError: cos_vml_cpu not implemented for 'Long'
print(t.cos(a.float()))

      

a = t.arange(0, 6).view(2, 3)
print(a)
print(a % 3)  # 等價於t.fmod(a, 3)
print(a ** 2)  # 等價於t.pow(a, 2)

       

a = t.arange(0, 6).view(2, 3)
print(a)
# a中每個元素都與3相比,取較大的一個
print(t.clamp(a, min=3))

     

 

六、歸併操作

       歸併操作會是輸出形狀小於輸入形狀,並可以沿着某一維度進行指定操作。

常用的歸併操作:

函數 功能
mean/sum/median/mode 均值/和/中位數/衆數
norm/dist 範數/距離
std/var 標準差/方差
cumsum/cumprod 累加/累乘

以上大多數函數都有一個參數dim,用來指定這些操作是在哪個維度上執行的。

假設輸入的形狀是(m, n, k)——m行n列

輸入dim 輸出的形狀
0 (1, n, k)或者(n, k)——沿着列,變成一行
1 (m, 1, k)或者(m, k)——沿着行,變成一列
2 (m, n, 1)或者(m, n)

注意: size中是否有“1”,取決於參數keepdim,keepdim=True會保留維度1。默認爲false

七、常用的比較函數

函數 功能
gt/lt/ge/le/eq/ne 大於/小於/大於等於/小於等於/等於/不等
topk 最大的k個數
sort 排序
max/min 比較兩個tensor的最大值和最小值

max/min爲例:

t.max(tensor) 返回tensor中最大的一個數
t.max(tensor,dim) 指定維上最大的數,返回tensor和下標
t.max(tensor1,tensor2) 比較兩個tensor相比較的元素

 

 

 

 

八、常用的線性代數函數

函數 功能
trace 對角線元素之和(矩陣的跡)
diag 對角線元素
triu/tril 矩陣的上三角/下三角,可指定偏移量
mm/bmm 矩陣乘法/batch的矩陣乘法
addmm/addbmm/addmv 矩陣運算
t 轉置
dot/cross 內積/外積
inverse 求逆矩陣
svd 奇異值分解

注意:矩陣的轉置會導致存儲空間不連續,需調用它的.contiguous方法將其轉爲連續

a = t.ones(2, 3)
print(a)
# 求a的轉置
b = a.t()
# 查看a的轉置矩陣b是否連續
print(b.is_contiguous())
# 將其轉爲連續
print(b.contiguous())

結果:

             

九、對於Tensor和Numpy之間遇到的問題

需要注意的是:Numpy和Tensor共享內存。PyTorch已經支持了自動廣播法則。

當遇到Tensor不支持的操作時,可以先轉成Numpy數組,處理後再轉爲tensor,其轉換開銷很小。

  • 當輸入數組的某個維度的長度爲1時,計算時沿此維度複製擴充成一樣的形狀。
  • unsqueeze或view:爲數據某一維的形狀補1,實現法則1.
  • expand或expand_as,重複數組,實現法則3;該操作不會複製數組,所以不會佔用額外的空間

     9.1、持久化

          tensor的保存:t.save

          tensor的加載:t.load

在load時還可以將GPU tensor映射到CPU或其他GPU上。

if t.cuda.is_available():
    a = a.cuda(1)  # 把a轉爲GPU1上的tensor
    t.save(a, 'a.path')
    # 加載爲b,存儲於GPU1上(因爲保存時tensor就在GPU1上)
    b = t.load('a.path')
    # 加載爲c,存儲於CPU
    c = t.load('a.path', map_location=lambda storage, loc: storage)
    # 加載爲d,存儲於GPU0上
    d = t.load('a.path', map_location={'cuda:1':'cuda: 0'})

    9.2、向量化

           向量化計算是一種特殊的並行計算方式,一般程序在同一時間只執行一個操作的方式,它可以在同一時間執行多個操作,通常是對不同的數據執行同樣的一個或一批指令,或者說把指令應用於一個數組/向量上。向量化可極大地提高科學運算的效率。

在科學計算程序中應當極力避免使用Python原生的for循環,儘量使用向量化的數值計算。

           還需要注意:

  • 大多數t.function都有一個參數out,這時產生的結果將保存在out指定的tensor之中
a = t.arange(0, 20000000)
b = t.LongTensor()
t.arange(0, 20000000, out=b)  # 64bit的LongTensor不會溢出
  • t.set_num_threads可以設置PyTorch進行CPU多線程並行計算時所佔用的線程數,用來限制PyTorch所佔用的CPU數目。
  • t.set_printoptions可以用來設置打印tensor時的數值精度和格式。

十、View的用法

a=torch.Tensor([[[1,2,3],[4,5,6]]])
b=torch.Tensor([1,2,3,4,5,6])

print(a.view(1,6))
print(b.view(1,6))

輸出結果:tensor([[1., 2., 3., 4., 5., 6.]]) 
          tensor([[1., 2., 3., 4., 5., 6.]]) 
# -------------------------------------------------------
a=torch.Tensor([[[1,2,3],[4,5,6]]])
print(a.view(3,2))
輸出結果:
tensor([[1., 2.],
        [3., 4.],
        [5., 6.]])
相當於就是從1,2,3,4,5,6順序的拿數組來填充需要的形狀
# --------------------------------------------------------
但是如果你想得到:
tensor([[1., 4.],
        [2., 5.],
        [3., 6.]])

就需要用到permute()
# -------------------------------------------------------
另外,參數不可爲空。
參數中的-1就代表這個位置由其他位置的數字來推斷,只要在不致歧義的情況的下,view參數就可以推斷出來,也就是人可以推斷出形狀的情況下,view函數也可以推斷出來。
比如a tensor的數據個數是6個,如果view(1,-1),我們就可以根據tensor的元素個數推斷出-1代表6。而如果是view(-1,-1,2),人不知道怎麼推斷,機器也不知道。
還有一種情況是人可以推斷出來,但是機器推斷不出來的:view(-1,-1,6),人可以知道-1都代表1,但是機器不允許同時有兩個負1。

如果沒有-1,那麼所有參數的乘積就要和tensor中元素的總個數一致了,否則就會出現錯誤。

十一、sequeeze和unsqueeze

 簡介和用法

squeezeunsqueeze的作用與其翻譯基本一致,被作用維度壓縮和解壓縮.用法相對簡單,具體如下:

tensor_unsqueeze = tensor.unsqueeze(dim)

tensor存在n個維度,則dim的取值爲[-n+1,n]區間的整數,且dim的取值不能爲空.

tensor_squeeze = tensor.squeeze(dim)

tensor存在n個維度,則dim的取值爲[-n,n-1]區間的整數,但dim的值可以爲空

具體示例:

首先看unsqueeze,其中的參數dim不能爲空。

f = torch.arange(0, 6).view(3, 2)
print(f, f.size())
# 參數表示在哪一維的前面增加一個維度
print(f.unsqueeze(0), f.unsqueeze(0).size())  # 1×3×2
print(f.unsqueeze(1), f.unsqueeze(1).size())  # 3×1×2
print(f.unsqueeze(2), f.unsqueeze(2).size())  # 3×2×1
# --------------------------------------------------
tensor([[0, 1],
        [2, 3],
        [4, 5]]) torch.Size([3, 2])

tensor([[[0, 1],
         [2, 3],
         [4, 5]]]) torch.Size([1, 3, 2])

tensor([[[0, 1]],

        [[2, 3]],

        [[4, 5]]]) torch.Size([3, 1, 2])

tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

再看squeeze,它是將被操作目標中維度爲1的部分去除。

其中dim表示需要在哪一維去掉一個維度,如果不指定則自動尋找,如果指定則當指定的維度爲1時去掉,如果不爲1則不改變。

f = torch.arange(0, 6).view(3, 2, 1)
print(f, f.size())  # 3*2*1
print(f.squeeze(0), f.squeeze(0).size())  # 3*2*1,維度爲3,不能去掉,所以不變
print(f.squeeze(1), f.squeeze(1).size())  # 3*2*1,維度爲2,不能去掉,所有不變
print(f.squeeze(2), f.squeeze(2).size())  # 3*2  ,維度爲1,可以去掉,所有改變
print(f.squeeze(), f.squeeze().size())    # 如果無參數,則自動尋找,找到則刪除。
# -------------------------------------------------------------------------------
tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

tensor([[0, 1],
        [2, 3],
        [4, 5]]) torch.Size([3, 2])

tensor([[0, 1],
        [2, 3],
        [4, 5]]) torch.Size([3, 2])

 

十二、cat的用法

cat是用於將兩個矩陣進行拼接,0表示按行拼接,1表示按列拼接

a = torch.ones(2, 3)
b = 2 * torch.ones(4, 3)
c = 4 * torch.ones(2, 4)
print(a)
print(b)
print(c)
d = torch.cat((a, b), 0)  # 0表示按行拼接
e = torch.cat((a, c), 1)  # 1表示按列拼接
print(d)
print(e)
# -----------------------------------------------
tensor([[1., 1., 1.],
        [1., 1., 1.]])

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

tensor([[4., 4., 4., 4.],
        [4., 4., 4., 4.]])

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

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

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章