PyTorch基礎

      在〈PyTorch基礎〉中尚無留言

torch 就是一台可以啟動 GPU 進行數學運算的計算機。torch 一樣需把資料交由 cuda 進行運算,所以 cuda 還是必需先安裝。

PyTorch 是 2017 年初由 Facebook 開發,基於 Torch 之上的開源深度學習框架,因語法簡潔優雅,概念直觀,容易上手,一推出就瓜分 Tensorflow 的市場。

安裝套件

安裝 Pytorch 時,若使用 Python 預設的網址下載,會安裝到無法啟動 cuda 的版本。

所以必需使用 –index-url 指定到 Pytorch 的官網下載與我們 cuda 相同的版本。本例因安裝 cuda 11.8 版本,所以 –index-url 亦需指定 cu118。

pip install torch torchvision torchaudio
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 --no-cache-dir

也可以手動指定想要下載的版本

pip install torch==2.0.1+cu118 torchvision==0.15.2+cu118 torchaudio===2.0.2+cu118 -f https://download.pytorch.org/whl/cu118/torch_stable.html --no-cache-dir

如果電腦的記憶体只有 16 G 以下,又同時開啟二個專案以上,安裝上面的 Pytorch 時會出現 Memory error例外,甚至當機連滑鼠鍵盤都不會動,加上 “–no-cache-dir” 即可解決。

測試是否有安裝成功,可使用如下指令,如果印出 “True”,表示安裝成功。

當然如果沒有 nVidia 顯卡的人,因為 CUDA 安裝不起來,所以就算 torch 安裝成功,結果還是 False。

import torch
print(torch.cuda.is_available())
結果:
True

基本格式

numpy 的基本格式是 np.array,中文稱”陣列”。而陣列裏的資料可以是 np.int8, np.int32, np.float32…。

torch 的基本格式為 torch.Tensor,中文叫”張量”。張量又細分為 torch.tensor(),torch.Tensor(), torch.FlatTensor(), torch.DoubleTensor()。張量的資料型態可以是 torch.int8. int32, float32….

torch.tensor()

torch.tensor() 是最廣泛被使用的格式。

這也是唯一可以產生出整數型態的 Tensor,也是唯一可以產生純量的資料。整數若沒有指定型態,預設是 torch.int64。

import torch
a=torch.tensor(10)#預設為torch.int64
b=torch.tensor(10, dtype=torch.int32)
print(a.dtype)
print(a)
print(b)

結果:
torch.int64
tensor(10)
tensor(10, dtype=torch.int32)

也可以產生純量的浮點數。浮點數若沒有指定型態,預設是 torch.float32。

import torch
a=torch.tensor(10.)#預設是 torch.float32
b=torch.tensor(10, dtype=torch.float64)
print(a.dtype)
print(a)
print(b)

結果:
torch.float32
tensor(10.)
tensor(10., dtype=torch.float64)

也可以產生整數或浮點數的陣列

import torch
a=torch.tensor([1,2,3], dtype=torch.int32)
b=torch.tensor([1,2,3], dtype=torch.float64)
print(a)
print(b)
結果:
tensor([1, 2, 3], dtype=torch.int32)
tensor([1., 2., 3.], dtype=torch.float64)

torch.Tensor()

參數只能是陣列,且不能指定 dtype,也就資料型態只能是 torch.float32。

import torch
a=torch.Tensor([1,2,3])
print(a)
結果:
tensor([1., 2., 3.])

torch.FloatTensor()

torch.FloatTensor([2,10]) 裏的參數如果是 list,那就跟 torch.Tensor() 一模一樣。

import torch
a=torch.Tensor([2,10])
b=torch.FloatTensor([2,10])
print(a)
print(b)

結果:
tensor([ 2., 10.])
tensor([ 2., 10.])

但如果是 torch.FloatTensor(2, 10),則是產生 2*10 二維的陣列,裏面預設值為 0。此法不常用,因為裏面的值雖是 0,但卻有小數點誤差的問題,一般都會使用 torch.zeros([2,10],dtype=torch.float32)。

c=torch.FloatTensor(2,10)
print(c)

結果 :
tensor([[8.7244e-39, 9.2755e-39, 1.0653e-38, 1.0837e-38, 1.0102e-38, 8.4490e-39,
         9.6429e-39, 8.4490e-39, 9.6429e-39, 9.2755e-39],
        [1.0286e-38, 9.0919e-39, 8.9082e-39, 9.2755e-39, 8.4490e-39, 8.9082e-39,
         1.0286e-38, 1.0194e-38, 9.9184e-39, 9.0000e-39]])

此時可以利用 c 來產生 亂數

import pylab as plt
import torch
plt.figure(figsize=(12,6))
c=torch.FloatTensor(2,1000)
plt.subplot(1,2,1)
#產生平均分佈亂數
c.uniform_(0,1)
plt.scatter(c[0,:], c[1,:], s=1)

plt.subplot(1,2,2)
#產生常態分佈亂數
c.normal_(0,1)
plt.scatter(c[0,:], c[1,:], s=1)
plt.savefig('torch_random.jpg')
plt.show()

torch.DoubleTensor()

變數型態為 torch.float64 

import torch
a=torch.DoubleTensor([1,2,3])
print(a)
結果 :
tensor([1., 2., 3.], dtype=torch.float64)

同樣的,如果參數為 torch.DoubleTensor(2,10),則產生 2*10 的二維陣列。

四則運算

Tensor 可以作四則運算,包含 +-*/%,不同型態可以相互運算。運算後的結果,為最大的資料型態。

但如果整數/整數,結果是 torch.float32。

import torch
a=torch.tensor([1,2,3], dtype=torch.int32)
b=torch.DoubleTensor([1,2,3])
c=torch.tensor([2,4,5], dtype=torch.int32)
print(a*b)
print(a/c)
結果:
tensor([1., 4., 9.], dtype=torch.float64)
tensor([0.5000, 0.5000, 0.6000])

型態轉換

torch 的型態可以互相轉換,常用的有 .char(), .byte()….,也可以使用 .type(),如下代碼說明

import torch as tc
a=tc.tensor([1., 2., 3.])
print(a.char())#int8
print(a.byte())#uint8
print(a.short())#int16
print(a.int())#int32
print(a.long())#int64
print(a.float())#float32
print(a.double())#float64

print(a.type(tc.int8))
結果 : 
tensor([1, 2, 3], dtype=torch.int8)
tensor([1, 2, 3], dtype=torch.uint8)
tensor([1, 2, 3], dtype=torch.int16)
tensor([1, 2, 3], dtype=torch.int32)
tensor([1, 2, 3])
tensor([1., 2., 3.])
tensor([1., 2., 3.], dtype=torch.float64)
tensor([1, 2, 3], dtype=torch.int8)

Process finished with exit code 0

矩陣相乘

矩陣相乘可用 torch.mm(a, b),請注意 a, b 二者必需滿足矩陣相乘的規則,也就是維度的中間必需相同。
比如 [5, 3] * [3,5] ,第一個矩陣維度是 5*3,第二個矩陣維度是 3*5,中間都是 3 才能相乘。

另外請特別注意,二者的型態必需相同。由下面的代碼中,a 變數沒有指定型態時,預設就是 int64。

import torch
a=torch.tensor([[1,2],[3,4],[5,6]])
b=torch.tensor([[1,2,3],[4,5,6]], dtype=torch.int64)
print(torch.mm(a,b))
結果 :
tensor([[ 9, 12, 15],
[19, 26, 33],
[29, 40, 51]])

numpy 互轉

Tensor 轉成 numpy,只需使用 numpy()即可,如下

import torch
a=torch.tensor([[1,2,3],[4,5,6]], dtype=torch.float32)
print(a.numpy())
結果 :
[[1. 2. 3.]
[4. 5. 6.]]

numpy 轉成 Tensor,必需使用 torch.from_numpy()

import torch
import numpy as np
a=np.array([[1,2,3],[4,5,6]], dtype=np.float64)
b=torch.from_numpy((a))
print(b)
結果 :
tensor([[1., 2., 3.],
[4., 5., 6.]], dtype=torch.float64)

維度

取得 Tensor 的維度,可以 shape 或 size(),二者的結果都是 torch.Size([2,3])。

shape 是 Tensor 的屬性,取得某一維的資料需使用 shape[index]。
size() 是 Tensor 裏的方法,取得某一維的資料需使用 size(index)

import torch
a=torch.tensor([[1,2,3],[4,5,6]], dtype=torch.float64)
print(a.shape, a.shape[0])
print(a.size(), a.size(0))
結果 :
torch.Size([2, 3]) 2
torch.Size([2, 3]) 2

陣列工具

產生陣列的工具有 torch.zeros(),torch.ones(),torch.rand(),torch.randn()。

每個工具中的 shape 可以是多參數、list 或是 tuple

import torch
a=torch.zeros(2,5)#多參數
print(a)
b=torch.zeros([2,5])#list
print(b)
c=torch.zeros((2,5))#tuple
print(c)
結果:
tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])

torch.randint

randint  會產生整數亂數,參數如下 troch.randint(最低,最高, [維度])

import torch
a=torch.randint(0, 100, [10])
print(a)
結果 :
tensor([50, 46, 12, 75, 19, 45, 62, 91, 91, 86])

torch.rand

產生平均分佈亂數,其值介於 0~1之間

import torch
import pylab as plt
a=torch.rand(2,1000)
plt.scatter(a[0,:], a[1,:], s=1)
plt.show()

torch.randn

torch.randn 是標準常態分佈,接近 0 的地方機率愈大。

import torch
import pylab as plt
a=torch.randn(2,1000)
plt.scatter(a[0,:], a[1,:], s=1)
plt.show()

torch.normal

torch.normal (中心值, 變異數, shape) 同 torch.randn,但可以更改中心值及變異數的正負範圍。

底下的代碼中,接近 50 的幾率最大,左右二邊的邊界是 -150 及 150。

import torch
import pylab as plt
a=torch.normal(50,100,(2,1000))
plt.scatter(a[0, :], a[1, :], s=1)
plt.show()

torch.linspace

同 np.linspace(起始值, 結束值, 切割數)

import torch
a=torch.linspace(0,10,10)
print(a)
結果 :
tensor([ 0.0000, 1.1111, 2.2222, 3.3333, 4.4444, 5.5556, 6.6667, 7.7778,
8.8889, 10.0000])

torch.arange

同 np.arange(起始值, 結束值, 步進值),其值可以是浮點數,但最後不包含結束值。

import torch
a=torch.arange(0,5,0.1)
print(a)
結果 :
tensor([0.0000, 0.1000, 0.2000, 0.3000, 0.4000, 0.5000, 0.6000, 0.7000, 0.8000,
0.9000, 1.0000, 1.1000, 1.2000, 1.3000, 1.4000, 1.5000, 1.6000, 1.7000,
1.8000, 1.9000, 2.0000, 2.1000, 2.2000, 2.3000, 2.4000, 2.5000, 2.6000,
2.7000, 2.8000, 2.9000, 3.0000, 3.1000, 3.2000, 3.3000, 3.4000, 3.5000,
3.6000, 3.7000, 3.8000, 3.9000, 4.0000, 4.1000, 4.2000, 4.3000, 4.4000,
4.5000, 4.6000, 4.7000, 4.8000, 4.9000])

平均數及標準差

計算平均數,注意要計算的數值必需是小數(float32, float64)。 

import torch
a=torch.randint(0, 100, [10], dtype=torch.float32)
print(a)
print(f'平均數 : {torch.mean(a)}')
print(f'標準差 : {torch.std(a)}')

結果 : 
tensor([27., 48., 87., 74.,  4., 60., 97., 94., 50., 43.])
平均數 : 58.400001525878906
標準差 : 30.152206420898438

啟用GPU

為了偵測是否有GPU,需先設定 deive

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

torch 預設使用 CPU 運算,若要啟用 GPU,可以在 Tensor 變數加 .to(0) 或 .cuda() 直接啟用 GPU。但這個方法會有 bug。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
dt=torch.DoubleTensor(batch,2).to(device)
#dt=torch.DoubleTensor(batch,2).to(0)
#dt=torch.DoubleTensor(batch,2).cuda()

新版的正確作法直接在產生 tensor 時,使用 device 參數宣告要常駐在 GPU 中,那麼以後的計算都會由 GPU 執行。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
array=torch.zeros([2,batch], dtype=torch.float32, device=device)

請注意,如果 x 是 GPU 裏的變數,那麼只要跟 x 有關的變數,也都會自動變成 GPU 變數。

如下代碼中,y 並未指定 device=”cuda:0″,但列印出來的結果還是 GPU 的變數

import torch as tc
x=tc.linspace(0,10,10, device='cuda:0')
y=tc.square(x)
print("x: ", x)
print("y :", y)
結果 : 
x:  tensor([ 0.0000,  1.1111,  2.2222,  3.3333,  4.4444,  5.5556,  6.6667,  7.7778,
         8.8889, 10.0000], device='cuda:0')
y : tensor([  0.0000,   1.2346,   4.9383,  11.1111,  19.7531,  30.8642,  44.4444,
         60.4938,  79.0124, 100.0000], device='cuda:0')

參考

https://hackmd.io/@kent010341/SkcZyEGR8?utm_source=preview-mode&utm_medium=rec

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *