Pytorch的低階API主要包括張量操作,動态計算圖和自動微分。
如果把模型比作一個房子,那麼低階API就是【模型之磚】。
在低階API層次上,可以把Pytorch當做一個增強版的numpy來使用。
Pytorch提供的方法比numpy更全面,運算速度更快,如果需要的話,還可以使用GPU進行加速。
前面幾章我們對低階API已經有了一個整體的認識,本章我們将重點詳細介紹張量操作和動态計算圖。
張量的操作主要包括張量的結構操作和張量的數學運算。
張量結構操作諸如:張量建立,索引切片,次元變換,合并分割。
張量數學運算主要有:标量運算,向量運算,矩陣運算。另外我們會介紹張量運算的廣播機制。
動态計算圖我們将主要介紹動态計算圖的特性,計算圖中的Function,計算圖與反向傳播。
本篇我們介紹張量的數學運算。
一,标量運算
張量的數學運算符可以分為标量運算符、向量運算符、以及矩陣運算符。
加減乘除乘方,以及三角函數,指數,對數等常見函數,邏輯比較運算符等都是标量運算符。
标量運算符的特點是對張量實施逐元素運算。
有些标量運算符對常用的數學運算符進行了重載。并且支援類似numpy的廣播特性。
import torch
import numpy as np
複制
a = torch.tensor([[1.0,2],[-3,4.0]])
b = torch.tensor([[5.0,6],[7.0,8.0]])
a+b #運算符重載
複制
tensor([[ 6., 8.],
[ 4., 12.]])
複制
a-b
複制
tensor([[ -4., -4.],
[-10., -4.]])
複制
a*b
複制
tensor([[ 5., 12.],
[-21., 32.]])
複制
a/b
複制
tensor([[ 0.2000, 0.3333],
[-0.4286, 0.5000]])
複制
a**2
複制
tensor([[ 1., 4.],
[ 9., 16.]])
複制
a**(0.5)
複制
tensor([[1.0000, 1.4142],
[ nan, 2.0000]])
複制
a%3 #求模
複制
tensor([[1., 2.],
[0., 1.]])
複制
a//3 #地闆除法
複制
tensor([[ 0., 0.],
[-1., 1.]])
複制
a>=2 # torch.ge(a,2) #ge: greater_equal縮寫
複制
tensor([[False, True],
[False, True]])
複制
(a>=2)&(a<=3)
複制
tensor([[False, True],
[False, False]])
複制
(a>=2)|(a<=3)
複制
tensor([[True, True],
[True, True]])
複制
a==5 #torch.eq(a,5)
複制
tensor([[False, False],
[False, False]])
複制
torch.sqrt(a)
複制
tensor([[1.0000, 1.4142],
[ nan, 2.0000]])
複制
a = torch.tensor([1.0,8.0])
b = torch.tensor([5.0,6.0])
c = torch.tensor([6.0,7.0])
d = a+b+c
print(d)
複制
tensor([12., 21.])
複制
print(torch.max(a,b))
複制
tensor([5., 8.])
複制
print(torch.min(a,b))
複制
tensor([1., 6.])
複制
x = torch.tensor([2.6,-2.7])
print(torch.round(x)) #保留整數部分,四舍五入
print(torch.floor(x)) #保留整數部分,向下歸整
print(torch.ceil(x)) #保留整數部分,向上歸整
print(torch.trunc(x)) #保留整數部分,向0歸整
複制
tensor([ 3., -3.])
tensor([ 2., -3.])
tensor([ 3., -2.])
tensor([ 2., -2.])
複制
x = torch.tensor([2.6,-2.7])
print(torch.fmod(x,2)) #作除法取餘數
print(torch.remainder(x,2)) #作除法取剩餘的部分,結果恒正
複制
tensor([ 0.6000, -0.7000])
tensor([0.6000, 1.3000])
複制
# 幅值裁剪
x = torch.tensor([0.9,-0.8,100.0,-20.0,0.7])
y = torch.clamp(x,min=-1,max = 1)
z = torch.clamp(x,max = 1)
print(y)
print(z)
複制
tensor([ 0.9000, -0.8000, 1.0000, -1.0000, 0.7000])
tensor([ 0.9000, -0.8000, 1.0000, -20.0000, 0.7000])
複制
二,向量運算
向量運算符隻在一個特定軸上運算,将一個向量映射到一個标量或者另外一個向量。
#統計值
a = torch.arange(1,10).float()
print(torch.sum(a))
print(torch.mean(a))
print(torch.max(a))
print(torch.min(a))
print(torch.prod(a)) #累乘
print(torch.std(a)) #标準差
print(torch.var(a)) #方差
print(torch.median(a)) #中位數
複制
tensor(45.)
tensor(5.)
tensor(9.)
tensor(1.)
tensor(362880.)
tensor(2.7386)
tensor(7.5000)
tensor(5.)
複制
#指定次元計算統計值
b = a.view(3,3)
print(b)
print(torch.max(b,dim = 0))
print(torch.max(b,dim = 1))
複制
tensor([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
torch.return_types.max(
values=tensor([7., 8., 9.]),
indices=tensor([2, 2, 2]))
torch.return_types.max(
values=tensor([3., 6., 9.]),
indices=tensor([2, 2, 2]))
複制
#cum掃描
a = torch.arange(1,10)
print(torch.cumsum(a,0))
print(torch.cumprod(a,0))
print(torch.cummax(a,0).values)
print(torch.cummax(a,0).indices)
print(torch.cummin(a,0))
複制
tensor([ 1, 3, 6, 10, 15, 21, 28, 36, 45])
tensor([ 1, 2, 6, 24, 120, 720, 5040, 40320, 362880])
tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])
torch.return_types.cummin(
values=tensor([1, 1, 1, 1, 1, 1, 1, 1, 1]),
indices=tensor([0, 0, 0, 0, 0, 0, 0, 0, 0]))
複制
#torch.sort和torch.topk可以對張量排序
a = torch.tensor([[9,7,8],[1,3,2],[5,6,4]]).float()
print(torch.topk(a,2,dim = 0),"\n")
print(torch.topk(a,2,dim = 1),"\n")
print(torch.sort(a,dim = 1),"\n")
#利用torch.topk可以在Pytorch中實作KNN算法
複制
torch.return_types.topk(
values=tensor([[9., 7., 8.],
[5., 6., 4.]]),
indices=tensor([[0, 0, 0],
[2, 2, 2]]))
torch.return_types.topk(
values=tensor([[9., 8.],
[3., 2.],
[6., 5.]]),
indices=tensor([[0, 2],
[1, 2],
[1, 0]]))
torch.return_types.sort(
values=tensor([[7., 8., 9.],
[1., 2., 3.],
[4., 5., 6.]]),
indices=tensor([[1, 2, 0],
[0, 2, 1],
[2, 0, 1]]))
複制
三,矩陣運算
矩陣必須是二維的。類似torch.tensor([1,2,3])這樣的不是矩陣。
矩陣運算包括:矩陣乘法,矩陣轉置,矩陣逆,矩陣求迹,矩陣範數,矩陣行列式,矩陣求特征值,矩陣分解等運算。
#矩陣乘法
a = torch.tensor([[1,2],[3,4]])
b = torch.tensor([[2,0],[0,2]])
print(a@b) #等價于torch.matmul(a,b) 或 torch.mm(a,b)
複制
tensor([[2, 4],
[6, 8]])
複制
#矩陣轉置
a = torch.tensor([[1.0,2],[3,4]])
print(a.t())
複制
tensor([[1., 3.],
[2., 4.]])
複制
#矩陣逆,必須為浮點類型
a = torch.tensor([[1.0,2],[3,4]])
print(torch.inverse(a))
複制
tensor([[-2.0000, 1.0000],
[ 1.5000, -0.5000]])
複制
#矩陣求trace
a = torch.tensor([[1.0,2],[3,4]])
print(torch.trace(a))
複制
tensor(5.)
複制
#矩陣求範數
a = torch.tensor([[1.0,2],[3,4]])
print(torch.norm(a))
複制
tensor(5.4772)
複制
#矩陣行列式
a = torch.tensor([[1.0,2],[3,4]])
print(torch.det(a))
複制
tensor(-2.0000)
複制
#矩陣特征值和特征向量
a = torch.tensor([[1.0,2],[-5,4]],dtype = torch.float)
print(torch.eig(a,eigenvectors=True))
#兩個特征值分别是 -2.5+2.7839j, 2.5-2.7839j
複制
torch.return_types.eig(
eigenvalues=tensor([[ 2.5000, 2.7839],
[ 2.5000, -2.7839]]),
eigenvectors=tensor([[ 0.2535, -0.4706],
[ 0.8452, 0.0000]]))
複制
#矩陣QR分解, 将一個方陣分解為一個正交矩陣q和上三角矩陣r
#QR分解實際上是對矩陣a實施Schmidt正交化得到q
a = torch.tensor([[1.0,2.0],[3.0,4.0]])
q,r = torch.qr(a)
print(q,"\n")
print(r,"\n")
print(q@r)
複制
#矩陣svd分解
#svd分解可以将任意一個矩陣分解為一個正交矩陣u,一個對角陣s和一個正交矩陣v.t()的乘積
#svd常用于矩陣壓縮和降維
a=torch.tensor([[1.0,2.0],[3.0,4.0],[5.0,6.0]])
u,s,v = torch.svd(a)
print(u,"\n")
print(s,"\n")
print(v,"\n")
print([email protected](s)@v.t())
#利用svd分解可以在Pytorch中實作主成分分析降維
複制
tensor([[-0.2298, 0.8835],
[-0.5247, 0.2408],
[-0.8196, -0.4019]])
tensor([9.5255, 0.5143])
tensor([[-0.6196, -0.7849],
[-0.7849, 0.6196]])
tensor([[1.0000, 2.0000],
[3.0000, 4.0000],
[5.0000, 6.0000]])
複制
四,廣播機制
Pytorch的廣播規則和numpy是一樣的:
- 1、如果張量的次元不同,将次元較小的張量進行擴充,直到兩個張量的次元都一樣。
- 2、如果兩個張量在某個次元上的長度是相同的,或者其中一個張量在該次元上的長度為1,那麼我們就說這兩個張量在該次元上是相容的。
- 3、如果兩個張量在所有次元上都是相容的,它們就能使用廣播。
- 4、廣播之後,每個次元的長度将取兩個張量在該次元長度的較大值。
- 5、在任何一個次元上,如果一個張量的長度為1,另一個張量長度大于1,那麼在該次元上,就好像是對第一個張量進行了複制。
torch.broadcast_tensors可以将多個張量根據廣播規則轉換成相同的次元。
a = torch.tensor([1,2,3])
b = torch.tensor([[0,0,0],[1,1,1],[2,2,2]])
print(b + a)
複制
tensor([[1, 2, 3],
[2, 3, 4],
[3, 4, 5]])
複制
a_broad,b_broad = torch.broadcast_tensors(a,b)
print(a_broad,"\n")
print(b_broad,"\n")
print(a_broad + b_broad)
複制
tensor([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
tensor([[0, 0, 0],
[1, 1, 1],
[2, 2, 2]])
tensor([[1, 2, 3],
[2, 3, 4],
[3, 4, 5]])
複制