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

MVT
Đang cập nhật

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 efficientNetB0ResnetV50. 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ực
  • pred_labels list : các label của dữ liệu dự đoán
  • class_names list (mặc định None) : 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ần Khám phá dữ liệu)
  • norm bool (mặc định True) : 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

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) )

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à imageslabels để 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)

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)
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_datavalid_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_pathconf_predpred_labelpred_name
0dog-breed-identification/test/719c20e685679103...0.99046384papillon
1dog-breed-identification/test/8db6b8f62434b16f...0.98528932cocker_spaniel
2dog-breed-identification/test/380dd7b2b1c76c3c...0.99354857irish_terrier
3dog-breed-identification/test/97b6a6178a31ed3c...0.81649194samoyed
4dog-breed-identification/test/27a5ccc9944d0a70...0.643474112vizsla
...............
10352dog-breed-identification/test/9e8232b5e5ad1976...0.407704112vizsla
10353dog-breed-identification/test/ed63374c99282b30...0.80164128chesapeake_bay_retriever
10354dog-breed-identification/test/70284866addb982f...0.98164824brittany_spaniel
10355dog-breed-identification/test/c1bae285fa572caf...0.98063742entlebucher
10356dog-breed-identification/test/a72fcf5fcbb929fd...0.35893257irish_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)


Bài viết có liên quan