1. Tensor là gì?

Đa số các thuật toán ML, DL chỉ xử lí được data dưới dạng số thực nên các dữ liệu đưa vào mô hình phải được chuyển về dạng số.

Tensor là đơn vị tính cơ bản trong deep learning, nó chứa dữ liệu và dữ liệu này thường là numeric. Đó cũng là nguồn cảm hứng mà google đặt tên cho thư viện deep learning nổi tiếng của mình là tensorflow ( Các tensor được tính toán theo(flow) computation graph).

Các dạng tensor thường gặp

1. Scalars (0D tensor) : tensor chứa duy nhất một number. Vd : 0,1,2,3

2. Vector (1D tensor) : một array number người ta gọi là vector hay 1D tensor. Vd : [1,2,3],[,3,1,2]

3. Matrix (2D tensor) : 1 array vector được gọi là matrix, hay 2D tensor nó giống như 1 bảng tính gồm các column và row . vd : [[2,1,1],[1,2,3],[1,2,3]]

4. Higher-dimension tensor (3D tensor) : Tưởng tượng như là 1 khối (cubic) hình hộp chữ nhật chứa các number. Nó được tạo nên từ nhiều matrix (2D tensor).

Các thuộc tính của tensor

1. Number of axis : số axis của tensor, hiểu đơn giản là số chiều không gian chứa tensor, vd : scalars 0 axis, vector 1 axis, matrix 2 axis…

2. Shape : Số chiều tensor trên mỗi axis . Vd : matrix có shape (5,10) gồm 5 row (axis=0) và 10 column (axis=1)

3. Data type : thường gọi là dtype trong python, kiểu dữ liệu lưu trữ mỗi tensor thông thường là float32.

Một số tensor data thường sử dụng trong deep learning :

Ảnh màu (rgb) được biểu diễn dưới dạng 1 tensor 3 chiều

image

Hay dữ liệu dạng chữ (tôi, yêu, hoa,..) cũng được chuyển về dạng vector trước khi cho vào các mô hình, ví dụ như mô hình word2vec.

image

Hay các bảng số liệu được ghi nhận dưới cấu trúc (sample, feature) thường được sử dụng để dự đoán trong các bài toán ML

image

2.Numpy arrays vs PyTorch tensors

Numpy là thư viện Python giúp lưu trữ và xử lý các phép tính với dữ liệu dạng số thực. Tuy nhiên, Numpy được viết bằng C/C++ nên tốc độ xử lý và tính toán rất nhanh.

PyTorch tensors có chức năng và mục đích tương tự Numpy arrays nhưng có một vài ưu điểm hơn:

  • Thực hiện tính toán nhanh trên GPU, vì các mô hình DL muốn tăng tốc thì cần xử lý qua các GPU nên tensors hỗ trợ tính toán nhanh trên GPU rất cần thiết.
  • Các Pytorch tensors có thể lưu lại được đồ thị tính toán nên có thể tính đạo hàm nhanh chóng, phục vụ cho thuật toán backpropagation trong Deep Learning.

3. Torch Tensors

Số thực là dữ liệu 0D, vector 1D, ma trận 2D còn dữ liệu từ 3D trở đi được gọi là tensor.

image

3.1 Vector

Để truy cập đến phần tử của vector và sửa phần tử của vector ta dùng chỉ số index. Index sẽ được đánh bắt đầu từ 0 đến phần tử cuối cùng của vector. image

Để truy cập phần tử cuối cùng

x[-1] # Tương đương với x[x.shape[0] - 1], lấy phần tử cuối cùng

Vậy có cách nào lấy được 1 số phần tử trong vector, ví dụ 3 phần tử cuối cùng, các phần tử index chẵn,..? Có, slicing sẽ giúp mọi người.

image

Nếu mọi người không truyền gì thì mặc định start=0, stop=x.shape[0] và step=1. Ý tưởng slicing là sẽ lấy từ phần tử index start đến index (stop – 1) với bước nhảy là step.

x = x[:] = x[::] = x[0:x.shape[0]:1] # lấy tất các phần tử trong x

Như ví dụ x[1:5:2] ở trên thì mình sẽ lấy phần tử đầu ở index 1, sau đó lấy phần tử ở index 3, tuy nhiên sẽ không lấy phần tử ở index 5 vì mình chỉ lấy từ index start đến (stop – 1) hay từ 1 -> 4.

x[1:5:2] # output: [2, 4]

Torch tensors không hỗ trợ step âm như python list.

3.1 Ma trận

image

Ví dụ muốn ấy kích thước ta có thể dùng

A.shape # torch.Size([3, 2])
A.shape[0] # 3

image

A[1:, :1] # Tương đương A[1:A.shape[0]:1, 0:1:1]

3.3 Tensor 3D

Với tensor 3D thì thuộc tính shape sẽ cho ra 3 giá trị, tương ứng độ sâu (depth), số hàng, số cột. Để truy cập phần tử thì mình cũng phải chỉ rõ index của depth, hàng và cột. Tương tự để slicing thì mình cũng phải slicing trên cả 3 chiều.

4. Torch Properties

Gán giá trị cho tensor và torch sẽ tự động gán dtype bằng với dtype của giá trị có kiểu rộng hơn trong tensor.

points = torch.tensor([7, 8, 10, 6.5])
print(points.dtype) # output: torch.float32

Tuy nhiên mình cũng có thể khởi tạo kiểu dữ liệu cho tensor luôn

points = torch.tensor([7, 8, 10, 6])
print(points.dtype) # output: torch.int64

# Gán kiểu dữ liệu cho tensor
points = torch.tensor([7, 8, 10, 6], dtype=torch.short)
print(points.dtype) # output: torch.int16

Hoặc mình cũng có thể chuyển kiểu dữ liệu của tensor đã được khai báo

points = torch.tensor([7, 8, 10, 6]).short()
points = torch.tensor([7, 8, 10, 6]).to(dtype=torch.short)

Hàm to(dtype=…) sẽ kiểm tra kiểu dữ liệu của tensor và chuyển sang kiểu dữ liệu mới nếu cần thiết. Phần dưới mình sẽ dùng hàm to() để chuyển tensor từ CPU sang GPU.

5. Torch transpose

Hàm torch transpose(input, dim0, dim1) : để tìm ma trận chuyển vị của tensor input (Cụ thể chuyển chiều dim0 với dim1)

Với ma trận 2D image

Với ma trận 3D image

CÁC PHÉP TÍNH KHÁC CÁC BẠN CÓ THỂ THAM KHẢO TẠI ĐÂY

6. Torch GPU

Torch storage thì mặc định sẽ lưu ở CPU, tuy nhiên Torch cho phép tensor lưu ở GPU để tính toán song song cũng như tăng tốc độ xử lý.

Nếu 1 tensor được lưu ở GPU, thì các phép tính toán sẽ được thực hiện ở GPU.

Để khởi tạo 1 tensor và lưu trên gpu thì mình dùng thuộc tính device.

x_gpu = torch.tensor([[4.0, 1.0], [5.0, 3.0], [2.0, 1.0]], device='cuda')

Hoặc mình có thể copy 1 tensor từ CPU sang GPU

x = torch.tensor([[4.0, 1.0], [5.0, 3.0], [2.0, 1.0]])
x_gpu = x.to(device='cuda')

Mỗi tensor chỉ được lưu trên 1 GPU nhất định nên nếu có nhiều GPU thì phải chỉ rõ lưu trên GPU nào, index GPU cũng bắt đầu từ 0.

x_gpu = x.to(device='cuda:0')
# hoặc
x_gpu = x.cuda(0)
x_gpu = x_gpu + 4 # Thực hiện phép tính trên GPU

Để chuyển ngược lại từ GPU về CPU thì mình dùng

x_cpu = x_gpu.to(device='cpu')
# hoặc
x_cpu = x_gpu.cpu()

7. Torch Tensor to Numpy Array

Torch cho phép chuyển tensor sang Numpy array. Các thuộc tính về size, shape sẽ được giữ nguyên, type sẽ chuyển từ Torch sang Numpy.

x = torch.tensor([1,2,3])
x_np = x.numpy()

Nếu tensor được lưu trên CPU, Torch tensor và Numpy array sẽ dùng chung vùng nhớ, nên thay đổi giá trị ở 1 biến thì giá trị biến còn lại cũng thay đổi.

x[1] = 0
print(x) # output: [1, 0, 3]
print(x_np) # output: [1, 0, 3]

Nếu tensor được lưu trên GPU thì mọi người sẽ không thể chuyển trực tiếp tensor sang Numpy array được, mà mình cần copy nội dung của tensor sang CPU trước rồi mới chuyển sang Numpy array. Do đó 2 biến trên gpu và np không dùng chung vùng nhớ và sửa 1 biến không ảnh hưởng biến còn lại.

x_gpu = torch.tensor([1, 2, 3], device='cuda')
x_np = x_gpu.numpy() # Error
x_np = x_gpu.cpu().numpy() # ok
x_gpu[1] = 0 
print(x_gpu) # output: [1, 0, 3]
print(x_np) # output: [1, 2, 3]

Tương tự, mình có thể chuyển Numpy array sang Torch tensor. Torch tensor sẽ lưu ở CPU và 2 biến trên np và cpu sẽ dùng chung vùng nhớ.

x_np = np.array([1, 2, 3])
x_cpu = torch.from_numpy(x_np)