PyTorch中Tensor的基本用法与动手学深度学习的预备知识
同個(gè)人博客網(wǎng)站 : www.serendipper-x.cn
🐳🐳
-
第一部分是PyTorch中有關(guān)Tensor的一些基本用法,因?yàn)橹安]有系統(tǒng)學(xué)習(xí)過PyTorch,所以現(xiàn)在看書的同時(shí)慢慢學(xué)習(xí)PyTorch的知識(shí)
-
第二部分是原書的知識(shí)和一些自己的理解
- 一、PyTorch 中的Tensor
- 1.1 Tensor的創(chuàng)建
- 1.2 Tensor的數(shù)據(jù)類型
- 1.2.1 torch.FloatTensor
- 1.2.2 torch.IntTensor
- 1.2.3 torch.rand
- 1.2.4 torch.randn
- 1.2.5 torch.range
- 1.2.6 torch.zeros
- 1.3 Tensor的運(yùn)算
- 1.3.1 torch.abs
- 1.3.2 torch.add
- 1.3.3 torch.clamp
- 1.3.4 torch.div
- 1.3.5 torch.mul
- 1.3.6 torch.pow
- 1.3.7 torch.mm
- 1.3.8 torch.mv
- 二、原書
- 2.1 數(shù)據(jù)操作
- 2.1.1 索引
- 2.1.2 改變形狀
- 2.2 線性代數(shù)
- 2.3 廣播機(jī)制
- 2.4 運(yùn)算內(nèi)存開銷
- 2.5 Tensor和NumPy相互轉(zhuǎn)換
- 2.2.6 Tensor on GPU
張量 Tensor
張量包含了一個(gè)數(shù)據(jù)集合,這個(gè)數(shù)據(jù)集合就是原始值變形而來的,它可以是一個(gè)任何維度的數(shù)據(jù)。tensor的rank就是其維度。
Rank本意是矩陣的秩,不過Tensor Rank和Matrix Rank的意義不太一樣,這里就還叫Rank。Tensor Rank的意義看起來更像是維度,比如Rank =1就是向量,Rank=2 就是矩陣了,Rank = 0 就是一個(gè)值。
一、PyTorch 中的Tensor
在PyTorch中,**torch.Tensor**是存儲(chǔ)和變換數(shù)據(jù)的主要工具。Tensor 和 NumPy 的多維數(shù)組非常類似。
首先導(dǎo)入PyTorch
import torch1.1 Tensor的創(chuàng)建
創(chuàng)建一個(gè)5x3的未初始化的 Tensor
x = torch.empty(5, 3) print(x) tensor([[5.4880e+23, 4.5886e-41, 2.7434e-24],[3.0915e-41, 4.4842e-44, 0.0000e+00],[4.4842e-44, 0.0000e+00, 2.7450e-24],[3.0915e-41, 5.4880e+23, 4.5886e-41],[4.2039e-45, 0.0000e+00, 4.6243e-44]])創(chuàng)建一個(gè)5x3的隨機(jī)初始化的 Tensor
x = torch.rand(5, 3) # 這里rand的用法后面會(huì)講到 print(x) tensor([[0.7787, 0.8019, 0.3431],[0.1335, 0.3062, 0.2305],[0.6151, 0.5777, 0.2794],[0.4701, 0.6086, 0.9624],[0.6524, 0.6794, 0.8206]])創(chuàng)建一個(gè)5x3的long類型全0的 Tensor
x = torch.zeros(5, 3, dtype=torch.long) print(x) tensor([[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0]])直接根據(jù)數(shù)據(jù)創(chuàng)建
x = torch.tensor([5.5, 3]) print(x) tensor([5.5000, 3.0000])通過現(xiàn)有的 Tensor 來創(chuàng)建,此方法會(huì)默認(rèn)重用輸入 Tensor 的一些屬性,例如數(shù)據(jù)類型,除非自定義數(shù)據(jù)類型。
x = x.new_ones(5, 3, dtype=torch.float64) # new_ones 返回一個(gè)與size大小相同的用1填充的張量,默認(rèn)具有相同的torch.dtype和torch.device print(x)x = torch.randn_like(x, dtype=torch.float) # randn_like形狀與輸入的張量相同,指定新的數(shù)據(jù)類型 print(x) tensor([[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]], dtype=torch.float64) tensor([[-0.9532, 0.4367, -0.1972],[ 2.1078, 0.3750, -0.2939],[-0.3682, 1.3246, -0.7197],[-0.4119, 0.2093, -0.3431],[-1.7094, 0.0638, -0.4597]])通過 shape 或者size() 來獲取 Tensor 的形狀
print(x.size()) print(x.shape) torch.Size([5, 3]) torch.Size([5, 3])? 注意:返回的torch.Size其實(shí)就是一個(gè)tuple, 支持所有tuple的操作。
1.2 Tensor的數(shù)據(jù)類型
1.2.1 torch.FloatTensor
此變量用于生成數(shù)據(jù)類型為浮點(diǎn)型的 Tensor,傳遞給 torch.FloatTensor 的參數(shù)可以是一個(gè)列表,也可以是一個(gè)維度值。
a = torch.FloatTensor(2, 3) # 兩行三列 print(a) tensor([[5.4880e+23, 4.5886e-41, 5.4880e+23],[4.5886e-41, 1.4584e-19, 7.8458e+17]]) b = torch.FloatTensor([[2, 3], [4, 5]]) print(b, b.shape, b.dtype) tensor([[2., 3.],[4., 5.]]) torch.Size([2, 2]) torch.float321.2.2 torch.IntTensor
用于生成數(shù)據(jù)類型為整型的 Tensor,傳遞給 torch.IntTensor 的參數(shù)可以是一個(gè)列表,也可以是一個(gè)維度值。
a = torch.IntTensor(2, 3) print(a) tensor([[1726508320, 32745, 407958368],[ 22062, 1953384789, 1701869908]], dtype=torch.int32) b = torch.IntTensor([[2, 3], [4, 5]]) print(b, b.dtype) tensor([[2, 3],[4, 5]], dtype=torch.int32) torch.int321.2.3 torch.rand
用于生成數(shù)據(jù)類型為浮點(diǎn)型且維度指定的隨機(jī) Tensor,和在 Numpy 中使用 numpy.rand 生成隨機(jī)數(shù)的方法類似,隨機(jī)生成的浮點(diǎn)數(shù)據(jù)在 0~1區(qū)間均勻分布。
a = torch.rand(2, 3) print(a, a.dtype) tensor([[0.8055, 0.3392, 0.5802],[0.3333, 0.7156, 0.3415]]) torch.float321.2.4 torch.randn
用于生成數(shù)據(jù)類型為浮點(diǎn)型且維度指定的隨機(jī) Tensor,和在 Numpy 中使用 numpy.randn生成隨機(jī)數(shù)的方法類似,隨機(jī)生成的浮點(diǎn)數(shù)的取值滿足均值為0,方差為1的正態(tài)分布。
a = torch.randn(2, 3) print(a, a.dtype) tensor([[ 0.4737, 0.3686, -1.1102],[ 0.9147, -0.3446, -0.7511]]) torch.float321.2.5 torch.range
用于生成數(shù)據(jù)類型為浮點(diǎn)型且自定義其實(shí)范圍和結(jié)束范圍的 Tensor,所以傳遞給 torch.range 的參數(shù)有三個(gè),分別是范圍的起始值,范圍的結(jié)束值和步長,其中,步長用于指定從起始值到結(jié)束值的每步的數(shù)據(jù)間隔。
a = torch.range(2, 8, 3) print(a, a.dtype) tensor([2., 5., 8.]) torch.float32/opt/conda/lib/python3.7/site-packages/ipykernel_launcher.py:2: UserWarning: torch.range is deprecated in favor of torch.arange and will be removed in 0.5. Note that arange generates values in [start; end), not [start; end].1.2.6 torch.zeros
用于生成數(shù)據(jù)類型為浮點(diǎn)型且維度指定的 Tensor,不過這個(gè)浮點(diǎn)型的 Tensor 中的元素值全部為0
a = torch.zeros(3, 4) print(a, a.dtype) tensor([[0., 0., 0., 0.],[0., 0., 0., 0.],[0., 0., 0., 0.]]) torch.float321.3 Tensor的運(yùn)算
這里通常對 Tensor 數(shù)據(jù)類型的變量進(jìn)行運(yùn)算,來組合一些簡單或者復(fù)雜的算法,常用的 Tensor 運(yùn)算如下:
1.3.1 torch.abs
將參數(shù)傳遞到 torch.abs 后返回輸入?yún)?shù)的絕對值作為輸出,輸出參數(shù)必須是一個(gè) Tensor 數(shù)據(jù)類型的變量
a = torch.randn(2, 3) print(a) b = torch.abs(a) print(b) tensor([[-1.5257, 0.1174, -0.2927],[ 0.4662, 0.7019, 0.2605]]) tensor([[1.5257, 0.1174, 0.2927],[0.4662, 0.7019, 0.2605]])1.3.2 torch.add
將參數(shù)傳遞到 torch.add 后返回輸入?yún)?shù)的求和結(jié)果作為輸出,輸入?yún)?shù)既可以全部是 Tensor 數(shù)據(jù)類型的變量,也可以是一個(gè) Tensor 數(shù)據(jù)類型的變量,另一個(gè)是標(biāo)量。
a = torch.randn(2, 3) print(a)b = torch.randn(2, 3) print(b)c = torch.add(a, b) print(c)d = torch.randn(2, 3) print(d)e = torch.add(d, 10) print(e) tensor([[-1.5090, -1.1659, -0.7795],[ 0.8453, -0.0334, 0.2251]]) tensor([[-1.5168, -1.2602, 0.8775],[ 1.8206, -0.0880, -1.1371]]) tensor([[-3.0258, -2.4261, 0.0980],[ 2.6659, -0.1213, -0.9120]]) tensor([[0.2818, 1.4852, 2.0287],[1.1209, 1.6720, 1.0154]]) tensor([[10.2818, 11.4852, 12.0287],[11.1209, 11.6720, 11.0154]])可以指定輸出
result = torch.empty(2, 3) torch.add(a, b, out=result) print(result) tensor([[-3.0258, -2.4261, 0.0980],[ 2.6659, -0.1213, -0.9120]])關(guān)于加法還有兩種方式:
- 第一種,+號(hào)
- 第二種,inplace
? 注:PyTorch操作inplace版本都有后綴_, 例如x.copy_(y), x.t_()
print(a+b) tensor([[-3.0258, -2.4261, 0.0980],[ 2.6659, -0.1213, -0.9120]]) b.add_(a) print(b) tensor([[-3.0258, -2.4261, 0.0980],[ 2.6659, -0.1213, -0.9120]])1.3.3 torch.clamp
對輸入?yún)?shù)按照自定義的范圍進(jìn)行裁剪,最后將參數(shù)裁剪的結(jié)果作為輸出。所以輸入?yún)?shù)一共有三個(gè),分別是需要進(jìn)行裁剪的Tensor數(shù)據(jù)類型的變量、裁剪的上邊界和裁剪的下邊界,
具體的裁剪過程是:使用變量中的每個(gè)元素分別和裁剪的上邊界及裁剪的下邊界的值進(jìn)行比較,如果元素的值小于裁剪的下邊界的值,該元素就被重寫成裁剪的下邊界的值;
同理,如果元素的值大于裁剪的上邊界的值,該元素就被重寫成裁剪的上邊界的值。
a = torch.randn(2, 3) print(a)b = torch.clamp(a, -0.1, 0.1) print(b) tensor([[ 0.5965, 2.1073, -1.2866],[-0.1101, -1.6736, -2.2357]]) tensor([[ 0.1000, 0.1000, -0.1000],[-0.1000, -0.1000, -0.1000]])1.3.4 torch.div
將參數(shù)傳遞到 torch.div 后返回輸入?yún)?shù)的求商結(jié)果作為輸出,同樣,參與運(yùn)算的參數(shù)可以全部是 Tensor 數(shù)據(jù)類型的變量,也可以是 Tensor 數(shù)據(jù)類型的變量和標(biāo)量的組合。
a = torch.randn(2,3) print(a)b = torch.randn(2,3) print(b)c = torch.div(a,b) print(c)d = torch.randn(2,3) print(d)e = torch.div(d,10) print(e) tensor([[ 0.4518, 0.1334, 1.7579],[ 0.0349, -0.2346, 1.6790]]) tensor([[ 1.2516, -1.1198, 1.1351],[-0.6222, -0.6472, -0.0758]]) tensor([[ 0.3610, -0.1191, 1.5486],[ -0.0561, 0.3624, -22.1492]]) tensor([[ 0.2908, 0.0664, -1.4821],[ 0.4358, 0.3226, 1.0338]]) tensor([[ 0.0291, 0.0066, -0.1482],[ 0.0436, 0.0323, 0.1034]])1.3.5 torch.mul
將參數(shù)傳遞到 torch.mul 后返回輸入?yún)?shù)求積的結(jié)果作為輸出,參與運(yùn)算的參數(shù)可以全部是 Tensor 數(shù)據(jù)類型的變量,也可以是 Tensor 數(shù)據(jù)類型的變量和標(biāo)量的組合。
a = torch.randn(2, 3) print(a)b = torch.randn(2, 3) print(b)c = torch.mul(a, b) print(c)d = torch.randn(2, 3) print(d)e = torch.mul(d, 10) print(e) tensor([[ 0.5851, 0.2113, 0.6891],[ 1.1177, -0.0177, 1.5595]]) tensor([[ 0.9094, -0.0707, -0.3900],[ 0.2990, -0.9827, 0.7165]]) tensor([[ 0.5321, -0.0149, -0.2687],[ 0.3342, 0.0174, 1.1174]]) tensor([[-0.7012, 1.2348, 1.6156],[ 0.5412, 0.2345, -0.5753]]) tensor([[-7.0115, 12.3478, 16.1558],[ 5.4116, 2.3447, -5.7526]])1.3.6 torch.pow
將參數(shù)傳遞到 torch.pow 后返回輸入?yún)?shù)的求冪結(jié)果作為輸出,參與運(yùn)算的參數(shù)可以全部是 Tensor 數(shù)據(jù)類型的變量,也可以是 Tensor 數(shù)據(jù)類型的變量和標(biāo)量的組合。
a = torch.randn(2, 3) print(a)b = torch.pow(a, 2) print(b) tensor([[-0.9387, 1.0499, -1.6718],[-0.3190, -1.1677, -0.0666]]) tensor([[0.8812, 1.1024, 2.7948],[0.1018, 1.3635, 0.0044]])1.3.7 torch.mm
將參數(shù)傳遞到 torch.mm 后返回輸入?yún)?shù)的求積結(jié)果作為輸出,不過這個(gè)求積的方式和之前的 torch.mul運(yùn)算方式不太樣,
torch.mm 運(yùn)用矩陣之間的乘法規(guī)則進(jìn)行計(jì)算,所以被傳入的參數(shù)會(huì)被當(dāng)作矩陣進(jìn)行處理,參數(shù)的維度自然也要滿足矩陣乘法的前提條件,
即前一個(gè)矩陣的行數(shù)必須和后一個(gè)矩陣的列數(shù)相等,否則不能進(jìn)行計(jì)算。
a = torch.randn(2, 3) print(a)b = torch.randn(3, 2) print(b)b = torch.mm(a, b) print(b) tensor([[ 0.1701, 0.9539, -0.3128],[-0.2466, 2.4600, -1.6023]]) tensor([[-1.0573, -1.0292],[-0.2707, 0.2992],[-1.0913, -3.1058]]) tensor([[-0.0967, 1.0818],[ 1.3436, 5.9664]])1.3.8 torch.mv
將參數(shù)傳遞到 torch.mv 后返回輸入?yún)?shù)的求積結(jié)果作為輸出,torch.mv 運(yùn)用矩陣與向量之間的乘法規(guī)則進(jìn)行計(jì)算,被傳入的參數(shù)中的第1個(gè)參數(shù)代表矩陣,第2個(gè)參數(shù)代表向量,順序不能顛倒。
a = torch.randn(2, 3) print(a)b = torch.randn(3) print(b)c = torch.mv(a, b) print(c) tensor([[ 1.7745, 0.8665, -0.5622],[-0.6072, 0.5540, -1.0647]]) tensor([ 0.0553, -0.5526, -1.0924]) tensor([0.2335, 0.8233])二、原書
2.1 數(shù)據(jù)操作
部分操作已經(jīng)在前面提及
2.1.1 索引
索引出來的結(jié)果與原數(shù)據(jù)共享內(nèi)存,也即修改一個(gè),另一個(gè)會(huì)跟著修改。
x = torch.randn(2, 4) print(x) y = x[:, :3] print(y) y += 1 print(y) print(x[:, :3]) # 源tensor也被改了 print(x) tensor([[ 0.5706, 0.3683, 1.4869, 1.2791],[-0.1592, -1.7226, -1.1192, -0.9729]]) tensor([[ 0.5706, 0.3683, 1.4869],[-0.1592, -1.7226, -1.1192]]) tensor([[ 1.5706, 1.3683, 2.4869],[ 0.8408, -0.7226, -0.1192]]) tensor([[ 1.5706, 1.3683, 2.4869],[ 0.8408, -0.7226, -0.1192]]) tensor([[ 1.5706, 1.3683, 2.4869, 1.2791],[ 0.8408, -0.7226, -0.1192, -0.9729]])除了常用的索引選擇數(shù)據(jù)之外,PyTorch還提供了一些高級的選擇函數(shù):
| index_select(input, dim, index) | 在指定維度dim上選取,比如選取某些行、某些列 |
| masked_select(input, mask,out=None) | 根據(jù)布爾掩碼 (boolean mask) 索引輸入張量的 1D 張量 |
| nonzero(input) | 非0元素的下標(biāo) |
| gather(input, dim, index) | 根據(jù)index,在dim維度上選取數(shù)據(jù),輸出的size與index一樣 |
index_select
index_select(input,dim,index )參數(shù):
- input:索引的對象
- dim:表示從第幾維挑選數(shù)據(jù),類型為int值;0表示按行索引,1表示按列索引
- index:表示從第一個(gè)參數(shù)維度中的哪個(gè)位置挑選數(shù)據(jù),類型為torch.Tensor類的實(shí)例;
masked_select
masked_select(input,mask,out )參數(shù):
- input(Tensor) :需要進(jìn)行索引操作的輸入張量;
- mask(BoolTensor) :要進(jìn)行索引的布爾掩碼
- out(Tensor, optional) :指定輸出的張量。比如執(zhí)行 torch.zeros([2, 2], out = tensor_a),相當(dāng)于執(zhí)行 tensor_a = torch.zeros([2, 2]);
?? 注意:「 masked_select 函數(shù)最關(guān)鍵的參數(shù)就是布爾掩碼 mask,
傳入 mask 參數(shù)的布爾張量通過 True 和 False (或 1 和 0) 來決定輸入張量對應(yīng)位置的元素是否保留,
既然是一一對應(yīng)的關(guān)系,這就需要傳入 mask 中的布爾張量和傳入 input 中的輸入張量形狀要相同。」
mask = x.ge(0.5) print(mask) print(torch.masked_select(x, mask)) tensor([[ True, True, True, True],[ True, False, False, False]]) tensor([1.5706, 1.3683, 2.4869, 1.2791, 0.8408]) print(x) print(torch.nonzero(x)) tensor([[ 1.5706, 1.3683, 2.4869, 1.2791],[ 0.8408, -0.7226, -0.1192, -0.9729]]) tensor([[0, 0],[0, 1],[0, 2],[0, 3],[1, 0],[1, 1],[1, 2],[1, 3]])gather
gather(input, dim,index )參數(shù):
- input (Tensor) – 需要進(jìn)行索引操作的輸入張量;
- dim (int) – 表示從第幾維挑選數(shù)據(jù),類型為int值;
- index (LongTensor) – 要收集的元素的索引;
- out (Tensor, optional) – 指定輸出的張量。
2.1.2 改變形狀
用 view() 來改變 Tensor 的形狀:
?? 需要注意的是:-1所指的維度可以根據(jù)其他維度的值推出來,這個(gè)用法在很多地方都見過,應(yīng)該要記住
y = x.view(8) z = x.view(-1, 2) # -1所指的維度可以根據(jù)其他維度的值推出來 print(x.size(), y.size(), z.size()) torch.Size([2, 4]) torch.Size([8]) torch.Size([4, 2])🔥 view()返回的新 Tensor 與源 Tensor 雖然可能有不同的 size,但是是共享 data 的,也即更改其中的一個(gè),另外一個(gè)也會(huì)跟著改變。(顧名思義,view 僅僅是改變了對這個(gè)張量的觀察角度,內(nèi)部數(shù)據(jù)并未改變)
x += 1 print(x) print(y) tensor([[2.5706, 2.3683, 3.4869, 2.2791],[1.8408, 0.2774, 0.8808, 0.0271]]) tensor([2.5706, 2.3683, 3.4869, 2.2791, 1.8408, 0.2774, 0.8808, 0.0271])所以如果我們想返回一個(gè)真正新的副本(即不共享data內(nèi)存)該怎么辦呢?
Pytorch還提供了一個(gè) reshape() 可以改變形狀,但是此函數(shù)并不能保證返回的是其拷貝,所以不推薦使用。推薦先用 clone 創(chuàng)造一個(gè)副本然后再使用 view。
x_cp = x.clone().view(8) x -= 1 print(x) print(x_cp) tensor([[ 1.5706, 1.3683, 2.4869, 1.2791],[ 0.8408, -0.7226, -0.1192, -0.9729]]) tensor([2.5706, 2.3683, 3.4869, 2.2791, 1.8408, 0.2774, 0.8808, 0.0271])? 使用 clone 還有一個(gè)好處是會(huì)被記錄在計(jì)算圖中,即梯度回傳到副本時(shí)也會(huì)傳到源 Tensor
另外一個(gè)常用的函數(shù)就是 item(), 它可以將一個(gè)標(biāo)量 Tensor 轉(zhuǎn)換成一個(gè)Python number:
x = torch.randn(1) print(x) print(x.item()) tensor([1.0600]) 1.0599588155746462.2 線性代數(shù)
另外,PyTorch還支持一些線性函數(shù),這里提一下,免得用起來的時(shí)候自己造輪子,具體用法參考官方文檔。如下表所示:
| trace | 對角線元素之和(矩陣的跡) |
| diag | 對角線元素 |
| triu/tril | 矩陣的上三角/下三角,可指定偏移量 |
| mm/bmm | 矩陣乘法,batch的矩陣乘法 |
| addmm/addbmm/addmv/addr/baddbmm… | 矩陣運(yùn)算 |
| t | 轉(zhuǎn)置 |
| dot/cross | 內(nèi)積/外積 |
| inverse | 求逆矩陣 |
| svd | 奇異值分解 |
2.3 廣播機(jī)制
當(dāng)對兩個(gè)形狀不同的 Tensor 按元素運(yùn)算時(shí),可能會(huì)觸發(fā)廣播(broadcasting)機(jī)制:先適當(dāng)復(fù)制元素使這兩個(gè) Tensor 形狀相同后再按元素運(yùn)算。
x = torch.arange(1, 3).view(1, 2) print(x) y = torch.arange(1, 4).view(3, 1) print(y) print(x + y) tensor([[1, 2]]) tensor([[1],[2],[3]]) tensor([[2, 3],[3, 4],[4, 5]])由于 x 和 y 分別是1行2列和3行1列的矩陣,如果要計(jì)算 x + y,那么 x 中第一行的2個(gè)元素被廣播(復(fù)制)到了第二行和第三行,
而 y 中第一列的3個(gè)元素被廣播(復(fù)制)到了第二列。如此,就可以對2個(gè)3行2列的矩陣按元素相加。
2.4 運(yùn)算內(nèi)存開銷
前面說了,索引操作是不會(huì)開辟新內(nèi)存的,而像y = x + y 這樣的運(yùn)算是會(huì)新開內(nèi)存的,然后將y指向新內(nèi)存。
為了演示這一點(diǎn),我們可以使用Python自帶的 id 函數(shù):如果兩個(gè)實(shí)例的ID一致,那么它們所對應(yīng)的內(nèi)存地址相同;反之則不同。
x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) id_before = id(y) y = y + x print(id(y) == id_before) # False False如果想指定結(jié)果到原來的 y 的內(nèi)存,我們可以使用前面介紹的索引來進(jìn)行替換操作。在下面的例子中,我們把x + y的結(jié)果通過 [:] 寫進(jìn) y 對應(yīng)的內(nèi)存中。
x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) id_before = id(y) y[:] = y + x print(id(y) == id_before) # True True我們還可以使用運(yùn)算符全名函數(shù)中的 out 參數(shù)或者自加運(yùn)算符 += (也即 add_() )達(dá)到上述效果,例如 torch.add(x, y, out=y)和 y += x(y.add_(x))。
x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) id_before = id(y) torch.add(x, y, out=y) # y += x, y.add_(x) print(id(y) == id_before) # True True? 注:雖然 view 返回的 Tensor 與源 Tensor 是共享data的,但是依然是一個(gè)新的 Tensor(因?yàn)?Tensor 除了包含data外還有一些其他屬性),二者id(內(nèi)存地址)并不一致。
2.5 Tensor和NumPy相互轉(zhuǎn)換
我們很容易用 numpy() 和 from_numpy() 將 Tensor 和 NumPy 中的數(shù)組相互轉(zhuǎn)換。
但是需要注意的一點(diǎn)是: 這兩個(gè)函數(shù)所產(chǎn)生的的 Tensor 和 NumPy 中的數(shù)組共享相同的內(nèi)存(所以他們之間的轉(zhuǎn)換很快),改變其中一個(gè)時(shí)另一個(gè)也會(huì)改變!!!
? 還有一個(gè)常用的將NumPy中的array轉(zhuǎn)換成Tensor的方法就是torch.tensor(), 需要注意的是,此方法總是會(huì)進(jìn)行數(shù)據(jù)拷貝(就會(huì)消耗更多的時(shí)間和空間),所以返回的Tensor和原來的數(shù)據(jù)不再共享內(nèi)存。
Tensor轉(zhuǎn)NumPy
使用 numpy()將 Tensor 轉(zhuǎn)換成 NumPy 數(shù)組:
a = torch.ones(5) b = a.numpy() print(a, b)a += 1 print(a, b) b += 1 print(a, b) tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.] tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.] tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]NumPy數(shù)組轉(zhuǎn)Tensor
使用from_numpy() 將 NumPy 數(shù)組轉(zhuǎn)換成 Tensor :
import numpy as np a = np.ones(5) b = torch.from_numpy(a) print(a, b)a += 1 print(a, b) b += 1 print(a, b) [1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64) [2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64) [3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)所有在CPU上的 Tensor(除了 CharTensor)都支持與 NumPy 數(shù)組相互轉(zhuǎn)換。
此外上面提到還有一個(gè)常用的方法就是直接用 torch.tensor()將 NumPy 數(shù)組轉(zhuǎn)換成 Tensor,
需要注意的是該方法總是會(huì)進(jìn)行數(shù)據(jù)拷貝,返回的 Tensor 和原來的數(shù)據(jù)不再共享內(nèi)存。
c = torch.tensor(a) a += 1 print(a, c) [4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)2.2.6 Tensor on GPU
用方法 to() 可以將 Tensor 在CPU和GPU(需要硬件支持)之間相互移動(dòng)。
# 以下代碼只有在PyTorch GPU版本上才會(huì)執(zhí)行 if torch.cuda.is_available():device = torch.device("cuda") # GPUy = torch.ones_like(x, device=device) # 直接創(chuàng)建一個(gè)在GPU上的Tensorx = x.to(device) # 等價(jià)于 .to("cuda")z = x + yprint(z)print(z.to("cpu", torch.double)) # to()還可以同時(shí)更改數(shù)據(jù)類型總結(jié)
以上是生活随笔為你收集整理的PyTorch中Tensor的基本用法与动手学深度学习的预备知识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 视觉感知与认知
- 下一篇: linux的基础知识——模型结构和数据包