本主題主要說(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)容就容易理解:
- 基本屬性
- 了解對(duì)象的內(nèi)存與數(shù)據(jù)結(jié)構(gòu)
- 基本操作
- 數(shù)據(jù)進(jìn)出
- 數(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)算。
- 構(gòu)建數(shù)據(jù)對(duì)象的最終目的就是計(jì)算;
- 基本屬性
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)算)
- BLAS
- Basic Linear Algebra Subprograms(Fortran語(yǔ)言編寫,F(xiàn)ortran史上經(jīng)典古老的數(shù)學(xué)計(jì)算語(yǔ)言);
- LAPACK
- Linear Algebra Package,底層使用的也是BLAS;
- ATLAS
- Automatically Tuned Linear Algebra Software;
- 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)行編譯。
- cuBLAS與ACML:
- Intel的MKL和AMD的ACML都是在BLAS的基礎(chǔ)上,針對(duì)自己特定的CPU平臺(tái)進(jìn)行針對(duì)性的優(yōu)化加速。以及NVIDIA針對(duì)GPU開(kāi)發(fā)的cuBLAS。
- BLAS
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
- 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
- 屬性-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
- 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的使用
-
下載地址
https://github.com/intel/mkl-dnn
-
安裝
- cmake安裝,直接套路
如果torch不支持mkldnn,就需要使用源代碼重新安裝!