(此文為個人學習pytorch時的筆記,便於之后的查詢)
Tensor基本操作
創建tensor:
1.numpy向量轉tensor:
a=np.array([2,2,2])
b=torch.from_numpy(a)
2.列表轉tensor:
a=torch.tensor([2,2])
b=torch.FloatTensor([2,2.])#不常用
c=torch.tensor([[1,2],[3,4]])#2*2矩陣
3.利用大寫接受shape創建:
torch.empty(2,3)#生成一個2*3的0矩陣
torch.Tensor(2,3)#生成一個2*3的隨機矩陣
torch.IntTensor(2,3)
torch.FloatTensor(2,3).type()
默認下,Tensor為‘torch.FloatTensor’類型,若要改為double類型的,則需要執行
torch.set_default_tensor_type(torch.DoubleTensor)
來修改。
4.隨機創建Tensor:
a=torch.rand(3,3)#創建3*3的0到1均勻分布的矩陣
a=torch.randn(3,3)#均值為0方差為1正態分布矩陣
torch.rand_like(a)#等價於下一條
torch.rand(a.shape)
torch.randint(1,10,[3,3])#創建3*3的1到10隨機分布的整數矩陣
5.創建相同數的矩陣:
torch.full([3,3],1)#生成3*3的全為1的矩陣
torch.full([],1)#生成標量1
torch.full([2],1)#生成一個長度為2的值全為1的向量
torch.ones(3,3)
torch.zeros(3,3)
torch.eye(3,4)#生成對角為1矩陣,若不是對角矩陣,則多余出用0填充
torch.eye(3)#3*3對角矩陣
6.創建規律數列矩陣:
torch.arange(0,10)#生成[0,1,2,3,4,5,6,7,8,9]
torch.arange(0,10,2)#生成增量為2的數列
torch.arange(10)#效果同於(0,10)
torch.linspace(0,10,4)#生成[0.0000,3.3333,6,6667,10,0000]包括10的4等分向量
torch.logspace(0,-1,steps=10,base=10)#生成10個0到-1等分的數,再以其為指數,如第一個數#為1.000,最后一個數為0.100
7.創建隨機打散數組:
torch.randperm(10)#生成0~9這10個數亂序的數組(常用作索引)
tensor的比較:
torch.eq(a,b)#返回對比后的矩陣,若矩陣形狀相同,那么會對沒一個位置進行比較,返回一個同樣形狀的矩陣,相應位置若相同則返回1,不相等則為0
torch.all(torch.eq(a,b))#a,b相同時返回1,否則為1。即all內的張量為全1矩陣會返回1
tensor的切片(start : end : step):
如果要存放一張rgb的minist(28*28)圖片:
img=torch.rand(4,3,28,28)#4張圖片
img[1]#獲取第二張圖片
img[0,0].shape#獲取第一張圖片的第一個通道的圖片形狀
img[0,0,2,4]#返回像素灰度值標量
img[:2]#獲得img[0]和img[1]
#img[:2,:1]==img[:2,:1,:,:]
img[2:]#獲得img[2],img[3],img[4]三張圖片
img[-1:]#獲得img[4]
img[:,:,::2,::2]#對圖片進行隔行(列)采樣
#還有一種索引中的...操作,有自動填充的功能,一般用於維數很多時使用。
img[0,...]#img.shape的結果是torch.Size([4,28,28]),這是和img[0,:]或者img[0]是一樣的。
img[0,...,0:28:2]#此時由於寫了最右邊的索引,中間的...等價於:,:,即img[0,:,:,0:28:2]
tensor的索引查找(index_select/masked_select/take):
#同樣是上面的img
#比如要取前三張圖片,那么就是針對第一個維度(圖片數目)進行挑選
img.index_select(0,torch.tensor([0,1,2]))#第一個參數為軸,第二個參數為tensor類型的索引
img.index_select(0,torch.arange(3))#效果同上句
#利用掩碼mask
x=torch.rand(3,4)
mask=x.ge(0.5)#會把x中大於0.5的置為一,其他置為0,類似於閾值化操作。
y=torch.masked_select(x,mask)#將mask中值為1的元素取出來,比如mask有3個位置值為1
y.shape#結果為tensor.Size([3])
#利用take取元素
x=torch.tensor([[1,2,3],[4,5,6]])
torch.take(x,torch.tensor([0,2,6]))
#則最后結果為tensor([1,3,6]),也就是說會先將tensor壓縮成一維向量,再按照索引取元素。
tensor的維度變換(view/reshape/squeeze/transpose/expand/permute):
img=torch.rand(4,1,28,28)
##view(reshape)##
#view==reshape,可以任意替換
x=img.view(4,28*28)
img.view(4,28,28)
x.view(4,28,28,1)#此操作可行但不合理,邏輯上的問題會造成信息污染
##squeeze減少維度數和unsqueeze擴展維度數##
#squeeze只關心有值的,可以擠壓該值只有1個的維度,則最后會保留值總數目
x=torch.rand(1,32,1,1)#1張圖,有32個通道,每個通道一個像素
x.squeeze()#形狀變為[32]
x.squeeze(0)#[32,1,1]
x.squeeze(1)#[1,32,1,1]並沒有發生壓縮,因為該維度上有值,不能減少這一維度,不會報錯
#unsqueeze會在參數維度上進行,若有此維度則會先將當前維度后移再拓展
img.unsqueeze(0).shape#結果為torch.Size([1,4,1,28,28]),物理意義為batch
img.unsqueeze(-1).shape#結果為torch.Size([4,1,28,28,1]),等價於unsqueeze(4)
#例如圖片要在某個維度上面做加減,那么僅僅有一維數據是不夠的,此時就需要將一維數據擴展維度
b=torch.rand(32)#torch.Size([32])
f=torch.rand(4,32,14,14)#要做到在每個channel上增加某一bias
b=b.unsqueeze(1).unsqueeze(2).unsqueeze(0)#形狀為[1,32,1,1]
#但僅僅如此是不夠的,我們知道矩陣進行加減操作是需要形狀完全一致的,所以形狀必須為[4,32,14,14],這就需要在某一維度上進行拓展的操作,需要了解后面的api(expand)才可以解決。
##expend僅在有需要時增加數據的擴展(starstarstar)/repeat主動增加數據的擴展##
#為了將[1,32,1,1]擴展為[4,32,14,14]:
#expend
b.expend(4,32,14,14)#直接輸入想要的形狀,但是只有原維度上的數值為1時才可以進行擴展
b.expend(4,33,14,14)#報錯
b.expend(4,-1,-1,-1)#表示其他維度不變,僅怎加第0維的內容
#repeat,注意參數輸入的是在該維度上拷貝的次數而不是形狀!
b.repeat(4,32,1,1)#[4,1024,1,1] 1024=32*32
#正確操作
b.repeat(4,1,14,14)#[4,32,14,14]
#張量的轉置(維度交換)操作
#對於二維向量來說:
a=torch.rand(3,4)
a.t()#即完成了轉置
#對於任意維度張量的轉置操作:transpose
a=torch.rand(4,3,32,32)
a.transpose(1,3)#接收參數為要進行交換那兩個維度,[4,32,32,3]
#接收index來進行轉置:permute
a.permute(0,2,3,1)#形狀為[4,32,32,3]
tensor的Broadcasting:
在矩陣相加時,如果兩矩陣的形狀不一致,則會自動運行broadcast
#有點類似於先unsqueeze再expand
#自動會在第0維處插入一個維度,並且同時將形狀為1的部分自動轉換成想要運算的對象的形狀,這表示着在broadcast前先要將后面的維度數調至想要的樣子再使用。
#例如,將形狀為(32)的向量轉化為(4,32,14,14),則先要unsueeze到(32,1,1),才會自動broadcast為(4,32,14,14).
#轉換成物理意義容易理解,比如矩陣加上一個數就是broadcast.比如上面為圖片數據時,(32)就是對32個通道想要加的不同bias,會自動廣播為對每個灰度值上的bias。(真正運算的是該數據的最基本單位)。加上(14,14)就是對每一張圖的每個通道的圖上加上一個(14,14)的bias。
tensor的拼接與拆分(cat/stack/spilit/chunk):
#cat拼接
a=torch.rand(4,3,18,18)
b=torch.rand(5,3,18,18)
c=torch.rand(4,1,18,18)
d=a.copy()
torch.cat([a,b],dim=0)#拼接得到(9,3,18,18)的數據
#若為2維數據,dim=0則是豎向拼接,dim=0就是橫向拼接。dim所指維度可以不同,但其他維度形狀必須一致
torch.cat([a,c],dim=1)#就會得到(4,4,18,18)的數據。
#stack增維度拼接
torch.stack([a,b],dim=0)#得到形狀為(2,4,3,18,18)。使用時列表內對象的形狀需要一致。
#split拆分
#根據欲拆分長度:
a1,a2=a.split(2,dim=0)#拆分長度為2.對第0維按照2個一份進行拆分。拆分獲得兩個形狀為(2,3,18,18)的張量。
a1,a2=a.split([3,1],dim=0)#不同長度拆分。獲得(3,3,18,18)和(1,3,18,18)兩個形狀的張量。
#chunk拆分
#根據欲拆分數量
a1,a2,a3,a4=a.chunk(4,dim=0)#將張量依第0維拆分成4個(1,3,18,18)的張量。等效於a.split(1,dim=0)
tensor的運算:
# +等價於torch.add()
#乘法
#tensor直接相*,其結果為element wise,矩陣乘法為torch.matmul或者@
#高維tensor矩陣相乘實際上是對多個二維矩陣進行並行運算
a=torch.rand(4,3,28,64)
b=torch.rand(4,3,64,32)
a@b#結果得到的形狀為(4,3,28,32)
#若(4,3,28,64)@(4,1,64,32)則會自動調用廣播機制,把(4,1,64,32)轉變為(4,3,64,32)再相乘。無法調用廣播機制的乘法則會報錯。
#平方
a=torch.full([2,2],2)#創建一個(2,2)的全2矩陣
a.pow(2)#a的每個元素都平方
a**2#等價於上一句
#開方
a.sqrt()#平方根
a**0.5#等價於上一句
#exp,log
a.torch.exp(torch.ones(2,2))
torch.log(a)
#近似
#floor()向下取整,ceil()向上取整,round()四舍五入。
#取整取小數
#trunc()取整,frac()取小數
#clamp取范圍
a=torch.tensor([[3,5],[6,8]])
a.clamp(6)#得到[[6,6],[6,8]],小於6的都變為6
a.clamp(5,6)#得到[[5,5],[6,6]],小於下限變為下限,大於上限變為上限。
tensor的統計屬性:
#范數
#求多少p范數只需要在norm(p)的參數中修改p即可
a.norm(1)#求a的一范數,范數也可以加dim=
#求最大值和最小值與其相關的索引
a.min()
a.max()
a.argmax()#會得到索引值,返回的永遠是一個標量,多維張量會先拉成向量再求得其索引。拉伸的過程為每一行加起來變成一整行,而不是matlab中的列拉成一整列。
a.argmin()
a.argmax(dim=1)#如果不想獲取拉伸后的索引值就需要在指定維度上進行argmax,比如如果a為(2,2)的矩陣,那么這句話的結果就可能是[1,1],表示第一行第一個在此行最大,第二行第一個在此行最大。
#累加總和
a.sum()
#累乘綜合
a.prod()
#dim,keepdim
#假設a的形狀為(4,10)
a.max(dim=1)#結果會得到一個(4)的張量,表示4個樣本中每個樣本10個特征的最大值組成的張量。(max換成argmax也是同理)。
a.max(dim=1,keepdim=True)#同時返回a.argmax(dim=1)得到的結果,以保持維度數目和原來一致。
#top-k,k-th
a.topk(5)#返回張量a前5個最大值組成的向量
a.topk(5,dim=1,largest=False)#關閉largest求最小的5個
a.kthvalue(8,dim=1)#返回第八小的值
#比較操作
#都是進行element-wise操作
torch.eq(a,b)#返回的是張量
torch.equal(a,b)#返回的是True或者False
tensor的where和gather:
torch.where(condition,x,y)
torch.gather(input,dim,index,out=none)