Skip to main content

Tinh chỉnh mô hình - Phần 1: Chuẩn bị dữ liệu

tags: tutorial, training, introduction

Bài này cung cấp cho người đọc:

  • Cách chuẩn bị dữ liệu
  • Sử dụng một mạng nơ-ron tích chập và hàm độ lỗi

Giới thiệu

Mạng nơ-ron tích chập (Convolutional Neural Network - CNN) là một kĩ thuật vượt trội để giải quyết các vấn đề khó khăn ở nhiều lĩnh vực. Trong series này, chúng tôi sẽ hướng dẫn cho người đọc các kĩ thuật cơ bản để huấn luyện một CNN.

Cấu trúc bài này gồm ba phần chính:

  1. Chuẩn bị dữ liệu: 1.1. Giới thiệu tập dữ liệu 1.2. Chọn dữ liệu và trực quan hóa 1.3. Tiền xử lý
  2. Chuẩn bị mạng nơ-ron tích chập 2.1. Giới thiệu một số mạng CNN 2.2. Cách sử dụng một CNN được huấn luyện sẵn
  3. Chuẩn bị hàm độ lỗi 3.1. Giới thiệu và chọn hàm độ lỗi phù hợp 3.2. Chạy ví dụ minh họa

1. Chuẩn bị dữ liệu

1.1. Giới thiệu

Các hình ảnh, bảng biểu mà chúng ta sử dụng hằng ngày được xem như là dữ liệu thô (raw data), các dữ liệu này thường không thích hợp để đưa vào máy tính xử lý. Do đó, các dữ liệu thô thường được chuyển đổi thành các dạng vector/matrix hay tensor.

Nhiều bộ dữ liệu đã được tích hợp sẵn trong TensorFlow (như MNIST, ImageNet, PASCAL VOCCIFAR10) cho các bài toán khác nhau. Một bộ dữ liệu có thể được chia thành nhiều phần cho nhiều mục đích như huấn luyện (training), kiểm tra (testing).

1.2. Chọn dữ liệu và trực quan hóa

Chúng ta sẽ thực hiện bài toán phân loại ảnh (image classification) với bộ dữ liệu CIFAR10.

CIFAR-10 là bộ dữ liệu phổ biến cho bài toán phân loại ảnh. Với 60K ảnh train và test của 10 loại vật thể khác nhau (mèo, chó, ngựa,..). Vì kích thước không quá lớn (mỗi ảnh có 32x32 pixel) nên thường được sử dụng trong giảng dạy.

Lấy dữ liệu từ TensorFlow:

# gọi thư viện sử dụng
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
# cố định random seed
tf.random.set_seed(248)
class_names = ['airplane','automobile','bird','cat','deer',
'dog','frog','horse','ship','truck']

# lấy dữ liệu từ TF
(x_train, y_train), (x_test, y_test) = cifar10.load_data()

Dữ liệu của bộ CIFAR-10 đã được lưu trong 4 biến x_{train,test}, y_{train,test}. Chúng ta có thể kiểm tra một số thông tin về kích thước của dữ liệu như sau:

# in kích thước dữ liệu ra màn hình
print(x_train.shape, y_train.shape)
print( x_test.shape, y_test.shape)

Kết quả xuất ra màn hình:

(50000, 32, 32, 3) (50000, 1)
(10000, 32, 32, 3) (10000, 1)

Một bộ dữ liệu thường có hai thành phần chính là dữ liệu và nhãn của nó. Tương ứng trong đoạn code trên x là ảnh và y là nhãn của x.

Chúng ta có thể trực quan hóa dữ liệu để kiểm tra:

import matplotlib.pyplot as plt

# kiểm tra thử phần tử thứ 2 trong data
ind = 1
name = class_names[y_train[ind][0]]
print(name)
plt.imshow(x_train[ind])

Kết quả đầu ra là hình một chiếc xe tải cùng nhãn của nó. Vì ảnh chỉ có 32x32 pixel nên chất lượng rất kém !!!

![](https://i.imgur.com/uhPMmTR.jpg =300x)

1.3. Tiền xử lý dữ liệu

Ở bước này, chúng ta sẽ có hai phần cần chuẩn bị là ảnh và nhãn để phù hợp với kiến trúc mạng:

  • Ảnh cần chuyển về dạng tensor
  • Nhãn chuyển về dạng one-hot vector

Với ảnh, vì chúng ta đã lấy trực tiếp từ thư viện nên có thể sử dụng ngay. Tuy nhiên, nhãn dữ liệu hiện chưa phù hợp với bài toán. Chúng ta sẽ chuyển chuyển dữ liệu về dạng one-hot vector được mô tả trong trong bảng dưới: ![](https://i.imgur.com/0CGV5V6.png =400x)

Chúng ta có thể trực tiếp code hoặc sử dụng thư viện cho việc chuyển đổi one-hot:

# lấy số lượng lớp
num_class = len(class_names)

# chuyển đổi nhãn về dạng one-hot vector
y_train_oh = tf.one_hot(y_train[:,0], num_class)
y_test_oh = tf.one_hot(y_test[:, 0], num_class)

# check kết quả
print(y_train_oh.shape , y_test_oh.shape)
print(y_train_oh[1])

Hai dòng in ra màn hình dùng để kiểm tra kích thước và tính chính xác của việc chuyển đổi.

(50000, 10) (10000, 10)
tf.Tensor([0. 0. 0. 0. 0. 0. 0. 0. 0. 1.], shape=(10,), dtype=float32

2. Chuẩn bị mạng nơ-ron tích chập

2.1. Giới thiệu một số mạng CNN

Sau khi tiền xử lý dữ liệu, chúng ta sẽ sử dụng một mạng nơ-ron tích chập để học cho bài toán phân loại ảnh. Kiến trúc mạng có thể được chọn từ thư viện hoặc do chúng ta tự thiết kế.

Thư viện TensorFlow có nhiều mô hình cho bài toán phân loại ảnh như VGG, MobileNet, ResNetDenseNet được tích hợp sẵn.

Các mô hình trong thư viện sẽ có các trọng số được huấn luyện sẵn trên tập ImageNet. Bạn có thể tham khảo thêm ở đây.

2.2. Cách sử dụng một CNN được huấn luyện sẵn

Tuy VGG là một kiến trúc cổ điển nhưng vẫn được sử dụng nhiều cho đến hiện nay. Đầu tiên, chúng ta sẽ khởi tạo mạng VGG16 như sau:

net = tf.keras.applications.VGG16(include_top=False,
input_shape=(32,32,3))
print(net.summary())

Kết quả xuất ra màn hình:

Model: "vgg16"
...
=================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
_________________________________________________________________
None

Dùng lệnh summary() để kiểm tra các thông số trong VGG16. Vì đã loại bỏ hết lớp FC nên số lượng tham số còn lại khoảng 14,7M.

Tiếp theo, để phân loại cho 10 lớp trong CIFAR-10 chúng ta thêm vào lớp FC với 10 node như sau:

# lấy các layers trong mạng net
layers = net.layers

# khởi tạo và thêm hai layers mới vào danh sách các layers
exend_layers = [
tf.keras.layers.GlobalAvgPool2D(),
tf.keras.layers.Dense(10)
]
layers.extend(exend_layers)

# khởi tạo mạng new_net từ các từ danh sách các layers
new_net = tf.keras.models.Sequential(layers)
print(new_net.summary())

Số lượng tham số xuất ra màn hình.

Model: "sequential"
...
=================================================================
Total params: 14,719,818
Trainable params: 14,719,818
Non-trainable params: 0
_________________________________________________________________

Vậy khi in kiến trúc mạng mới, chúng ta thấy kiến trúc mạng đã thêm 2 lớp vào cuối cùng và số lượng tham số cũng tăng lên so với kiến trúc cũ.

3. Chuẩn bị hàm độ lỗi

3.1. Giới thiệu và chọn hàm độ lỗi phù hợp

Hàm độ lỗi giúp so sánh sự khác biệt giữa nhãn dự đoán từ mô hình được học và nhãn thật của con người.

Trong phân loại ảnh thì có nhiều hàm độ lỗi có thể được sử dụng như như Mean Absolute Error (MAE), Mean Square Error (MSE) hay Cross-Entropy (CE).

Tùy dữ liệu và mô hình sử dụng trong bài toán mà sử dụng hàm độ lỗi phù hợp. Để đo khoảng cách giữa các điểm trong không gian thì hàm độ lỗi phổ biến là MSE.

3.2. Chạy ví dụ minh họa

Trong TensorFlow, chúng ta có thể sử dụng hàm MSE như sau:

from tensorflow.keras.losses import mean_squared_error

# sử dụng mạng new_net để dự đoán trên tập test
y_test_pred = new_net.predict(x_test, 64)

# tính độ lỗi giữa kết quả dự toán và nhãn dữ liệu
loss = mean_squared_error(y_test_oh, y_test_pred).numpy().mean()
print(loss)

In giá trị độ lỗi ra màn hình là cố định cho các lần chạy, vì từ đầu đã xét random seed từ đầu

459.7654

Như vậy các bạn đã đọc và thực hành xong bài này. Nếu có khó khăn trong quá trình luyện tập, các bạn có thể tham khảo colab notebook của bài này. Những câu hỏi phía dưới nhằm cũng cố và mở đường cho bạn tìm hiểu thêm những thông tin khác mà không nêu trong bài.

Câu hỏi

  1. Dữ liệu đầu vào của mạng neural networks gồm bao nhiêu chiều và mô tả thông tin của từng chiều?
  2. Ngoài dữ liệu huấn luyện và kiểm tra (training và testing data) thì còn loại dữ liệu nào khác không?
  3. Trong phần mạng neural networks, tại sao lại loại bỏ lớp FC (include_top=False) của mô hình VGG16 trước để thêm lớp mới vào?
  4. Tại sao dùng hàm "mean()" trong dòng tính độ lỗi MSE ?