筆者PyTorch的全部簡單教程請訪問:http://www.lxweimin.com/nb/48831659
PyTorch教程-1:PyTorch中的Tensor基礎
首先,引入PyTorch
的模塊:
import torch
設置運算資源
使用 torch.cuda.is_available()
來判斷設備上的GPU是否可用,如果可用則返回True
,使用 torch.device()
則可以參數指定計算資源:
參數為
"cpu"
表示使用CPU計算參數為
"cuda"
表示使用GPU計算,默認會使用第一塊GPU,即"cuda:0"
-
對于多GPU的設備,可以通過設置
"cuda:N"
來指定使用第幾塊GPU,第一塊GPU是"cuda:0"
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(device)
cuda
創建張量(tensors)
Pytorch中的基本數據類型是tensors(張量),和numpy中的ndarrays是非常相似的,而且可以互相轉換,只是numpy中的多維數組只能在CPU上進行運算,而tensor則是PyTorch中設計的一種可以用于GPU高速運算的數據類型。
和numpy相似,PyTorch中也有很多方法來創建張量,這些方法的統一的幾個常用參數為:
- 前N個參數依次傳入整數:張量的維度
-
dtype
:數據類型,默認為torch.float32
參數 數據類型 torch.int 32位整數(等同于torch.int32) torch.int8, torch.int16, torch.int32, torch.int64 8位、16位、32位、64位整數 torch.float 32位浮點數(等同于torch.float32) torch.float16, torch.float32, torch.float64 16位、32位、64位浮點數 torch.double 64位浮點數(等同于torch.float64) -
device
:張量的目標存儲設備,默認為CPU
創建張量的常用方法有:
torch.tensor
:直接從數據創建,比如可以傳入(多維)listtorch.empty
:創建一個空的tensortorch.rand
:創建一個0-1之間隨機數的tensortorch.ones
:創建全1的tensor-
torch.zeros
:創建全0的tensor一些例子:
x = torch.tensor([1,2,3]) y = torch.rand(2,2,dtype=torch.float) z = torch.ones(2,2,dtype=torch.int,device=device) print(x) print(y) print(z)
tensor([1, 2, 3]) tensor([[0.4366, 0.6651], [0.9753, 0.7331]]) tensor([[1, 1], [1, 1]], device='cuda:0', dtype=torch.int32)
-
torch.full
:這個方法和上述方法擁有不同的參數設置,其將前N個用于指定維數的參數換成:第一個參數為tuple指定維數,第二個參數為指定的值,創建一個該維度大小的全是指定值的tensor,但是同樣有dtype
和device
等參數x=torch.full((2,3),1.2,dtype=torch.float) print(x)
tensor([[1.2000, 1.2000, 1.2000], [1.2000, 1.2000, 1.2000]])
基于已有的張量創建新的張量,可以使用new_
系列的方法,和上面的方法類似,new_
系列的方法在原有的方法前加上new_
,是一個tensor實例的成員方法,傳入的參數和上述一致,如果沒有指定的參數(指dtype
、device
等參數)則繼承原來的張量,但是維度信息必須傳入:
```python
x = torch.rand(4,3,dtype=torch.float16,device=device)
y = x.new_ones(x.size(),dtype=torch.int16)
print(x)
print(y)
```
------
```
tensor([[0.5366, 0.9004, 0.8706],
[0.9712, 0.2258, 0.4180],
[0.7842, 0.9976, 0.4412],
[0.5376, 0.7261, 0.4844]], device='cuda:0', dtype=torch.float16)
tensor([[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]], device='cuda:0', dtype=torch.int16)
```
new_
系列的方法有:
torch.new_tensor
torch.new_empty
torch.new_ones
torch.new_zeros
torch.new_full
張量的運算
基本運算的幾種方式
張量之間的基本運算有幾種不同的表達方式,這里以加法運算為例,列舉一下幾種不同方式,比如兩個張量x
和y
:
使用運算符運算:
x+y
使用torch的方法:
torch.add(x,y)
使用torch的方法時,傳入
out
參數來設置結果的賦值對象:torch.add(x,y,out=z)
-
使用
_
結尾的方法,完成類似于+=
的操作:y.add_(x)
x = torch.rand(3,2) y = torch.rand(3,2) z = x+y # method 1 z = torch.add(x,y) # method 2 torch.add(x,y,out=z) # method 3 y.add_(x) # method 4
常用的一些操作
一些張量的重要操作列在下邊:
獲取張量的形狀:使用
Tensor.size()
或者Tensor.shape
獲取張量的形狀,返回的是一個tuple獲取張量的維數:使用
Tensor.dim()
獲取張量的維數切片操作:tensors的切片操作和numpy完全一致。(筆者另有一篇詳細介紹關于numpy和list的索引、切片操作的文章,請移步:http://www.lxweimin.com/p/dd166725a2c3)
-
改變形狀:使用
Tensor.view
方法可以改變一個張量的形狀,使用參數-1
表示該維度的大小取決于其他維度x = torch.rand(4,6) print(x.size()) y = x.view(2,12) print(y.size()) z = x.view(8,-1) print(z.size())
torch.Size([4, 6]) torch.Size([2, 12]) torch.Size([8, 3])
-
從單元素的張量提出該單獨元素的值:對于只包含一個元素的Tensor,使用
Tensor.item()
獲取該元素x = torch.rand(1) print(x) print(x.item())
tensor([0.5759]) 0.5759033560752869
其他的操作
Tensor還有很多各種各樣的操作、方法、屬性等,參考完整的列表:
https://pytorch.org/docs/stable/torch.html
Tensor與其他數據類型的轉換
PyTorch的Tensor與Numpy的ndarray之間的轉換
假設 tensor_x
是一個Tensor,ndarray_y
是一個ndarray:
-
Tensor
轉ndarray
:使用Tensor.numpy()
將一個tensor
轉換成一個numpy
的ndarray
對象tensor_x = torch.rand(2,3) print(type(tensor_x)) ndarray_y = tensor_x.numpy() print(type(ndarray_y))
<class 'torch.Tensor'> <class 'numpy.ndarray'>
-
ndarray
轉Tensor
:使用torch.from_numpy(ndarray)
將一個ndarray
轉換成tensor
ndarray_y = np.ones((2,3)) print(type(ndarray_y)) tensor_x = torch.from_numpy(ndarray_y) print(type(tensor_x))
<class 'numpy.ndarray'> <class 'torch.Tensor'>
PyTorch的Tensor與Python的list之間的轉換
-
list
轉Tensor
:使用torch.tensor
或者torch.Tensor
均可:list_a = [[1,2,3],[4,5,6]] tensor_x = torch.tensor(list_a) tensor_y = torch.Tensor(list_a) print(type(tensor_x)) print(type(tensor_y))
<class 'torch.Tensor'> <class 'torch.Tensor'>
-
Tensor
轉list
:只能先轉換成numpy
數組,再通過numpy
數組的tolist
方法轉換成list
,沒有直接轉換的方法list_b = tensor_x.numpy().tolist() print(type(list_b))
<class 'list'>
將變量分配到GPU計算資源
我們已經知道如何設置計算資源,比如使用如下代碼返回一個可用的設備(即優先使用GPU),如何將一個Tensor分配到對應的計算資源呢?有兩種常用的方法:
-
在創建
Tensor
時設置device
參數將創建的變量直接發送到對應的設備,device
參數默認為"cpu"
:device = torch.device("cuda" if torch.cuda.is_available() else "cpu") x = torch.rand(4,3,device=device) print(x)
tensor([[0.1092, 0.7485, 0.1401], [0.2976, 0.3415, 0.6248], [0.7625, 0.6632, 0.7994], [0.8400, 0.1557, 0.6348]], device='cuda:0')
-
使用
tensor.to(device)
方法將該tensor
發送到目標設備,to
方法接收的第一個參數為一個指定目標設備的字符串,第二個參數可以設置數據類型,默認為tensor
原本的數據類型device = torch.device("cuda" if torch.cuda.is_available() else "cpu") x = torch.rand(4,3,device=device) y = x.to("cpu") print(y) print(y.device) z = x.to("cpu",torch.double) print(z) print(z.device) print(z.dtype)
tensor([[0.3537, 0.3610, 0.1814], [0.8401, 0.1496, 0.6197], [0.7640, 0.5794, 0.1897], [0.6594, 0.3619, 0.3482]]) cpu tensor([[0.3537, 0.3610, 0.1814], [0.8401, 0.1496, 0.6197], [0.7640, 0.5794, 0.1897], [0.6594, 0.3619, 0.3482]], dtype=torch.float64) cpu torch.float64
需要注意的是,兩個張量之間如果發生運算,必須保證兩個張量在統一運算資源下,否則會報錯,所以有時需要通過上述方法進行調整。比如如下的代碼驗證了這一點:
x = torch.rand(3,2,device="cpu")
y = torch.rand(3,2,device="cuda")
try:
z = x + y
except RuntimeError as e:
print("Meet error because the two tensors aren't at the same device: \n{}".format(e))
Meet error because the two tensors aren't at the same device:
Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!