Deep Learning với Tensorflow Module 3 Phần 2: Xây dựng mô hình phân loại trong Neural network - Mô hình nhiều class ( Multi Classification)
7. Thử nghiệm với tập dữ liệu lớn hơn (Fashiong MNIST)
Trong phần trước, chúng ta đã xây dựng mô hình phân loại 2 class (binary class). Khả năng dự đoán dữ liệu điểm là màu đỏ hoặc màu xanh của mô hình là cực kỳ xuất sắc. Nhưng nếu có nhiều class khác nhau thì liệu khả năng dự đoán của mô hình có tốt như vậy không? Phần này sẽ trả lời cho câu hỏi này.
Giả sử, bạn có một công ty chuyên cung cấp các loại quần áo thời trang đang là xu hướng trên thế giới. Mỗi lần nhập hàng về là một số lượng khổng lồ với nhiều loại hàng và mẫu mã khác nhau trong khi số lượng nhân viên của bạn lại có hạn. Chính vì thế để tối ưu quá trình phân loại hàng hóa, bạn quyết định tìm đến công cụ xử lý quá trình phân loại này. Do đó, bạn đã xây dựng mô hình deep learning neural network để dự đoán liệu món đồ đó là quần, áo, nón, hay giày dép...
Khi phân loại có nhiều hơn 2 đối tượng (class), thì được gọi là phân loại nhiều đối tượng (multiclass classification)
Để xây dựng mô hình phân loại nhiều đối tượng, nó cũng được áp dụng tượng tự như xây dựng mô hình Binary class và có một chút thay đổi trong đó. Bạn có thể tham khảo lai bảng phương pháp sau :
Hyperparameter | Phân loại 2 class (binary class) | Phân loại nhiều class (multi-class) | |||
---|---|---|---|---|---|
Input layer shape | Có cùng số biến giải thích (VD : Dự đoán bệnh nhân có bị tim mạch hay không dựa trên 5 đặc tính độ tuổi , giới tính , chiều cao , cân nặng , môi trường sống ) | Giống với binary class | |||
Hidden layers | Điều chỉnh tùy thuộc vào vấn đề, min=1, max= vô hạn | Giống với binary class | |||
Neurons trên hidden layer | Điều chỉnh tùy thuôc vào vấn đề, Thường từ 10 đến 100 | Giống với binary class | |||
Output layer shape | 1 ( vì chỉ có 2 class nên chỉ có thể là class này hoặc class kia) | Dựa vào số class (VD : 3 cho food , dog , photo ) | |||
Hidden activation | Thường là ReLU (rectified linear unit) | Giống với binary class | |||
Output activation | Sigmoid | Softmax | |||
Loss function | Cross entropy (tf.keras.losses.BinaryCrossentropy trong TensorFlow) | Cross entropy (tf.keras.losses.CategoricalCrossentropy trong TensorFlow) | |||
Optimizer | SGD (stochastic gradient descent), Adam | Giống với binary class |
Table 1: Typical architecture of a classification network. Source: Adapted from page 295 of Hands-On Machine Learning with Scikit-Learn, Keras & TensorFlow Book by Aurélien Géron
Để bắt đầu, chúng ta sẽ cần load dữ liệu có sẵn Fashion MNIST built-in trong thư viện Tensorflow
# Import các thư viện import tensorflow as tf import numpy as np import matplotlib.pyplot as plt import seaborn as sns sns.set()
Khám phá tập dữ liệu và labels
(train_data, train_labels), (test_data,test_labels) = tf.keras.datasets.fashion_mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz 32768/29515 [=================================] - 0s 0us/step 40960/29515 [=========================================] - 0s 0us/step Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz 26427392/26421880 [==============================] - 0s 0us/step 26435584/26421880 [==============================] - 0s 0us/step Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz 16384/5148 [===============================================================================================] - 0s 0us/step Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz 4423680/4422102 [==============================] - 0s 0us/step 4431872/4422102 [==============================] - 0s 0us/step
Kiểm tra thông tin mẫu dữ liệu train đầu tiên:
print(f"Mẫu dữ liệu train: {train_data[0][10:15]}") print(f"Hình thái mẫu dữ liệu train: {train_data[0].shape}") print(f"Label của mẫu dữ liệu train: {train_labels[0]}")
Mẫu dữ liệu train: [[ 0 0 0 0 0 0 0 0 0 0 0 0 0 193 228 218 213 198 180 212 210 211 213 223 220 243 202 0] [ 0 0 0 0 0 0 0 0 0 1 3 0 12 219 220 212 218 192 169 227 208 218 224 212 226 197 209 52] [ 0 0 0 0 0 0 0 0 0 0 6 0 99 244 222 220 218 203 198 221 215 213 222 220 245 119 167 56] [ 0 0 0 0 0 0 0 0 0 4 0 0 55 236 228 230 228 240 232 213 218 223 234 217 217 209 92 0] [ 0 0 1 4 6 7 2 0 0 0 0 0 237 226 217 223 222 219 222 221 216 223 229 215 218 255 77 0]] Hình thái mẫu dữ liệu train: (28, 28) Label của mẫu dữ liệu train: 9
Kích thước toàn bộ dữ liệu của train và test :
train_data.shape, train_labels.shape, test_data.shape, test_labels.shape
((60000, 28, 28), (60000,), (10000, 28, 28), (10000,))
Thông tin về labels :
np.unique(train_labels)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8)
Có 10 classes cho tập dữ liệu này (danh sách từ 0-9, mỗi phần tử đại diện cho 1 class).
Label | Description | ||
---|---|---|---|
0 | T-shirt/top | ||
1 | Trouser | ||
2 | Pullover | ||
3 | Dress | ||
4 | Coat | ||
5 | Sandal | ||
6 | Shirt | ||
7 | Sneaker | ||
8 | Bag | ||
9 | Ankle boot |
class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"] num_classes = len(class_names) class_names,num_classes
(['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot'], 10)
plt.imshow(train_data[0])
<matplotlib.image.AxesImage at 0x7fa2856bb890>
Tạo hàm hiển thị hình ảnh ngẫu nhiên kèm theo label :
import random import math def plot_random_images(n_samples=1): random_choices = random.sample(range(len(train_data)), k=n_samples) n_cols = 3 n_rows = math.ceil(n_samples / n_cols) plt.figure(figsize=(n_rows*6, 12)) for i, image_index in enumerate(random_choices) : target_image = train_data[image_index] target_class = train_labels[image_index] target_class_name = class_names[target_class] plt.subplot(n_rows, n_cols, i+1) plt.imshow(target_image,cmap=plt.cm.viridis) plt.title(target_class_name) plt.axis(False)
plot_random_images(10)
Trước khi xây dựng mô hình phân loại, dữ liệu mà chúng ta có được là những dữ liệu hình ảnh. Do đó, việc tìm kiếm các mối liên hệ từ các ma trận tạo thành các hình ảnh sẽ giúp mô hình dự đoán đưa đến kết luận liệu với dữ liệu đó thì hình ảnh được cho sẽ thuộc label nào.
Vì đây là dữ liệu multiclass classification, có một số kiến trúc trong mô hình cần lưu ý :
+ input shape : với dữ liệu này là 28x28 tensors(tương ứng với chiều cao và chiều rộng của hình)
- Với kích thước trên chúng ta sẽ duỗi chúng thành một vector với kích thước 784
+ output shape : Giá trị xuất ra của mô hình sẽ là một mảng gồm 10 phần tử tương ứng với 10 class và tổng của chúng sẽ là 1
(mỗi phần tử là khả năng (xác suất) xảy ra một class nào đó, xác suất càng cao thì khả năng xảy ra class đó càng lớn)
- Activation : Thay vì dùng sigmoid
như mô hình phân loại 2 class, thì với nhiều class sẽ là softmax
.
+ Thay đổi loss function
khi compile mô hình từ mô hình 2 class sang nhiều class :
- Lưu ý :
+ Nếu để labels từ 0-9 thì loss function phải là : tf.keras.losses.SparseCategoricalCrossentropy()
+ Nếu one-hot labels ( tức là tạo cho label thành một mảng gồm 10 phần tử, VD label là 2 thì sẽ có mảng sau : [0,0,1,0,0,0,0,0,0,0]) thì sử dụng : tf.keras.losses.CategoricalCrossentropy()
.
+ Chúng ta sẽ sử dụng validation_data
khi gọi hàm fit()
cho mô hình. Điều này cho chúng ta theo dõi được quá trình mô hình hoạt động trong cả train và test
Train mô hình chưa được chuẩn hóa (non-normolized)
from tensorflow.keras import Sequential from tensorflow.keras.layers import Flatten, Dense
Mô hình dưới đây label không được one-hot
nên sử dụng tf.keras.losses.SparseCategoricalCrossentropy()
.Trước khi chạy mô hình, cần chuyển kiểu dữ liệu của label thành float32
, nếu không có thể bạn sẽ bị báo lỗi
train_labels = np.float32(train_labels) test_labels = np.float32(test_labels) train_labels
array([9., 0., 0., ..., 3., 0., 5.], dtype=float32)
tf.random.set_seed(42) model_10 = Sequential([ Flatten(input_shape=(28,28)), Dense(4,activation="relu"), Dense(4,activation="relu"), Dense(num_classes,activation="softmax") ]) model_10.compile( loss=tf.keras.losses.SparseCategoricalCrossentropy(), optimizer="adam", metrics=["accuracy"] ) model_10_history = model_10.fit( train_data, train_labels, epochs=10, verbose=2, validation_data=(test_data, test_labels) )
Epoch 1/10 1875/1875 - 4s - loss: 2.1772 - accuracy: 0.1593 - val_loss: 1.8122 - val_accuracy: 0.2049 Epoch 2/10 1875/1875 - 4s - loss: 1.7162 - accuracy: 0.2447 - val_loss: 1.6517 - val_accuracy: 0.2895 Epoch 3/10 1875/1875 - 3s - loss: 1.6362 - accuracy: 0.2834 - val_loss: 1.6411 - val_accuracy: 0.3092
...
Epoch 9/10
1875/1875 - 4s - loss: 1.5713 - accuracy: 0.3250 - val_loss: 1.5652 - val_accuracy: 0.3138
Epoch 10/10
1875/1875 - 4s - loss: 1.5689 - accuracy: 0.3201 - val_loss: 1.5680 - val_accuracy: 0.3045
model_10.summary()
Model: "sequential_10"
_
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
_
dense_27 (Dense) (None, 4) 3140
_
dense_28 (Dense) (None, 4) 20
_
dense_29 (Dense) (None, 10) 50
=================================================================
Total params: 3,210
Trainable params: 3,210
Non-trainable params: 0
_
model_10.evaluate(test_data, test_labels)
313/313 [==============================] - 1s 2ms/step - loss: 1.5680 - accuracy: 0.3045
[1.5680228471755981, 0.304500013589859]
Tạo hàm vẽ biểu đồ mô tả quá trình mô hình train dữ liệu qua từng epochs
def plot_loss_curves(history) : history = history.history acc, loss = history["accuracy"], history["loss"] val_acc, val_loss = history["val_accuracy"], history["val_loss"] plt.figure(figsize=(16,6)) plt.subplot(121) plt.plot(acc, label="train accuracy") plt.plot(val_acc, label="val accuracy") plt.xlabel("epochs") plt.ylabel("percentage") plt.legend() plt.subplot(122) plt.plot(loss, label="train loss") plt.plot(val_loss, label="val loss") plt.xlabel("epochs") plt.ylabel("percentage") plt.legend()
plot_loss_curves(model_10_history)
Mô hình có độ chính xác tương đối thấp (~35%) sau 10 epochs khi sử dụng mô hình tương tự với binary class ở phần trước.
Liệu bạn có còn nhớ trước đây chúng ta đã từng nói về chuẩn hóa dữ liệu trong neural network (đưa dữ liệu về 0 - 1)?
model_10
chưa chuẩn hóa các dữ liệu trong ma trận,do đó, các giá trị pixel dao động từ 0 - 255. Trước khi gọi hàm fit
, các dữ liệu cần được chuẩn hóa.
Train mô hình với dữ liệu được chuẩn hóa (normolized data)
# Phạm vi các trị train data, test data khi chưa chuẩn hóa (train_data.min(), train_data.max()), (test_data.min(), test_data.max())
((0, 255), (0, 255))
# Phạm vi các giá trị sau khi chuẩn hóa train_data_scaled = train_data / 255. #(`255.` chia lấy kiểu float) test_data_scaled = test_data / 255. train_data_scaled.min(),train_data_scaled.max()
(0.0, 1.0)
OK, các giá trị đã được đưa về 0-1. Bây giờ ta sẽ chạy lại mô hình trên, chúng ta không cần phải khởi tạo mô hình bằng hàm Sequential
, chỉ cần compile
và fit
là được.
model_10.compile( loss=tf.keras.losses.SparseCategoricalCrossentropy(), optimizer="adam", metrics=["accuracy"] ) model_10_normed_history = model_10.fit( train_data_scaled, train_labels, epochs=10, validation_data=(test_data_scaled,test_labels) )
Epoch 1/10 1875/1875 [==============================] - 5s 3ms/step - loss: 1.6361 - accuracy: 0.3201 - val_loss: 1.4551 - val_accuracy: 0.3628 Epoch 2/10 1875/1875 [==============================] - 5s 3ms/step - loss: 1.4170 - accuracy: 0.3830 - val_loss: 1.3824 - val_accuracy: 0.4017 Epoch 3/10 1875/1875 [==============================] - 5s 3ms/step - loss: 1.3564 - accuracy: 0.4137 - val_loss: 1.3377 - val_accuracy: 0.4314 ...
Epoch 8/10
1875/1875 [==============================] - 5s 3ms/step - loss: 1.1960 - accuracy: 0.5143 - val_loss: 1.1772 - val_accuracy: 0.5257
Epoch 9/10
1875/1875 [==============================] - 5s 3ms/step - loss: 1.1755 - accuracy: 0.5199 - val_loss: 1.1762 - val_accuracy: 0.5259
Epoch 10/10
1875/1875 [==============================] - 5s 3ms/step - loss: 1.1656 - accuracy: 0.5232 - val_loss: 1.1905 - val_accuracy: 0.5104
Cũng là model_10
trước khi scaled dữ liệu, với 10 epochs, độ chính xác chỉ khoảng ~37%, còn bây giờ nó đã lên đến ~51%. Một sự cải thiện độ chính xác đáng kể khi chỉ cần scaled dữ liệu.
Theo dõi quá trình cải thiện của mô hình qua từng epochs:
pd.DataFrame(model_10_normed_history.history)
loss | accuracy | val_loss | val_accuracy | ||||||
---|---|---|---|---|---|---|---|---|---|
0 | 1.636052 | 0.320100 | 1.455113 | 0.3628 | |||||
1 | 1.417037 | 0.383033 | 1.382420 | 0.4017 | |||||
2 | 1.356395 | 0.413683 | 1.337729 | 0.4314 | |||||
3 | 1.323488 | 0.434050 | 1.309410 | 0.4495 | |||||
4 | 1.306254 | 0.448967 | 1.309463 | 0.4588 | |||||
5 | 1.289672 | 0.468233 | 1.272732 | 0.4840 | |||||
6 | 1.247299 | 0.493700 | 1.206420 | 0.5181 | |||||
7 | 1.196021 | 0.514300 | 1.177217 | 0.5257 | |||||
8 | 1.175470 | 0.519900 | 1.176230 | 0.5259 | |||||
9 | 1.165621 | 0.523217 | 1.190536 | 0.5104 |
plot_loss_curves(model_10_normed_history)
So sánh giữa mô hình có dữ liệu bình thường và mô hình có dữ liệu được scaled.
plt.figure(figsize=(16,6)) ax1 = plt.subplot(121) pd.DataFrame(model_10_history.history).plot(ax=ax1) ax1.set_title("Non normalized data") ax2 = plt.subplot(122) pd.DataFrame(model_10_normed_history.history).plot(ax=ax2) ax2.set_title("normalized data") plt.suptitle("Compare the performance between non normalized data and normolized data in the same model")
Text(0.5, 0.98, 'Compare the performance between non normalized data and normolized data in the same model')
Từ 2 biểu đồ trên, có thể thấy được mô hình được chuẩn hóa (scaled) dữ liệu cải thiện độ chính xác và giảm độ sai sót đi rất nhiều so với mô hình không được chuẩn hóa.
Vậy còn learning_rate
, chúng ta sẽ tìm learning_rate tốt cho mô hình
tf.random.set_seed(42) # Trước hết chúng ta sẽ copy lại mô hình model_11 model_11 = tf.keras.models.clone_model(model_10) model_11.summary()
Model: "sequential_10"
_
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
_
dense_27 (Dense) (None, 4) 3140
_
dense_28 (Dense) (None, 4) 20
_
dense_29 (Dense) (None, 10) 50
=================================================================
Total params: 3,210
Trainable params: 3,210
Non-trainable params: 0
_
trước khi compile
và fit
, ta sẽ tạo một callback function ghi lại learning_rate
của mô hình qua từng epoch và sẽ thực hiện train mô hình với 100 epochs
lr_scheduler = tf.keras.callbacks.LearningRateScheduler(lambda epoch : 1e-3 * 10**(epoch / 20),verbose=0) model_11.compile( loss="sparse_categorical_crossentropy", optimizer="adam", metrics=["accuracy"] ) model_11_normed_history = model_11.fit( train_data_scaled, train_labels, epochs=100, verbose=0, validation_data=(test_data_scaled,test_labels), callbacks=[ lr_scheduler ] )
Biểu diễn đồ thị thể hiện mối liên hệ giữa val_loss
và learning rate
lrs = 1e-3 * 10**(np.arange(100) / 20) plt.semilogx(lrs,model_11_normed_history.history["val_loss"]) plt.xlabel("Learning rate") plt.ylabel("val_loss") plt.title("Finding the ideal learning rate")
Text(0.5, 1.0, 'Finding the ideal learning rate')
Từ biểu đồ trên, có thể thấy val_loss
thấp nhất nằm khi learning rate
đạt giá trị $10^{-2}$. Nhưng trước hết, có thể thấy với số epochs 100, mô hình có vẻ như hoạt động không tốt, nên cần rút gọn số epochs lại. Bây giờ, thử fit lại mô hình với leanrning_rate
là $10^{-2}$ với epochs là 50
tf.random.set_seed(42) model_12 = tf.keras.models.clone_model(model_11) model_12.compile( loss="sparse_categorical_crossentropy", optimizer=tf.keras.optimizers.Adam(learning_rate=0.01), metrics=["accuracy"] ) model_12_normed_history = model_12.fit( train_data_scaled, train_labels, epochs=50, validation_data=(test_data_scaled,test_labels) )
Epoch 1/50 1875/1875 [==============================] - 5s 3ms/step - loss: 1.0991 - accuracy: 0.5714 - val_loss: 0.9693 - val_accuracy: 0.6478 Epoch 2/50 1875/1875 [==============================] - 5s 3ms/step - loss: 0.8667 - accuracy: 0.6924 - val_loss: 0.8411 - val_accuracy: 0.7120 Epoch 3/50 1875/1875 [==============================] - 5s 3ms/step - loss: 0.8373 - accuracy: 0.7011 - val_loss: 0.8128 - val_accuracy: 0.7123
...
Epoch 48/50
1875/1875 [==============================] - 5s 3ms/step - loss: 0.7480 - accuracy: 0.7327 - val_loss: 0.7731 - val_accuracy: 0.7317
Epoch 49/50
1875/1875 [==============================] - 5s 3ms/step - loss: 0.7464 - accuracy: 0.7333 - val_loss: 0.7966 - val_accuracy: 0.7229
Epoch 50/50
1875/1875 [==============================] - 5s 3ms/step - loss: 0.7407 - accuracy: 0.7356 - val_loss: 0.7792 - val_accuracy: 0.7288
Mô hình đã được train với learning_rate
tốt, độ chính xác 70-74%. Với độ chính xác này, mô hình dự báo cũng khá ổn, nhưng mô hình này mới chỉ là mô hình cơ bản, có thể nó sẽ còn tốt hơn rất nhiều nếu nó được cải thiện.
Cải thiện mô hình
Có thể cải thiện mô hình bằng một số cách sau : - Train mô hình lâu hơn ( không khả thi vì mô hình trước 100 epochs tỏ ra rất kém) ❌ - Tăng số lượng dữ liệu train (Dữ liệu không thể thêm trong trường hợp này ) ❌ - Tăng số hidden layers trong mô hình ✅ - Tăng số unit (neurons) trong mỗi layer ✅ - Sử dụng transfer learning (Phần sau sẽ giới thiệu)
Ta sẽ tăng số hidden layers cùng với tăng số lượng unit trong mỗi layer
tf.random.set_seed(42) model_13 = Sequential([ Flatten(input_shape=(28,28)), Dense(128, activation="relu"), Dense(128, activation="relu"), Dense(128, activation="relu"), Dense(num_classes, activation="softmax"), ]) model_13.compile( loss="sparse_categorical_crossentropy", optimizer=tf.keras.optimizers.Adam(learning_rate=0.01), metrics=["accuracy"] ) model_13_normed_history = model_13.fit( train_data_scaled, train_labels, epochs=10, validation_data=(test_data_scaled,test_labels) )
Epoch 1/10 1875/1875 [==============================] - 6s 3ms/step - loss: 0.5755 - accuracy: 0.7956 - val_loss: 0.5782 - val_accuracy: 0.8067 Epoch 2/10 1875/1875 [==============================] - 5s 3ms/step - loss: 0.4735 - accuracy: 0.8370 - val_loss: 0.5257 - val_accuracy: 0.8145 Epoch 3/10 1875/1875 [==============================] - 5s 3ms/step - loss: 0.4499 - accuracy: 0.8418 - val_loss: 0.4867 - val_accuracy: 0.8331
...
Epoch 8/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.4071 - accuracy: 0.8583 - val_loss: 0.4340 - val_accuracy: 0.8517
Epoch 9/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.4099 - accuracy: 0.8576 - val_loss: 0.4954 - val_accuracy: 0.8314
Epoch 10/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.4021 - accuracy: 0.8602 - val_loss: 0.4390 - val_accuracy: 0.8456
Mô hình đã tăng tỉ lệ chính xác lên rất nhiều sau khi cải thiện mô hình.
Đánh giá mô hình được cải thiện
model_13.evaluate(test_data_scaled, test_labels)
313/313 [==============================] - 1s 2ms/step - loss: 0.4390 - accuracy: 0.8456
[0.43895140290260315, 0.8456000089645386]
Nhìn chung, mô hình có khả năng dự đoán chính xác lên đến 83% trong tổng số mẫu. Vậy độ chính xác cụ thể từng loại class của tập dữ liệu này là bao nhiêu?
- Đầu tiên sẽ cho mô hình dữ đoán dữ liệu test
- So sánh kết quả dự đoán với test_label để đánh giá độ chính xac
Để làm được điều này, trước tiên ta sẽ dự đoán mô hình rồi sau đó sẽ tạo hàm thể hiện độ chính xác của ma trận confusion_matrix
y_pred_probs = model_13.predict(test_data_scaled) y_preds_probs.shape
(1000, 1)
Giá trị dự đoán gồm có 10000 tương ứng với 10000 mẫu từ tập dữ liệu test. Trong mỗi 10000 mẫu đó là một mảng gồm 10 phần tử đại diện cho 10 class thể hiện xác suất lựa chọn cho class đó. Vậy với xác suất nào lớn nhất, ta sẽ lựa chọn vị trí đó đại diện cho label dự đoán đó. VD : [0.1, 0.5,0.05,0.05,0.05,0.05, 0.05,0.05,0.05,0.05]
với 0.5 là lớn nhất nên dự đoán class 1
là label cho mẫu này.
y_pred_labels = np.argmax(y_pred_probs,axis=1) y_pred_labels
array([9, 2, 1, ..., 8, 1, 5])
from sklearn.metrics import confusion_matrix import itertools def plot_confusion_matrix(y_true, y_preds, class_names=None) : cm = confusion_matrix(y_true, y_preds) cm_normed = cm / np.sum(cm,axis=1).astype(np.float32) if class_names and cm.shape[0] != len(class_names) : print("the length of class_names is not valid") if class_names : labels = class_names else : labels = range(cm.shape[0]) fig, ax = plt.subplots(figsize=(3*cm.shape[0],3*cm.shape[1])) cax = ax.matshow(cm, cmap=plt.cm.Blues) fig.colorbar(cax) print(labels) ax.set( title="Confusion matrix", xlabel="Predict Label", ylabel="True label", xticks=range(cm.shape[0]), yticks=range(cm.shape[1]), xticklabels=labels, yticklabels=labels, ) ax.xaxis.set_ticks_position("bottom") ax.title.set_size(24) ax.set_xticklabels(labels=labels, rotation=90) ax.xaxis.label.set_size(20) ax.grid(False) threshold = (np.max(cm) + np.min(cm)) / 2 for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])) : plt.text(j, i, f"{cm[i,j]} ({cm_normed[i,j]*100:.2f})%", fontsize=15, horizontalalignment="center", color="black" if threshold > cm[i,j] else "white") plot_confusion_matrix(test_labels, y_pred_labels, class_names=class_names)
['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
Dự đoán label
Sau khi đo lường độ chính xác cụ thể trên từng class, chúng ta sẽ tiến hành thử nghiệm với mô hình dự đoán và so sánh với giá trị thực xem kết quả sẽ như thế nào.
Để thử nghiệm, ta sẽ tạo hàm dự đoán hình ảnh ngẫu nhiên trên tập dữ liệu test
. Hàm này nhận 3 tham số gồm :
+ Mô hình dự đoán
+ Tập dữ liệu test (ma trận hình ảnh được được chuẩn hóa)
+ Labels của tập dữ liệu test (để so sánh với giá trị dự đoán)
import random def make_predict_and_plot_image(model, image_data,labels) : random_image = random.choice(range(len(image_data))) image = image_data[random_image] target_class = labels[random_image] target_class_name = class_names[int(target_class)] image_pred_probs = model.predict(tf.expand_dims(image,axis=0)) image_pred_class= tf.argmax(image_pred_probs,axis=1) image_pred_label = class_names[int(image_pred_class)] color = "red" if target_class_name == image_pred_label : color = "green" plt.figure(figsize=(8,4)) plt.imshow(image) plt.title(f"Actual : {target_class_name}\n Predict: {image_pred_label} with {tf.reduce_max(image_pred_probs[0])*100:.2f}%", color=color)
make_predict_and_plot_image(model_13, test_data_scaled,test_labels)
Mô hình đã học được những đặc tính nào?
Ở những bài viết trước đã có nhiều lần đề cập đến việc tìm các đặc tính (các điểm chung hoặc đặc trưng của các hình ảnh để liên kết giữa chúng với nhau) tiêu biểu trong neural network bằng các con số, nhưng với mô hình này đặc tính trong nó là gì ?
model_13.layers
[<keras.layers.core.Flatten at 0x7fa2870a3350>, <keras.layers.core.Dense at 0x7fa2870a3490>, <keras.layers.core.Dense at 0x7fa2870a3850>, <keras.layers.core.Dense at 0x7fa2870a3c10>, <keras.layers.core.Dense at 0x7fa287096050>]
model_13.layers[1]
<keras.layers.core.Dense at 0x7fa2870a3490>
Và chúng ta có thể tìm thấy các đặc tính được học bởi các layer cụ thể bằng phương thức get_weights()
weights, bias = model_13.layers[1].get_weights() weights, bias[:5], weights.shape, bias.shape
(array([[ 2.66954973e-02, -9.56996530e-03, 7.47938275e-01, ..., -4.07474041e-02, 1.48007795e-02, -3.90902162e-04], [ 6.45309016e-02, -6.13619164e-02, 1.09231544e+00, ..., 4.91267771e-01, 5.40623888e-02, 4.54814956e-02], [ 4.06332910e-02, 4.49500158e-02, 2.56287861e+00, ..., 4.35182095e-01, -4.74400409e-02, -5.38105518e-03], ..., [ 7.16553256e-02, -3.15123200e-02, 1.48855698e+00, ..., 1.52392995e+00, 6.87063709e-02, 3.35246995e-02], [ 2.92116031e-02, -6.55823946e-03, 9.96252239e-01, ..., 1.63837636e+00, 4.45979163e-02, 6.81063607e-02], [ 5.24425432e-02, -7.66266957e-02, 7.30403543e-01, ..., 1.63493883e-02, 4.40619066e-02, -4.64956462e-03]], dtype=float32), array([-0.0600384 , -0.06001915, 1.6928424 , -0.09111124, -0.06004031], dtype=float32), (784, 128), (128,))
Có thể thấy ma trận weights
có kích thước tương tự với dữ liệu được duỗi sau khi nhập vào 784(28 x 28)
và có sự sao chép của các ma trận weights
với mỗi neuons trong một layer đươc chỉ định (layer được chỉ định có 128 neurons)
Mỗi giá trị trong ma trận weights
phản ánh cách mà các giá trị cụ thể trong dữ liệu đưa vào ảnh hưởng đến việc quyết định của mô hình
Kết luận
Chúng ta đã xây dựng một chuỗi mô hình, nhưng chưa từng đề cập đến những gì xảy ra bên trong quá trình train của mô hình đó là gì. Vậy chính xác mô hình đã học những gì ?
Mô hình đã học bằng việc cập nhật và cải thiện các đặc tính (các giá trị ma trận weight
và bias
) qua mỗi epochs. Nó thực hiện việc cải thiện bằng cách so sánh các điểm đặc trưng mà nó đã được học từ dữ liệu được đưa vào để nó dự đoán label với label thực.
Nếu các đặc tính (weight
và bias
) không đưa đến kết quả như mong muốn như làm giảm loss function (loss càng cao đồng nghĩa dự đoán càng tệ), thì khi đó optimizer sẽ cố gắng đưa mô hình cập nhật trở lại các đặc tính theo cách phù hợp ( sử dụng label thực để tham chiếu).
Quá trình sử dụng label thực như một phép tham chiếu để cải thiện mô hình dự đoán được gọi là backpropagation.
Có thể hiểu cách khác, dữ liệu và labels được truyền qua mô hình (truyền tới) và mô hình cố gắng tìm ra mối liên hệ giữa dữ liệu với label đó.
Và nếu như mô hình học về mối liên hệ không gần với mối liên hệ thực tế hoặc nó có thể cải thiện thì mô hình đó sẽ thực hiện bằng cách truyền ngược lại và điều chỉnh ma trận weight
và bias
để nó thể hiện dữ liệu tốt hơn.