Deep Learning với Tensorflow Module 8 phần 2: Dự án xây dựng mô hình nhận diện giống chó trong ảnh
Bài viết này là phần tóm tắt quá trình thực hiện của dự án. Để xem toàn bộ nội dung bạn có thể đọc tại notebook project 2 dog breed idintification
Ở phần trước, chúng ta đã xử khởi tạo và train 2 mô hình efficientNetB0
và ResnetV50
. Sau khi hoàn tất quá trình train, chúng ta có thể thấy được hiệu năng học của mô hình efficientNetB0
vượt trội hơn hẳn so với đối thủ. Do đó, trong bài viết này, chúng ta sẽ đánh giá, kiểm định mô hình với tập dữ valid_data
, một tập dữ liệu có label mà nó chưa từng biết đến và tiến hành dự đoán với tập dữ test
, một tập liệu chỉ có data, không có label.
Nội dung phần 2 của bài viết này bao gồm : 4. Đánh giá và dự đoán mô hình trên dữ liệu kiểm địn. 5. Mô hình dự đoán dữ liệu test.
Đánh giá và dự đoán mô hình trên dữ liệu kiểm định
Trước tiên chúng ta sẽ load lai mô hình tốt nhất đã được lưu ở phần trên
loaded_model = tf.keras.models.load_model(save_dir)
Đánh giá mô hình kiểm định
result_loaded_model = loaded_model.evaluate(valid_data) result_loaded_model
64/64 [==============================] - 40s 131ms/step - loss: 0.5578 - accuracy: 0.8264 [0.5578241348266602, 0.8264058828353882]
Dự đoán mô hình từ dữ liệu kiểm định
Mô hình có khả năng dự đoán chính xác đến >82% trên dữ liệu kiểm định (valid_data). Chúng ta sẽ tiến hành dự đoán của dữ liệu kiểm định này.
y_pred_probs = loaded_model.predict(valid_data,verbose=1) y_pred_probs
64/64 [==============================] - 9s 107ms/step array([[6.5913167e-07, 1.1576774e-06, 3.4290874e-06, ..., 4.4346267e-05, 1.2099714e-04, 7.5360936e-06], [1.5267351e-05, 1.2430275e-03, 7.7208351e-06, ..., 6.8555386e-07, 6.8753314e-09, 9.0866801e-05], [6.1690498e-06, 1.2055059e-03, 5.3473159e-06, ..., 2.6101031e-04, 1.6322512e-05, 9.0042965e-07], ..., [7.4642890e-07, 2.6508731e-05, 4.0508489e-06, ..., 5.9246922e-08, 1.4373866e-07, 8.6109121e-06], [1.2227687e-08, 7.9480897e-06, 1.6391324e-07, ..., 8.1840831e-08, 2.4569371e-08, 1.8823050e-08], [2.6653557e-05, 8.2158255e-07, 1.4097719e-05, ..., 3.1437924e-07, 2.4546750e-07, 1.3475732e-06]], dtype=float32)
print(y_pred_probs[0]) print(f"Max value (probability of prediction): {np.max(y_pred_probs[0])}") # the max probability value predicted by the model print(f"Sum: {np.sum(y_pred_probs[0])}") # because we used softmax activation in our model, this will be close to 1 print(f"Max index: {np.argmax(y_pred_probs[0])}") # the index of where the max value in y_pred_probs[0] occurs print(f"Predicted label: {class_names[np.argmax(y_pred_probs[0])]}") # the predicted label
[6.59131672e-07 1.15767739e-06 3.42908743e-06 1.34482616e-06 2.72144393e-06 2.24939873e-03 2.05446649e-05 4.08853078e-03 4.59479601e-08 1.23227255e-05 1.21699777e-05 7.92457513e-07 1.35807604e-05 1.13655017e-06 1.35270781e-07 2.36507331e-05 8.28607426e-06 2.83578925e-06 3.55027532e-06 4.27549821e-04 7.71246334e-07 2.39637728e-07 1.09740422e-05 3.83496968e-07 7.51108109e-06 4.73344215e-07 4.23187475e-06 1.91630592e-04 2.71264554e-07 1.41822090e-02 9.09239688e-08 1.12810767e-06 4.62244110e-08 4.77692993e-06 6.86475744e-07 1.00719842e-06 4.71708699e-06 1.93983607e-04 6.79521705e-04 4.08069491e-06 1.43510442e-06 7.95306505e-07 9.10500967e-05 5.22384216e-05 2.46401271e-07 2.32510979e-06 1.18959879e-05 1.36721883e-06 3.84785039e-07 9.76687033e-07 9.20587718e-06 1.26313773e-06 1.84009650e-07 2.80832883e-05 1.80097197e-06 7.94137886e-05 6.76853347e-07 4.23452917e-07 1.00959005e-06 2.99948226e-07 2.08447949e-04 3.97579743e-06 3.34251240e-07 3.90628679e-03 7.60221474e-06 1.23964230e-06 1.04888659e-05 2.04075309e-06 6.85298710e-06 1.09860522e-07 3.41395207e-07 1.95007124e-06 3.06370457e-05 3.69814370e-06 3.01278080e-04 1.18720410e-02 4.18014361e-06 7.60696412e-06 8.89284095e-08 6.08327991e-06 9.92018886e-06 6.04058096e-06 2.05763499e-07 2.63642249e-07 6.56740594e-05 6.70272414e-07 2.59109202e-05 1.62895390e-06 3.74019851e-06 4.62858179e-06 2.12962675e-07 2.64723235e-06 1.71348855e-08 1.93049691e-05 1.30704268e-06 3.09367861e-05 2.76060177e-06 7.19350101e-06 2.68925351e-06 3.00725742e-06 9.33815772e-06 1.93890119e-05 3.09747193e-05 3.41470724e-07 7.55873089e-06 4.06836705e-07 3.32941954e-06 9.64473159e-08 5.73803959e-07 2.00685932e-07 7.24479924e-06 9.60674286e-01 1.66857922e-06 3.19610699e-05 7.86470594e-07 8.68299082e-07 2.62349840e-05 4.43462668e-05 1.20997138e-04 7.53609356e-06] Max value (probability of prediction): 0.9606742858886719 Sum: 0.9999998211860657 Max index: 111 Predicted label: toy_terrier
y_pred_probs
là một mảng gồm 2045 phần tử đại diện cho 2045 hình ảnh, mỗi phần tử trong mảng lớn này lại là một mảng gồm 120 phần tử đại diện cho 120 class, và mỗi vị trí trong 120 phần tử này thể hiện xác suất có thể xảy ra cho class đó. Chúng ta sẽ lấy vị trí nào mà phần tử có giá trị lớn nhất trong mảng con làm đại diện dự đoán cho dữ liệu hình ảnh đó.
y_pred_labels = tf.argmax(y_pred_probs,axis=1).numpy() y_pred_labels
array([111, 56, 97, ..., 49, 49, 91])
Trước đây, label của chúng ta được biểu diễn dưới dạng mảng gồm 120 phần tử, nên bây giơ cũng làm tương tự như trên, lấy vị trí nào có giá trị lớn nhất làm vị trí đại diện cho dữ liệu hình ảnh đó.
y_true_labels = tf.argmax(y_valid, axis=1).numpy() y_true_labels
array([111, 56, 97, ..., 56, 49, 67])
Để đánh giá mô hình phân loại, có khá nhiều phương pháp. Chúng ta sẽ sử dụng một số phương pháp phổ biến như confusion_matrix
, accuracy_score
, classification_report
... Tất cả đều có sẵn trong sklearn
hoặc tf.metrics
.
from sklearn.metrics import confusion_matrix, accuracy_score
Ở phần Đánh giá mô hình kiểm định, bạn có thấy accuracy của nó là 0.8264
không, con số đó được tính bằng cách lấy số mẫu dự đoán đúng / tổng số mẫu.
Có thể thực hiện bằng phương pháp accuracy_score
:
accuracy_score(y_true_labels, y_pred_labels) -> 0.8264058679706602
Độ chính xác 0.8264
chỉ là đánh giá tổng thể tất cả các dữ liệu trong mô hình. Nếu muốn biết cụ thể class nào dự đoán chính xác nhất, class nào dự đoán kém nhất, hoặc bạn muốn quan tâm khả năng dự đoán của một class nào đó thì bạn sẽ làm sao?
confusion_matrix
sẽ giúp bạn làm điều này, nhưng nếu để nó hiển thị dưới dạng ma trận thì sẽ không được trực quan. Do đó, trong utility_function.py
đã xây dựng sẵn hàm biểu diễn confusion_matrix
mà bạn có thể tận dụng lại đó là plot_confusion_matrix()
, với các tham số:
true_labels
list : các label của dữ liệu thựcpred_labels
list : các label của dữ liệu dự đoánclass_names
list (mặc địnhNone
) : Danh sách các class_names nếu có (chúng ta có 120 giống chó đã được định nghĩa thành class_names ở phầnKhám phá dữ liệu
)norm
bool (mặc địnhTrue
) : liệu có quy ra thành tỉ lệ dự đoán ở mỗi phần tử hay không.
from utility_functions import plot_confusion_matrix
Vì class_names
đang thuộc kiểu numpy.array
, cần phải ép thành kiểu list thì hàm này mới hoạt động được.
plot_confusion_matrix(y_true_labels, y_pred_labels, list(class_names) )
![](http://images.ctfassets.net/tln063yrioga/2EcZLXXSu33I5KgqpdxPHA/6bf65d6e3805a9e2617871ee4f56a445/dog_breed_identication_output_123_0.png)
Tiếp theo, chúng ta sẽ dự đoán hình ảnh ngẫu nhiên từ tập dữ liệu kiểm định. Vì khi đưa vào mô hình, tập dữ liệu kiểm định được phân thành nhiều cụm, nên bây giờ chúng ta sẽ phải đưa dữ liệu từ các cụm đó trở về với vị trí tuần tự như ban đầu. Đầu tiên chúng ta sẽ tạo một hàm tên là unbatchify_data(data)
, sau đó tạo một biến kiểu list tên là images
và labels
để qua mỗi vòng lặp sử dụng phương thức unbatch()
có thể đẩy dữ liệu đó vào trong list.
def unbatchify_data(data) : images = [] labels = [] for image, label in data.unbatch() : images.append(image) labels.append(tf.argmax(label)) return images, labels images, labels = unbatchify_data(valid_data)
Hàm plot_pred_conf
sẽ giúp chúng ta tạo biểu đồ thể hiện những xác suất dự đoán tốt nhất cho một dữ liệu hình ảnh được dự đoán. Hàm này gồm các tham số :
+ pred_prob
list: mảng gồm 120 phần tử, mỗi phần tử thể hiện xác suất của nó
+ true_label
str (mặc định None
) : Giá trị thực sự của dữ liệu hình ảnh nếu có,
+ n
int (mặc định 10) : Top các giá trị dự đoán lớn nhất.
def plot_pred_conf(pred_prob, true_label=None, n=10) : pred_prob = np.squeeze(pred_prob) top_n_pred_indices = np.argsort(pred_prob)[:-n:-1] top_n_pred_values = pred_prob[[top_n_pred_indices]] top_n_pred_labels = np.array(class_names)[[top_n_pred_indices]] top_plot = plt.bar(range(len(top_n_pred_values)),top_n_pred_values) plt.xticks(labels=top_n_pred_labels, ticks=range(n),rotation=90) if true_label and np.isin(true_label, top_n_pred_labels) : top_plot[np.argmax(top_n_pred_labels==true_label)].set_color("green") else : for plot_item in top_plot: plot_item.set_color("gray") for plot_item in top_plot : x,h = plot_item.get_x(), plot_item.get_height() plt.text(x,h, f"{h:.2f}", ha="left", va="bottom")
Mọi thứ đã sẵn sàng, chúng ta sẽ tạo hàm đê dự đoán dữ liệu hình ảnh ngẫu nhiên, cũng như biểu diễn dữ liệu đó thành hình ảnh và biểu đồ cột thống kê top những xác suất có khả năng xảy ra cao nhất.
import random import math def plot_and_predict_random_images(model,images,labels=None, n_samples=1) : random_image_indices = random.sample(range(len(images)), k=n_samples) images = [ images[i] for i in random_image_indices] if labels : labels = [labels[i] for i in random_image_indices] n_cols = 2 n_rows = math.ceil(n_samples/n_cols) fig, axes = plt.subplots(figsize=(n_cols*5*2, n_rows*5)) fig.tight_layout() for i in range(n_samples) : image = images[i] label = None if labels : label = labels[i] pred_prob = model.predict(tf.expand_dims(image, axis=0)) pred_label = tf.squeeze(tf.argmax(pred_prob,axis=1)).numpy() color = "black" if label : color = "red" if pred_label == label : color = "green" plt.subplot(n_rows, n_cols*2, 2*i+1) plt.imshow(image/255.) plt.axis(False) if label : plt.title(f"Actual: {class_names[label]}\nPredict: {class_names[pred_label]}") else : plt.title(f"Predict: {class_names[pred_label]}") plt.subplot(n_rows, n_cols*2, 2*i+2) if label : plot_pred_conf(pred_prob, class_names[label]) else : plot_pred_conf(pred_prob)
plot_and_predict_random_images(loaded_model, images, labels, 10)
![](http://images.ctfassets.net/tln063yrioga/6ij8HCBvDteNi94Uo8Ota4/6e29f8d2e16b6266c5f130ee3d2ebf2c/dog_breed_identication_output_130_1.png)
Chúng ta có thể dễ dàng đánh giá được kết quả dự đoán qua biểu đồ cùng với hình ảnh trực quan. Vì dữ liệu kiểm định valid_data
của chúng ta có sẵn label
nên có thể dễ dạng đánh giá.
Bây giờ, chúng ta sẽ sử dụng mô hình để dự đoán với dữ liệu test
.
5. Mô hình dự đoán dữ liệu test.
Tạo đường dẫn liên kết đến tập dữ liệu test
.
test_dir = "dog-breed-identification/test"
Khám phá dữ liệu test
walk_through_directory(test_dir)
Có 0 thư mục và 10357 tập tin trong thư mục dog-breed-identification/test
Tạo list đường dẫn đến các file ảnh trong dữ liệu test
test_image_paths = [] for image_name in os.listdir(test_dir) : test_image_paths.append(os.path.join(test_dir, image_name)) test_image_paths[:10]
['dog-breed-identification/test/719c20e68567910305db04be473df3cb.jpg', 'dog-breed-identification/test/8db6b8f62434b16f4c83a6b807a322ff.jpg', 'dog-breed-identification/test/380dd7b2b1c76c3c91a65b4b35d1f0ea.jpg', 'dog-breed-identification/test/97b6a6178a31ed3c4c5e67bb4dcc7a9c.jpg', 'dog-breed-identification/test/27a5ccc9944d0a7081814a481a02a880.jpg', 'dog-breed-identification/test/5e193ae2c366405e230a53daa4fb7721.jpg', 'dog-breed-identification/test/fd0a3ceca8806d5d63f72fb57c0a73c0.jpg', 'dog-breed-identification/test/83b3a854863d6e7047bee089969663ff.jpg', 'dog-breed-identification/test/bd4211cd31953f8ada0a80791a37cf73.jpg', 'dog-breed-identification/test/b3bdba23a9105fe502fc2b661f215cd8.jpg']
Để mô hình có thể dự đoán được dữ liệu thì dữ liệu đó phải có hình dạng tương đồng với dữ liệu mà mô hình đó train. Vì trước đó, dữ liệu train_data
và valid_data
được đều được tiền xử lý hình ảnh kèm theo label và sau đó đưa vào thành từng cụm để mô hình train, cho nên test_data
cũng cần phải đưa vào thành từng cụm nhưng không có label. Và hàm create_data_batches()
sẽ giúp tiền xử lý dữ liệu và đưa chúng thành từng cụm
test_data = create_data_batches(test_image_paths,test_data=True) test_data
Đang xử lý và chuyển dữ liệu test thành từng cụm. Đã xử lý xong! 💡 <BatchDataset shapes: (None, 224, 224, 3), types: tf.float32>
OK,test_data
đã sẵn sàng, tiền hành dự đoán thôi!!!
test_pred_probs = loaded_model.predict(test_data,verbose=1)
324/324 [==============================] - 36s 110ms/step
Cũng tương tự như phần kiểm định mô hình, chúng ta sẽ có một mảng lớn là tập hợp của 10365 mảng con với 120 phần tử đại diện cho xác suất có thể xảy ra của mỗi class trong mảng. Chúng ta sẽ lấy vị trí mà phần tử có giá trị (xác suất) lớn nhất để làm đại diện dự đoán cho mảng con đó.
test_pred_labels = tf.argmax(test_pred_probs,axis=1).numpy() test_pred_labels
array([84, 32, 57, ..., 24, 42, 57])
Tạo bảng thống kê các giá trị dự đoán của mỗi hình ảnh trong dữ liệu test
với pd.DataFrame()
test_df = pd.DataFrame({ "image_path" : test_image_paths, "conf_pred" : tf.reduce_max(test_pred_probs,axis=1).numpy(), "pred_label" : test_pred_labels, "pred_name" : [class_names[pred_label] for pred_label in test_pred_labels] }) test_df
image_path | conf_pred | pred_label | pred_name | ||||||
---|---|---|---|---|---|---|---|---|---|
0 | dog-breed-identification/test/719c20e685679103... | 0.990463 | 84 | papillon | |||||
1 | dog-breed-identification/test/8db6b8f62434b16f... | 0.985289 | 32 | cocker_spaniel | |||||
2 | dog-breed-identification/test/380dd7b2b1c76c3c... | 0.993548 | 57 | irish_terrier | |||||
3 | dog-breed-identification/test/97b6a6178a31ed3c... | 0.816491 | 94 | samoyed | |||||
4 | dog-breed-identification/test/27a5ccc9944d0a70... | 0.643474 | 112 | vizsla | |||||
... | ... | ... | ... | ... | |||||
10352 | dog-breed-identification/test/9e8232b5e5ad1976... | 0.407704 | 112 | vizsla | |||||
10353 | dog-breed-identification/test/ed63374c99282b30... | 0.801641 | 28 | chesapeake_bay_retriever | |||||
10354 | dog-breed-identification/test/70284866addb982f... | 0.981648 | 24 | brittany_spaniel | |||||
10355 | dog-breed-identification/test/c1bae285fa572caf... | 0.980637 | 42 | entlebucher | |||||
10356 | dog-breed-identification/test/a72fcf5fcbb929fd... | 0.358932 | 57 | irish_terrier |
10357 rows × 4 columns
test_images = [] for image in test_data.unbatch(): test_images.append(image)
Biểu diễn kết quả dự đoán bằng hình ảnh cũng như biểu đồ những class nào có xác suất xảy ra cao nhất
plot_and_predict_random_images(loaded_model,test_images,labels=None,n_samples=5)
![](http://images.ctfassets.net/tln063yrioga/7GwJXTDmntlGwCABv7dhOz/db68fabe1e95624bc3ce116ddb8d6f38/dog_breed_identication_output_149_1.png)