[Deep Learning] Pytorch cơ bản

  Feb 21, 2018      2m
   

Cơ bản Pytorch

[Deep Learning] Pytorch cơ bản

1. Mục lục

    1. Mục lục
    1. Cơ bản Pytorch
    1. Tensor
      • 3.1. Khởi tạo Tensor
      • 3.2. Tensor trên CPU / GPU
      • 3.3. Các kiểu dữ liệu Tensor
      • 3.4. Các toán tử trên Tensor
      • 3.4.1. Cú pháp
      • 3.4.2. Các toán tử trên phần tử (element-wise) thường dùng
      • 3.4.3. Broadcast
    1. Variable
      • 4.1. Khởi tạo Variable
      • 4.2. Autograd

2. Cơ bản Pytorch

Pytorch là framework Deep Learning cho phép lập trình trên Python, thực hiện các phép tính toán trên GPU. Cài đặt Pytorch dễ dàng bằng cách theo hướng dẫn trên trang chủ http://pytorch.org.

Lưu ý: Các code ví dụ trong bài thực hành này hoạt động tốt nhất trên Python 3.5.

3. Tensor

Tensor là kiểu dữ liệu chính trong Pytorch. Có thể hình dung Tensor là khối ma trận nhiều chiều.

3.1. Khởi tạo Tensor

Khởi tạo Tensor có kích thước 3 hàng, 4 cột:

import torch
x = torch.Tensor(3,4)
print(x)

Kết quả in ra Tensor:

 5.0234e+24  4.5894e-41  5.0234e+24  4.5894e-41
 0.0000e+00  0.0000e+00  6.7355e+24  4.5894e-41
 0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
[torch.FloatTensor of size 3x4]

Vì ta không đặc tả cách khởi tạo nên việc chạy đi chạy lại script trên sẽ in ra các kết quả khác nhau và miền giá trị của mỗi phần tử sẽ không biết trước được.

Khởi tạo Tensor theo phân phối đồng đều (uniform distribution)

import torch
x = torch.rand(3,4)
print(x)

Mỗi phần tử nằm trong miền giá trị [0,1)

 0.6179  0.2847  0.2000  0.9990
 0.8118  0.1532  0.6351  0.9820
 0.0704  0.5383  0.8822  0.1310
[torch.FloatTensor of size 3x4]

Khởi tạo Tensor nhiều chiều:

import torch
x = torch.Tensor([[2,5],[4,3],[1,5]])
y = torch.Tensor([[[1,2,3,4], [2,6,8,1], [4,8,10,2]], [[0,2,7,6], [1,9,3,2], [1,2,3,4]]])
print(x)
print(y)
print('y.size()', y.size())

Dùng phương thức .size() để kiểm tra kích thước Tensor. Kết quả:

 2  5
 4  3
 1  5
[torch.FloatTensor of size 3x2]


(0 ,.,.) =
   1   2   3   4
   2   6   8   1
   4   8  10   2

(1 ,.,.) =
   0   2   7   6
   1   9   3   2
   1   2   3   4
[torch.FloatTensor of size 2x3x4]

y.size() torch.Size([3, 2])

Tensor cũng có thể được tạo từ kiểu dữ liệu NumPy.

import torch
import numpy as np
x = np.array([1,2,3])
y = torch.from_numpy(X)

print('x', x)
print('y', y)
y += 1
print('x*', x)
print('y*', y)

z = y.numpy()
print('z', z)
print('type(z)', type(z))

Khởi tạo numpy array x, chuyển đổi x thành Tensor y. Tensor y cộng thêm 1 đơn vị, x cũng sẽ tự động thay đổi theo. Từ Tensor ta cũng có thể chuyển đổi ngược lại về numpy.

x [1 2 3]
y
 1
 2
 3
[torch.LongTensor of size 3]

x* [2 3 4]
y*
 2
 3
 4
[torch.LongTensor of size 3]

z [2 3 4]
type(z) <class 'numpy.ndarray'>

3.2. Tensor trên CPU / GPU

Tính toán trên GPU nhanh gấp nhiều lần trên CPU. Tensor hỗ trợ việc tính toán trên GPU, mặc định Tensor tạo theo cách thông thường sẽ nằm trên CPU. Để đem Tensor lên GPU tính toán, ta dùng phương thức .cuda().

import torch

x = torch.Tensor([1,2,3])
y = torch.Tensor([4,5,6])
if torch.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    print(x + y)
else:
    print('Cuda is not available!')

Dòng lệnh torch.cuda.is_available() kiểm tra xem máy tính có hỗ trợ CUDA. Nếu có kết quả sẽ in ra như sau:

 5
 7
 9
[torch.cuda.FloatTensor of size 3 (GPU 0)]

Minh họa việc tính toán trên GPU nhanh hơn CPU bằng ví dụ sau:

import torch
import time

x = torch.rand(10000,10000)
y = torch.rand(10000,10000)
tic = time.time()
x + y
toc = time.time()
print('Elapsed time on CPU: %fs' % (toc-tic))

x = x.cuda()
y =  y.cuda()
tic = time.time()
x + y
toc = time.time()
print('Elapsed time on GPU: %fs' % (toc-tic))

Kết quả:

Elapsed time on CPU: 0.118872s
Elapsed time on GPU: 0.000901s

3.3. Các kiểu dữ liệu Tensor

Bảng các kiểu dữ liệu Tensor (http://pytorch.org/docs/0.3.0/tensors.html#torch-tensor):

Kiểu dữ liệuCPU TensorGPU Tensor
32-bit floating pointtorch.FloatTensortorch.cuda.FloatTensor
64-bit floating pointtorch.DoubleTensortorch.cuda.DoubleTensor
16-bit floating pointtorch.HalfTensortorch.cuda.HalfTensor
8-bit integer (unsigned)torch.ByteTensortorch.cuda.ByteTensor
8-bit integer (signed)torch.CharTensortorch.cuda.CharTensor
16-bit integer (signed)torch.ShortTensortorch.cuda.ShortTensor
32-bit integer (signed)torch.IntTensortorch.cuda.IntTensor
64-bit integer (signed)torch.LongTensortorch.cuda.LongTensor
import torch

x = torch.FloatTensor(range(5))
y = torch.cuda.FloatTensor(range(5))
print(x)
print(y)

Kết quả:

 0
 1
 2
 3
 4
[torch.FloatTensor of size 5]


 0
 1
 2
 3
 4
[torch.cuda.FloatTensor of size 5 (GPU 0)]

3.4. Các toán tử trên Tensor

3.4.1. Cú pháp

Có các cú pháp sau:

  1. Dùng toán tử nhị phân
    import torch
    x = torch.rand(3)
    y = torch.rand(3)
    z = x + y
    print(z)
    

    Kết quả:

     1.6920
     1.1049
     1.0741
    [torch.FloatTensor of size 3]
    
  2. Dùng phương thức trong class torch
    import torch
    x = torch.rand(3)
    y = torch.rand(3)
    z = torch.add(x, y)
    print(z)
    
  3. Dùng phương thức trong thực thể Tensor. Cách này sẽ trực tiếp thay đổi dữ liệu trong thực thể gọi phương thức.
    import torch
    x = torch.rand(3)
    y = torch.rand(3)
    z = x.add_(y)
    print(z)
    

3.4.2. Các toán tử trên phần tử (element-wise) thường dùng

  • Toán tử cộng: + / torch.add()
  • Toán tử nhân: * / torch.mul()
      import torch
      x = torch.FloatTensor([[2,5],[4,3],[1,5]])
      y = torch.FloatTensor([[1,4],[-2,2],[3,-2]])
      print(x)
      print(y)
      print(torch.mul(x,y))
    

    Từng phần tử của ma trận x nhân tương ứng từng phần tử của ma trận y. Kết quả:

      2  5
      4  3
      1  5
      [torch.FloatTensor of size 3x2]
    
    
      1  4
      -2  2
      3 -2
      [torch.FloatTensor of size 3x2]
    
    
      2  20
      -8   6
      3 -10
      [torch.FloatTensor of size 3x2]
    
  • Toán tử bình phương: ** / torch.pow()
      import torch
      x = torch.FloatTensor([1,2,3])
      print(torch.pow(x, 2))
      print(x**2)
    
  • Toán tử căn bậc 2: torch.sqrt()
      import torch
      torch.sqrt(torch.randn(4))
    

3.4.3. Broadcast

Broadcast cho phép ta thực hiện các toán tử giữa 2 tensor của pytorch / mảng numpy không cùng số chiều. Quy tắc Broadcast:

  • Thêm chiều vào phía trước tensor có chiều ngắn hơn cho đến khi số chiều 2 tensor bằng nhau
  • Số phần tử của mỗi chiều của 2 tensor phải:
    • bằng nhau, hoặc
    • một tensor có 1 phần tử, giá trị của phần tử được nhân bản thành k phần tử (bằng với số phần tử của tensor còn lại ở chiều đang xét)
import torch
x = torch.rand(2,1,3)
y = torch.ones(3,1)
print(x)
print(y)
print(x+y)

Giải thích:

  • Kích thước của x: 2x1x3
  • Kích thước của y: 3x1
  • Broadcast:
    • Thêm chiều vào phía trước của y cho đến khi số chiều bằng x –> kích thước của y: 1x3x1
    • Xét chiều thứ 0: chiều thứ 0 của y là 1, nhỏ hơn x (là 2) –> kích thước y: 2x3x1
    • Xét chiều thứ 1: chiều thứ 1 của y là 3, lớn hơn x (là 1) –> kích thước x: 2x3x3
    • Xét chiều thứ 2: chiều thứ 2 của y là 1, nhỏ hơn x (là 3) –> kích thước y: 2x3x3
  • Kết quả kích thước tensor đầu ra sẽ là 2x3x3
(0 ,.,.) =
  0.6508  0.2330  0.3965

(1 ,.,.) =
  0.1472  0.8538  0.4213
[torch.FloatTensor of size 2x1x3]

 1
 1
 1
[torch.FloatTensor of size 3x1]

(0 ,.,.) =
  1.6508  1.2330  1.3965
  1.6508  1.2330  1.3965
  1.6508  1.2330  1.3965

(1 ,.,.) =
  1.1472  1.8538  1.4213
  1.1472  1.8538  1.4213
  1.1472  1.8538  1.4213
[torch.FloatTensor of size 2x3x3]

Nếu vi phạm quy tắc broadcast trên thì Pytorch sẽ báo lỗi:

import torch
x=torch.FloatTensor(5,2,4,1)
y=torch.FloatTensor(3,1,1)
(x+y).size()

Hiển thị lỗi:

RuntimeError: inconsistent tensor size, expected r_ [5 x 2 x 4 x 1], t [5 x 2 x 4 x 1] and src [3 x 1 x 1] to have the same number of elements, but got 40, 40 and 3 elements respectively

4. Variable

Variable là class bao bọc (wrapper) Tensor cho phép thực hiện tính toán đạo hàm. Variable lưu trữ data (tensor) và grad (gradient). Pytorch Variable

4.1. Khởi tạo Variable

import torch
from torch.autograd import Variable
x = Variable(torch.ones(2, 2), requires_grad=True)
print(x)

Variable hỗ trợ hầu hết các toán tử của Tensor.

4.2. Autograd

Minh họa cách tính Gradient tự động trong Pytorch bằng ví dụ sau: Cho đồ thị tính toán như hình. Đầu vô [x,y,z] = [5,3,7]. Tất cả các trọng số w đều được khởi tạo là 0.5. Tính kết quả (biến result) khi ta cho [x,y,z] qua mạng (forward) và gradient của mỗi trọng số w (backward). Pytorch Autograd Example

import torch
from torch.autograd import Variable

xy = Variable(torch.FloatTensor([5, 3]), requires_grad=True) # size: 2
z = Variable(torch.FloatTensor([7]), requires_grad=True)    # size: 1
w12 = Variable(torch.FloatTensor([0.5, 0.5]), requires_grad=True)   # size: 2
w3 = Variable(torch.FloatTensor([0.5]), requires_grad=True) # size: 1
w4 = Variable(torch.FloatTensor([0.5]), requires_grad=True) # size: 1
w5 = Variable(torch.FloatTensor([0.5]), requires_grad=True) # size: 1

k = xy*w12
o1 = k[0]*k[1]
o2 = o1*w4 + z*w3
result = o2*w5
print('result', result)         # 2.6875

result.backward()
print('w12.grad', w12.grad)     # 1.8750, 1.8750
print('w3.grad', w3.grad)       # 3.5000
print('w4.grad', w4.grad)       # 1.8750
print('w5.grad', w5.grad)       # 5.3750

Forward
o1 = x * w1 * y * w2 = 5 * 0.5 * 3 * 0.5 = 3.75
o2 = o1 * w4 + z * w3 = 3.75 * 0.5 + 7 * 0.5 = 5.375
result = o2 * w5 = 5.375 * 0.5 = 2.6875

Backward

Cần chú ý công thức đạo hàm của hàm hợp:

f'(u(x)) = f'(u) * u'(x)

result = o2 * w5

Đạo hàm của result theo w5 = (o2 * w5)' = o2 = 5.375

Đạo hàm của result theo o2 = f'(o2) = w5 = 0.5

o2 = o1 * w4 + z * w3

Đạo hàm của result theo w3 = f'(o2) * o2'(w3) = 0.5 * z = 3.5

Đào hàm của result theo w4 = f'(o2) * o2'(w4) = 0.5 * o1 = 1.875

Đào hàm của result theo o1 = g'(o1) = f'(o2) * o2'(o1) = 0.5 * w4 = 0.25

o1 = x * w1 * y * w2

Đạo hàm của result theo w1 = g'(o1) * o1'(w1) = 0.25 * x * y * w2 = 1.875

Đạo hàm của result theo w2 = g'(o1) * o1'(w2) = 0.25 * x * w1 * y = 1.875


Link download: 2018-02-21-pytorch-co-ban.pdf

Tham khảo thêm: