TORCH01-02:Tensor的基本屬性

本主題主要說(shuō)明Tensor的屬性及其使用;這些屬性的設(shè)置,影響著數(shù)據(jù)的使用;Tensor最大的好處就是提供了計(jì)算跟蹤,這個(gè)跟蹤用來(lái)提供動(dòng)態(tài)圖的構(gòu)建,這個(gè)與Tensorflow的靜態(tài)圖是不同滴。同時(shí)還提供了導(dǎo)數(shù)的逆向計(jì)算,這是目前神經(jīng)網(wǎng)絡(luò)中最成功的網(wǎng)絡(luò)思想:前饋神經(jīng)網(wǎng)絡(luò)的實(shí)現(xiàn)基礎(chǔ)(梯度下降算法);


回顧

  • 因?yàn)門orch的核心是Tensor,Tensor的數(shù)據(jù)由Storage管理,所以這兩個(gè)類的關(guān)系搞清楚,就可以使用Tensor了。

Tensor的Python構(gòu)造器定義如下

    Tensor.__init__(torch.device device)
    Tensor.__init__(torch.Storage storage)
    Tensor.__init__(Tensor other)
    Tensor.__init__(tuple of ints size, torch.device device)
    Tensor.__init__(object data, torch.device device)

Storage的Python構(gòu)造器定義如下

    FloatStorage.__init__() no arguments
    FloatStorage.__init__(int size)
    FloatStorage.__init__(Sequence data)
    FloatStorage.__init__(torch.FloatStorage view_source)
    FloatStorage.__init__(torch.FloatStorage view_source, int offset)
    FloatStorage.__init__(torch.FloatStorage view_source, int offset, int size)

關(guān)于Tensor

Tensor與Numpy

  • 實(shí)際上按照Python一貫的思路,會(huì)提供很多函數(shù)來(lái)替代構(gòu)造器的使用,這樣做有兩個(gè)原因:

    • 個(gè)性化,方便,簡(jiǎn)單;
    • 使用工廠模式來(lái)創(chuàng)建對(duì)象,符合軟件的常見(jiàn)設(shè)計(jì)模式,Python大量采用;
      • 今后不要?jiǎng)硬粍?dòng)就說(shuō)面向?qū)ο笞詈?,最方便。最直觀,最方便的還是函數(shù),拿來(lái)就用,不需要構(gòu)建對(duì)象才能使用。
  • Torch號(hào)稱是GPU版本的Numpy,Numpy有的Tensor都有,所以按照Numpy的思路,在構(gòu)建好對(duì)象后,有三大塊功能是需要數(shù)理下的,掌握這三大基礎(chǔ)功能,后面的內(nèi)容就容易理解:

    1. 基本屬性
      • 了解對(duì)象的內(nèi)存與數(shù)據(jù)結(jié)構(gòu)
    2. 基本操作
      • 數(shù)據(jù)進(jìn)出
    3. 數(shù)學(xué)運(yùn)算
      • 構(gòu)建數(shù)據(jù)對(duì)象的最終目的就是計(jì)算;
        • 計(jì)算的類別很多,基本數(shù)學(xué)運(yùn)算,隨機(jī)采樣,線性代數(shù)的矩陣運(yùn)算,統(tǒng)計(jì)計(jì)算,......
        • 這里先明白基本的數(shù)學(xué)運(yùn)算。

Tensor的官方文檔結(jié)構(gòu)

torch
        Tensors
                Creation Ops
                Indexing, Slicing, Joining, Mutating Ops
                Generators
        Random sampling
                In-place random sampling
                Quasi-random sampling
                Serialization
                Parallelism
                Locally disabling gradient computation
        Math operations
                Pointwise Ops
                Reduction Ops
                Comparison Ops
                Spectral Ops
                Other Operations
                BLAS and LAPACK Operations
        Utilities
  • 這里先搞定Tensor本身的基本屬性與操作
    • 基本屬性(從C/C++文檔對(duì)應(yīng))
    • 基本操作
      • Indexing(索引訪問(wèn)操作)
      • Slicing (切片訪問(wèn)操作【是索引的批量級(jí)升級(jí)版本】)
      • Joining(數(shù)據(jù)組合與合并)
      • Mutating Ops(數(shù)據(jù)訪問(wèn):索引與切片的函數(shù)版本)
    • 數(shù)學(xué)運(yùn)算:
      • Pointwise Ops(元素運(yùn)算)
      • Reduction Ops(降維運(yùn)算)
      • Comparison Ops(比較運(yùn)算)
      • Spectral Ops(譜運(yùn)算)
      • Other Operations(其他運(yùn)算)
      • BLAS and LAPACK Operations(線性代數(shù)運(yùn)算)
        1. BLAS
          • Basic Linear Algebra Subprograms(Fortran語(yǔ)言編寫,F(xiàn)ortran史上經(jīng)典古老的數(shù)學(xué)計(jì)算語(yǔ)言);
        2. LAPACK
          • Linear Algebra Package,底層使用的也是BLAS;
        3. ATLAS
          • Automatically Tuned Linear Algebra Software;
        4. OpenBLAS:
          • 在編譯時(shí)根據(jù)目標(biāo)硬件進(jìn)行優(yōu)化,生成運(yùn)行效率很高的程序或者庫(kù)。OpenBLAS的優(yōu)化是在編譯時(shí)進(jìn)行的,所以其運(yùn)行效率一般比ATLAS要高。因此OpenBLAS對(duì)硬件的依賴比較高,換一個(gè)硬件平臺(tái)可能會(huì)重新進(jìn)行編譯。
        5. cuBLAS與ACML:
          • Intel的MKL和AMD的ACML都是在BLAS的基礎(chǔ)上,針對(duì)自己特定的CPU平臺(tái)進(jìn)行針對(duì)性的優(yōu)化加速。以及NVIDIA針對(duì)GPU開(kāi)發(fā)的cuBLAS。

Tensor的基本屬性與屬性函數(shù)

  • 先構(gòu)建一個(gè)張量(Tensor)使用;
import torch

t_vector = torch.LongTensor(
    data= [1, 2, 3, 4, 5]
)
print(t_vector)
t_matrix = torch.LongTensor(
    data= [
        [1, 2, 3, 4],
        [5, 6, 7, 8]
    ]
)
print(t_matrix)
tensor([1, 2, 3, 4, 5])
tensor([[1, 2, 3, 4],
        [5, 6, 7, 8]])

屬性

屬性-T

  • 返回Tensor的轉(zhuǎn)置;
print(t_vector.T)    # 向量轉(zhuǎn)置還是本身,不產(chǎn)生轉(zhuǎn)置效果
print(t_matrix.T)
tensor([1, 2, 3, 4, 5])
tensor([[1, 5],
        [2, 6],
        [3, 7],
        [4, 8]])

屬性-data

  • 返回張量的數(shù)據(jù), 返回的也是張量,就是張量本身;
    • 返回不同的id;
    • 共享同一個(gè)Stroage;
    • 但是data返回的數(shù)據(jù)狀態(tài)改變:require s_grad = False,就是不能求導(dǎo)。
# 地址不同
print(t_vector.data)
print(type(t_vector.data))
print(id(t_vector), id(t_vector.data))
tensor([1, 2, 3, 4, 5])
<class 'torch.Tensor'>
4481379352 4510253344
# 數(shù)據(jù)相互影響
d = t_vector.data
t_vector[2] =88
print(d)

tensor([ 1,  2, 88,  4,  5])
# data與原張量的差異

屬性-dtype

  • Tensoor元素類型
print(t_vector.dtype)
torch.int64

屬性-grad,grad_fn,requires_grad

  • 導(dǎo)數(shù):
    • 默認(rèn)是None
    • 調(diào)用backward計(jì)算導(dǎo)數(shù),導(dǎo)數(shù)是累加的。如果每次單獨(dú)計(jì)算,需要清空;
    • 導(dǎo)數(shù)的計(jì)算需要導(dǎo)數(shù)函數(shù)grad_fn(沒(méi)有指定函數(shù)的張量無(wú)法計(jì)算導(dǎo)數(shù))。
    • grad_fn函數(shù)自動(dòng)跟蹤,需要設(shè)置requires_grad=True
  1. grad屬性
print(t_vector.grad)
None
t_vector.backward()
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

<ipython-input-10-771cce0a66d3> in <module>()
----> 1 t_vector.backward()


/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
    116                 products. Defaults to ``False``.
    117         """
--> 118         torch.autograd.backward(self, gradient, retain_graph, create_graph)
    119 
    120     def register_hook(self, hook):


/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
     91     Variable._execution_engine.run_backward(
     92         tensors, grad_tensors, retain_graph, create_graph,
---> 93         allow_unreachable=True)  # allow_unreachable flag
     94 
     95 


RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
  1. 屬性-grad_fn
    • 張量所在的導(dǎo)數(shù)函數(shù)
t1 = torch.Tensor([1.0])
t2 = torch.Tensor([1.0])

t3 = t1 + t2
print(t3)
print(t3.grad_fn)
tensor([2.])
None
  1. requires_grad屬性
t1.requires_grad=True
t2.requires_grad=True
t4 = t1 + t2
print(t4)
print(t4.grad_fn)
print(type(t4.grad_fn))
print(t4.requires_grad)
print(t1.grad_fn)
tensor([5.], grad_fn=<AddBackward0>)
<AddBackward0 object at 0x10cd1b780>
<class 'AddBackward0'>
True
None
print(t4.grad)
t4.backward()
print(t4.grad)    # 沒(méi)有導(dǎo)數(shù)
print(t1.grad)     # t1與t2導(dǎo)數(shù)(偏導(dǎo)數(shù))
print(t2.grad)
print(t1.grad_fn)
None
None
tensor([2.])
tensor([2.])
None

屬性-is_cuda,device

  • 判斷是否是cuda計(jì)算(GPU計(jì)算)
  • device使用專門的類構(gòu)造;
t1 = torch.Tensor([2.5])
print(t1.is_cuda)
False
t2 = torch.Tensor([2.5], device=torch.device('cpu:0'))
t2 = torch.Tensor([2.5], device=torch.device('cpu'))
print(t2.is_cuda)

False
t3 = torch.Tensor([2.5], device=torch.device('cuda'))
print(t3.is_cuda)   # 蘋果電腦不支持,請(qǐng)?jiān)贜vidia的顯卡上運(yùn)算,其他支持GPU運(yùn)算的電腦上運(yùn)行
# 在window上還需要安裝廠商驅(qū)動(dòng)
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

<ipython-input-25-8168e2f27255> in <module>()
----> 1 t3 = torch.Tensor([2.5], device=torch.device('cuda'))
      2 print(t3.is_cuda)   # 蘋果電腦不支持,請(qǐng)?jiān)贜vidia的顯卡上運(yùn)算,其他支持GPU運(yùn)算的電腦上運(yùn)行


RuntimeError: legacy constructor for device type: cpu was passed device type: cuda, but device type must be: cpu
# 判定電腦是否之處GPU運(yùn)算
print(torch.cuda.is_available())
False

屬性-is_leaf,grad與retain_grad函數(shù)

  • 這個(gè)屬性用來(lái)判定張量Tensor是否是Leaf Tensor,下面兩種情況都應(yīng)該是Leaf Tensor:

    • 屬性requires_grad為False的。
    • 屬性requires_grad=True,但是用戶構(gòu)建的Tensor,表示該張量不是計(jì)算結(jié)果,而是用戶構(gòu)建的初始張量。
  • 運(yùn)行backward后,僅僅只有Leaf Tensor在才會(huì)有g(shù)rad屬性。如果非Leaf Tensor需要具有g(shù)rad屬性,需要使用retain_grad函數(shù)開(kāi)啟grad屬性。

# 演示葉子Tensor與grad,backward的關(guān)系
import torch

t1 = torch.Tensor([1.0])     # 用戶構(gòu)建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1 + t2
t3.backward()

print(t1.is_leaf, t2.is_leaf, t3.is_leaf)
print(t1.grad)     # Leaf Tensor的grad屬性由backward函數(shù)產(chǎn)生。
True True False
tensor([1.])
# 演示Non-Leaf Tensor 與 retain_grad的關(guān)系

import torch

t1 = torch.Tensor([1.0])     # 用戶構(gòu)建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1 + t2
t3.retain_grad()    # 調(diào)用該函數(shù)后,t3才有g(shù)rad屬性,可以注釋這個(gè)語(yǔ)句體驗(yàn)
t3.backward()

print(t1.is_leaf, t2.is_leaf, t3.is_leaf)
print(t3.grad) 
True True False
tensor([1.])

屬性-ndim與dim函數(shù)

  • Tensor的維度
import torch
t1 = torch.Tensor([1.0, 20])     # 用戶構(gòu)建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [2.0, 1.0],
        [1.0, 2.0]
    ]
)
print(t1.ndim)   # 1 維

print(t2.ndim)  # 2 維
print(t2.dim())
1
2
2

屬性-shape與size函數(shù)

  • Tensor的形狀,與size函數(shù)一樣
import torch
t1 = torch.Tensor([1.0, 20])     # 用戶構(gòu)建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [2.0, 1.0],
        [1.0, 2.0]
    ]
)
print(t2.shape) # 屬性shape

print(t2.size())  # 函數(shù)size()
torch.Size([2, 2])
torch.Size([2, 2])

屬性-is_sparse

  • 是否稀疏張量:

    • 在矩陣中,若數(shù)值為0的元素?cái)?shù)目遠(yuǎn)遠(yuǎn)多于非0元素的數(shù)目,并且非0元素分布沒(méi)有規(guī)律時(shí),則稱該矩陣為稀疏矩陣;與之相反,若非0元素?cái)?shù)目占大多數(shù)時(shí),則稱該矩陣為稠密矩陣。定義非零元素的總數(shù)比上矩陣所有元素的總數(shù)為矩陣的稠密度。
  • is_sparse該屬性是只讀,不可寫的

    • 稀疏張量提供專門的API產(chǎn)生。
  • 稀疏張量有自己的構(gòu)造規(guī)則:
    • 稀疏張量被表示為一對(duì)致密張量:一維張量和二維張量的索引??梢酝ㄟ^(guò)提供這兩個(gè)張量來(lái)構(gòu)造稀疏張量,以及稀疏張量的大小。
# 默認(rèn)的張量都是稠密張量
import torch
t1 = torch.Tensor([0, 0])     # 用戶構(gòu)建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [1, 0],
        [0, 0]
    ]
)
print(t1.is_sparse)  # 屬性shape

print(t2.is_sparse)  # 函數(shù)size()

t3 = torch.Tensor(1000,1000)
t3.fill_(0)
t3[0,0]=1
print(t3.is_sparse)  
print(t3)
t3.is_sparse=True   # 不能修改該屬性,該屬性是只讀,不可寫的。
False
False
False
tensor([[1., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        ...,
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.]])



---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-59-180881d46907> in <module>()
     17 print(t3.is_sparse)
     18 print(t3)
---> 19 t3.is_sparse=True
     20 print()


AttributeError: attribute 'is_sparse' of 'torch._C._TensorBase' objects is not writable
# 稀疏矩陣
import torch
ts = torch.sparse.FloatTensor(2, 3)
print(ts.is_sparse)  
print(ts)
print(ts.to_dense())
True
tensor(indices=tensor([], size=(2, 0)),
       values=tensor([], size=(0,)),
       size=(2, 3), nnz=0, layout=torch.sparse_coo)
tensor([[0., 0., 0.],
        [0., 0., 0.]])

屬性-layout

  • 張量Tensor使用Storage表示都是一維的,其構(gòu)成張量只要采用布局計(jì)算。這個(gè)布局使用layout屬性設(shè)置

    • 一般都是采用strided
    • 稀疏矩陣的布局使用的是:torch.sparse_coo
  • 目前常用的就是這兩種布局layout。

import torch
t1 = torch.Tensor([0, 0])     # 用戶構(gòu)建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [1, 0],
        [0, 0]
    ]
)
print(t1.layout, t2.layout)
torch.strided torch.strided

屬性-output_nr

  • 在反向傳播中存放輸出。
    • 具體用途先存疑。
import torch
t1 = torch.Tensor([0, 0])     # 用戶構(gòu)建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [1, 0],
        [0, 0]
    ]
)
print(t2.output_nr)
0
# 演示Non-Leaf Tensor 與 retain_grad的關(guān)系

import torch

t1 = torch.Tensor([2.0])     # 用戶構(gòu)建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1.sin()
print(t1.output_nr, t2.output_nr, t2.output_nr)
t3.retain_grad()    # 調(diào)用該函數(shù)后,t3才有g(shù)rad屬性,可以注釋這個(gè)語(yǔ)句體驗(yàn)
t3.backward()
print(t3)
print(t1.is_leaf, t2.is_leaf, t3.is_leaf)
print(t3.grad) 
print(t1.output_nr, t2.output_nr, t2.output_nr)
0 0 0
tensor([0.9093], grad_fn=<SinBackward>)
True True False
tensor([1.])
0 0 0

屬性-其他

  • is_mkldnn:intel提供的加速CPU運(yùn)算的方法,判定是否CPU加速
  • is_quantized:是否被量化(量化指將信號(hào)的連續(xù)取值近似為有限多個(gè)離散值)
  • name:張量名
  • volatile:新版本已經(jīng)停用;
# 演示Non-Leaf Tensor 與 retain_grad的關(guān)系

import torch

t1 = torch.Tensor([2.0])     # 用戶構(gòu)建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1 + t2
print(t1.is_mkldnn)
print(t2.name)
print(t2.is_quantized)
False
None
False

附錄:mkldnn的使用

  1. 下載地址

    • https://github.com/intel/mkl-dnn
  2. 安裝

    • cmake安裝,直接套路
  3. 如果torch不支持mkldnn,就需要使用源代碼重新安裝!


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容