摘要:Tensor,它可以是0維、一維以及多維的陣列,你可以將它看作為神經網路界的Numpy,它與Numpy相似,二者可以共享記憶體,且之間的轉換非常方便。
本文分享自華為雲社群《Tensor:Pytorch神經網路界的Numpy》,作者: 擇城終老 。
Tensor
Tensor,它可以是0維、一維以及多維的陣列,你可以將它看作為神經網路界的Numpy,它與Numpy相似,二者可以共享記憶體,且之間的轉換非常方便。
但它們也不相同,最大的區別就是Numpy會把ndarray放在CPU中進行加速運算,而由Torch產生的Tensor會放在GPU中進行加速運算。
對於Tensor,從介面劃分,我們大致可分為2類:
- torch.function:如torch.sum、torch.add等。
- tensor.function:如tensor.view、tensor.add等。
而從是否修改自身來劃分,會分為如下2類:
- 不修改自身資料,如x.add(y),x的資料不變,返回一個新的Tensor。
- 修改自身資料,如x.add_(y),運算結果存在x中,x被修改。
簡單的理解就是方法名帶不帶下劃線的問題。
現在,我們來實現2個陣列對應位置相加,看看其效果就近如何:
import torch x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) print(x + y) print(x.add(y)) print(x) print(x.add_(y)) print(x)
執行之後,效果如下:
下面,我們來正式講解Tensor的使用方式。
建立Tensor
與Numpy一樣,建立Tensor也有很多的方法,可以自身的函式進行生成,也可以通過列表或者ndarray進行轉換,同樣也可以指定維度等。具體方法如下表(陣列即張量):
這裡需要注意Tensor有大寫的方法也有小寫的方法,具體效果我們先來看看程式碼:
import torch t1 = torch.tensor(1) t2 = torch.Tensor(1) print("值{0},型別{1}".format(t1, t1.type())) print("值{0},型別{1}".format(t2, t2.type()))
執行之後,效果如下:
其他示例如下:
import torch import numpy as np t1 = torch.zeros(1, 2) print(t1) t2 = torch.arange(4) print(t2) t3 = torch.linspace(10, 5, 6) print(t3) nd = np.array([1, 2, 3, 4]) t4 = torch.from_numpy(nd) print(t4)
其他例子基本與上面基本差不多,這裡不在贅述。
修改Tensor維度
同樣的與Numpy一樣,Tensor一樣有維度的修改函式,具體的方法如下表所示:
示例程式碼如下所示:
import torch t1 = torch.Tensor([[1, 2]]) print(t1) print(t1.size()) print(t1.dim()) print(t1.view(2, 1)) print(t1.view(-1)) print(torch.unsqueeze(t1, 0)) print(t1.numel())
執行之後,效果如下:
擷取元素
當然,我們建立Tensor張量,是為了使用裡面的資料,那麼就不可避免的需要獲取資料進行處理,具體擷取元素的方式如表:
示例程式碼如下所示:
import torch # 設定隨機數種子,保證每次執行結果一致 torch.manual_seed(100) t1 = torch.randn(2, 3) # 列印t1 print(t1) # 輸出第0行資料 print(t1[0, :]) # 輸出t1大於0的資料 print(torch.masked_select(t1, t1 > 0)) # 輸出t1大於0的資料索引 print(torch.nonzero(t1)) # 獲取第一列第一個值,第二列第二個值,第三列第二個值為第1行的值 # 獲取第二列的第二個值,第二列第二個值,第三列第二個值為第2行的值 index = torch.LongTensor([[0, 1, 1], [1, 1, 1]]) # 取0表示以行為索引 a = torch.gather(t1, 0, index) print(a) # 反操作填0 z = torch.zeros(2, 3) print(z.scatter_(1, index, a))
執行之後,效果如下:
我們a = torch.gather(t1, 0, index)對其做了一個圖解,方便大家理解。如下圖所示:
當然,我們直接有公司計算,因為這麼多資料標線實在不好看,這裡博主列出轉換公司供大家參考:
當dim=0時,out[i,j]=input[index[i,j]][j] 當dim=1時,out[i,j]=input[i][index[i][j]]
簡單的數學運算
與Numpy一樣,Tensor也支援數學運算。這裡,博主列出了常用的數學運算函式,方便大家參考:
需要注意的是,上面表格所有的函式操作均會建立新的Tensor,如果不需要建立新的,使用這些函式的下劃線"_"版本。
示例如下:
t = torch.Tensor([[1, 2]]) t1 = torch.Tensor([[3], [4]]) t2 = torch.Tensor([5, 6]) # t+0.1*(t1/t2) print(torch.addcdiv(t, 0.1, t1, t2)) # t+0.1*(t1*t2) print(torch.addcmul(t, 0.1, t1, t2)) print(torch.pow(t,3)) print(torch.neg(t))
執行之後,效果如下:
上面的這些函式都很好理解,只有一個函式相信沒接觸機器學習的時候,不大容易理解。也就是sigmoid()啟用函式,它的公式如下:
歸併操作
簡單的理解,就是對張量進行歸併或者說合計等操作,這類操作的輸入輸出維度一般並不相同,而且往往是輸入大於輸出維度。而Tensor的歸併函式如下表所示:
示例程式碼如下所示:
t = torch.Tensor([[1, 2]]) t1 = torch.Tensor([[3], [4]]) t2 = torch.Tensor([5, 6]) # t+0.1*(t1/t2) print(torch.addcdiv(t, 0.1, t1, t2)) # t+0.1*(t1*t2) print(torch.addcmul(t, 0.1, t1, t2)) print(torch.pow(t,3)) print(torch.neg(t))
執行之後,效果如下:
需要注意的是,sum函式求和之後,dim的元素個數為1,所以要被去掉,如果要保留這個維度,則應當keepdim=True,預設為False。
比較操作
在量化交易中,我們一般會對股價進行比較。而Tensor張量同樣也支援比較的操作,一般是進行逐元素比較。具體函式如下表:
示例程式碼如下所示:
t = torch.Tensor([[1, 2]]) t1 = torch.Tensor([[3], [4]]) t2 = torch.Tensor([5, 6]) # t+0.1*(t1/t2) print(torch.addcdiv(t, 0.1, t1, t2)) # t+0.1*(t1*t2) print(torch.addcmul(t, 0.1, t1, t2)) print(torch.pow(t,3)) print(torch.neg(t))
執行之後,輸出如下:
矩陣運算
機器學習與深度學習中,存在大量的矩陣運算。與Numpy一樣常用的矩陣運算一樣,一種是逐元素相乘,一種是點積乘法。函式如下表所示:
這裡有3個主要的點積計算需要區分,dot()函式只能計算1維張量,mm()函式只能計算二維的張量,bmm只能計算三維的矩陣張量。示例如下:
# 計算1維點積 a = torch.Tensor([1, 2]) b = torch.Tensor([3, 4]) print(torch.dot(a, b)) # 計算2維點積 a = torch.randint(10, (2, 3)) b = torch.randint(6, (3, 4)) print(torch.mm(a, b)) # 計算3維點積 a = torch.randint(10, (2, 2, 3)) b = torch.randint(6, (2, 3, 4)) print(torch.bmm(a, b))
執行之後,輸出如下: