
目錄
- Tensor
- 創建Tensor
- 修改Tensor維度
- 截取元素
- 簡單的數學運算
- 歸并操作
- 比較操作
- 矩陣運算
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(*size) | 直接從引數構造,支持list,Numpy陣列 |
| eye(row,column) | 創建指定行列的二維Tensor |
| linspace(start,end,steps) | 從start到end,均勻切分成steps份 |
| logspace(start,end,steps) | 從10^start到10^and,均分成steps份 |
| rand/randn(*size) | 生成[0,1)均勻分布/標準正態分布的資料 |
| ones(*size) | 生成指定shape全為1的張量 |
| zeros(*size) | 生成指定shape全為0的張量 |
| ones_like(t) | 回傳與t的shape相同的張量,且元素全為1 |
| zeros_like(t) | 回傳與t的shape相同的張量,且元素全為0 |
| arange(start,end,step) | 在區間[start,end)上,以間隔step生成一個序列張量 |
| from_Numpy(ndarray) | 從ndarray創建一個Tensor |
這里需要注意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()))
運行之后,效果如下:

可以看到,tensor與Tensor生成的值的型別就不同,而且t2(Tensor)回傳一個大小為1的張量,而t1(tensor)回傳的就是1這個值,
其他示例如下:
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一樣有維度的修改函式,具體的方法如下表所示:
| 函式 | 意義 |
|---|---|
| size() | 回傳張量的shape,即維度 |
| numel(input) | 計算張量的元素個數 |
| view(*shape) | 修改張量的shape,但View回傳的物件與源張量共享記憶體,修改一個,另一個也被修改,Reshape將生成新的張量,而不要求源張量是連續的,View(-1)展平陣列 |
| resize | 類似與view,但在size超出時,會重新分配記憶體空間 |
| item | 若張量為單元素,則回傳Python的標量 |
| unsqueeze | 在指定的維度增加一個“1” |
| squeeze | 在指定的維度壓縮一個“1” |
示例代碼如下所示:
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張量,是為了使用里面的資料,那么就不可避免的需要獲取資料進行處理,具體截取元素的方式如表:
| 函式 | 意義 |
|---|---|
| index_select(input,dim,index) | 在指定維度選擇一些行或者列 |
| nonzero(input) | 獲取非0元素的下標 |
| masked_select(input,mask) | 使用二元值進行選擇 |
| gather(input,dim,index) | 在指定維度上選擇資料,輸出的維度與index一致(index的型別必須是LongTensor型別的) |
| scatter_(input,dim,index,src) | 為gatter的反操作,根據指定索引補充資料(將src中資料根據index中的索引按照dim的方向填進input中) |
示例代碼如下所示:
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也支持數學運算,這里,博主列出了常用的數學運算函式,方便大家參考:
| 函式 | 意義 |
|---|---|
| abs/add | 絕對值/加法 |
| addcdiv(t,v,t1,t2) | t1與t2逐元素相除后,乘v加t |
| addcmul(t,v,t1,t2) | t1與t2逐元素相乘后,乘v加t |
| ceil/floor | 向上取整/向下取整 |
| clamp(t,min,max) | 將張量元素限制在指定區間 |
| exp/log/pow | 指數/對數/冪 |
| mul(或*)/neg | 逐元素乘法/取反 |
| sigmoid/tanh/softmax | 激活函式 |
| sign/sqrt | 取符號/開根號 |
需要注意的是,上面表格所有的函式操作均會創建新的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的歸并函式如下表所示:
| 函式 | 意義 |
|---|---|
| cumprod(t,axis) | 在指定維度對t進行累積 |
| cumsum | 在指定維度對t進行累加 |
| dist(a,b,p=2) | 回傳a,b之間的p階范數 |
| mean/median | 均值/中位數 |
| std/var | 標準差/方差 |
| norm(t,p=2) | 回傳t的p階范數 |
| prod(t)/sum(t) | 回傳t所有元素的積/和 |
示例代碼如下所示:
t = torch.linspace(0, 10, 6)
a = t.view((2, 3))
print(a)
b = a.sum(dim=0)
print(b)
b = a.sum(dim=0, keepdim=True)
print(b)
運行之后,效果如下:

需要注意的是,sum函式求和之后,dim的元素個數為1,所以要被去掉,如果要保留這個維度,則應當keepdim=True,默認為False,
比較操作
在量化交易中,我們一般會對股價進行比較,而Tensor張量同樣也支持比較的操作,一般是進行逐元素比較,具體函式如下表:
| 函式 | 意義 |
|---|---|
| equal | 比較張量是否具有相同的shape與值 |
| eq | 比較張量是否相等,支持broadcast |
| ge/le/gt/lt | 大于/小于比較/大于等于/小于等于比較 |
| max/min(t,axis) | 回傳最值,若指定axis,則額外回傳下標 |
| topk(t,k,dim) | 在指定的dim維度上取最高的K個值 |
示例代碼如下所示:
t = torch.Tensor([[1, 2], [3, 4]])
t1 = torch.Tensor([[1, 1], [4, 4]])
# 獲取最大值
print(torch.max(t))
# 比較張量是否相等
# equal直接回傳True或False
print(torch.equal(t, t1))
# eq回傳對應位置是否相等的布林值與兩者維度相同
print(torch.eq(t, t1))
# 取最大的2個元素,回傳索引與值
print(torch.topk(t, 1, dim=0))
運行之后,輸出如下:

矩陣運算
機器學習與深度學習中,存在大量的矩陣運算,與Numpy一樣常用的矩陣運算一樣,一種是逐元素相乘,一種是點積乘法,函式如下表所示:
| 函式 | 意義 |
|---|---|
| dot(t1,t2) | 計算t1與t2的點積,但只能計算1維張量 |
| mm(mat1,mat2) | 計算矩陣乘法 |
| bmm(tatch1,batch2) | 含batch的3D矩陣乘法 |
| mv(t1,v1) | 計算矩陣與向量乘法 |
| t | 轉置 |
| svd(t) | 計算t的SVD分解 |
這里有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))
運行之后,輸出如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291771.html
標籤:AI
