Văn Công Minh Triết (Triết Harry)
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # **Phương pháp Transfer Learning và Data Augumentation cho xử lý thiếu data** - **Thành viên:** - Phạm Hoàng Phúc - Phan Đình Minh Quân - Huỳnh Chí Tài - Nguyễn Hoàng Phúc Thịnh - Văn Công Minh Triết # **I. Giới thiệu chung** Trong quá trình phát triển mô hình, thường xuyên xuất hiện tình huống mà mô hình dự báo không đạt được độ chính xác mong muốn, dù đã sử dụng các kiến trúc phức tạp và tiên tiến nhất. Trong trường hợp này, việc xác định nguyên nhân gây ra sự không chính xác là một thách thức. Mặc dù có sự nghi ngờ về việc dữ liệu được gán nhãn không chính xác, nhưng sau khi kiểm tra, không tìm thấy vấn đề nào liên quan đến việc gán nhãn. Do đó, câu hỏi đặt ra là tại sao mô hình lại không thể dự báo chính xác? Quá trình huấn luyện một mô hình trí tuệ nhân tạo trên dữ liệu từ đầu thường không đem lại kết quả tốt và có thể dẫn đến lãng phí tài nguyên tính toán. Trong bài viết này, chúng tôi sẽ giải thích các nguyên nhân chính dẫn đến hiệu suất huấn luyện không tốt và giới thiệu một phương pháp phổ biến giúp cải thiện độ chính xác và tiết kiệm thời gian. Phương pháp này dựa trên ý tưởng chuyển giao tri thức đã được học từ các mô hình hiệu quả trước đó, được biết đến là transfer learning. ### **1.1. Nguyên nhân mô hình dự báo kém** Nếu ta loại bỏ các vấn đề liên quan đến dữ liệu như gán nhãn không chính xác, ảnh mờ, bị che khuất, và nhiều vấn đề khác, thì nguyên nhân thường dẫn đến hiệu suất dự báo kém của mô hình là: - Dữ liệu nhỏ và không đại diện là một vấn đề phổ biến. Khi bộ dữ liệu quá nhỏ, mô hình không thể học được các đặc trưng tổng quát, dẫn đến khả năng áp dụng kém khi phải đối mặt với các tác vụ phân loại mới. Ví dụ, nếu chúng ta chỉ có 100 ảnh chó và mèo từ Việt Nam trong bộ dữ liệu, đó là một mẫu nhỏ hơn so với các loài chó và mèo trên toàn thế giới. Sử dụng mô hình được huấn luyện trên một bộ dữ liệu nhỏ có thể dẫn đến dự đoán không chính xác khi đối mặt với dữ liệu mới và đa dạng hơn. - Mô hình mất cân bằng dữ liệu gây ra khó khăn trong việc dự đoán các mẫu thuộc nhóm thiểu số. Điều này làm giảm khả năng mô hình nhận biết và phân loại đúng các trường hợp thuộc nhóm ít xuất hiện. - Trong trường hợp các bộ dữ liệu lớn với hàng triệu ảnh, các mô hình có kiến trúc phức tạp thường có khả năng mang lại độ chính xác cao. Tuy nhiên, khi đối diện với các bộ dữ liệu nhỏ, các mô hình phức tạp có thể giảm độ chính xác do hiện tượng overfitting. - Quá trình tối ưu hóa có thể gặp khó khăn khiến bạn đối mặt với các vấn đề như thiết lập learning rate không phù hợp, dẫn đến việc mô hình mất thời gian huấn luyện và không đạt được điểm global optimal. Trong trường hợp này, bạn có thể xem xét việc thay đổi phương pháp cập nhật gradient descent và thiết lập lịch trình learning rate. Trên TensorFlow Keras, bạn có thể thiết lập lịch trình learning rate thông qua CheckPoint như sau: ```python= import tensorflow as tf def scheduler(epoch): if epoch < 10: return 0.001 else: return 0.001 * tf.math.exp(0.1 * (10 - epoch)) callback = tf.keras.callbacks.LearningRateScheduler(scheduler) your_model.fit(data, labels, epochs=100, callbacks=[callback], validation_data=(val_data, val_labels)) ``` ### **1.2. Vai trò của transfer learning** #### **1.2.1. Chuyển giao tri thức** Trong thời kỳ phát triển mạnh mẽ của deep learning, tài nguyên về trí tuệ nhân tạo ngày càng phong phú. Đồng thời, số lượng các mô hình được huấn luyện trước với chất lượng cao và độ chính xác tăng lên. Hiện nay, hầu hết mọi lĩnh vực đều có sẵn các pretrained-model chất lượng. Lý thuyết về transfer learning được Lorien Pratt thử nghiệm lần đầu tiên vào năm 1993 và sau đó đã viết lại dưới dạng một lý thuyết toán học vào năm 1998. Ông đã thực hiện việc hiện thực hóa ý tưởng về việc chuyển giao tri thức giữa các mô hình, tương tự như cách con người chia sẻ tri thức với nhau. Một mô hình có khả năng sử dụng lại kiến thức đã được huấn luyện trước đó và cải thiện hiệu suất trên tác vụ phân loại của nó. #### **1.2.2. Cải thiện accuracy và tiết kiệm chi phí huấn luyện** Ví dụ, trong bài toán phân loại chó và mèo, nếu bạn bắt đầu huấn luyện từ đầu, bạn sẽ cần nhiều epochs hơn để đạt được độ chính xác mong đợi. Tuy nhiên, nếu bạn tận dụng lại các pretrained-model, bạn sẽ cần ít epochs hơn để đạt được cùng một độ chính xác, thậm chí độ chính xác có thể cao hơn so với việc không sử dụng transfer learning. ![sơ đồ hiệu suất](https://hackmd.io/_uploads/B1dU_Ug6T.jpg) Hình 1: Sơ đồ so sánh hiệu suất mô hình trước và sau khi áp dụng transfer learning. (Nguồn: Handbook Of Research On Machine Learning Applications and Trends: Algorithms, Methods and Techniques). Từ đồ thị ta có thể thấy sử dụng transfer learning sẽ mang lại 3 lợi thế chính: - Có điểm khởi đầu của accuracy tốt hơn (higher start). - Accuracy có tốc độ tăng nhanh hơn (higher slope). - Đường tiệm cận của độ chính xác tối ưu cao hơn (higher asymptote). #### **1.2.3. Hiệu quả với dữ liệu nhỏ** Trong trường hợp bộ dữ liệu có kích thước quá nhỏ và khó mở rộng, các mô hình được huấn luyện từ chúng sẽ gặp khó khăn trong việc dự báo chính xác. Tuy nhiên, việc tận dụng lại tri thức từ các pretrained-model có cùng tác vụ phân loại sẽ giúp cải thiện hiệu suất dự báo của các mô hình. Điều này xảy ra vì các mô hình đã được huấn luyện trên cả hai nguồn tri thức: dữ liệu huấn luyện ban đầu và tri thức từ pretrained-model. # **II. Transfer learning** ### **2.1. Ví dụ về transfer learning** Quá trình chuyển giao tri thức từ một mô hình trước sang một bài toán hiện tại được gọi là transfer learning. Để hiểu rõ hơn, mình lấy ví dụ: Trong bài toán dự báo chó và mèo, khi cả hai nhãn này đều xuất hiện trong một bộ dữ liệu như ImageNet, chúng ta có kỳ vọng rằng có thể tận dụng lại các trọng số từ pretrained-model trên ImageNet để huấn luyện lại mô hình cho bài toán của chúng ta một cách nhanh chóng và chính xác hơn. ### **2.2. Kiến trúc mô hình sử dụng transfer learning** Như đã biết, các lớp của mạng nơ-ron tích chập (CNN) thực chất là các bộ trích xuất đặc trưng, trong đó mỗi lớp CNN sẽ thực hiện việc trích xuất các đặc trưng theo các cấp độ khác nhau. ![feature map](https://hackmd.io/_uploads/Syz69Ig6a.jpg) Hình 2: Các đặc trưng được học từ mạng CNN có sự khác biệt rõ rệt giữa các lớp Convolutional Layers. Ở những lớp đầu tiên, các bộ lọc thường tập trung vào việc phát hiện các chi tiết chung của ảnh như các nét ngang, nét dọc và các cạnh. Các đặc trưng này được gọi là đặc trưng bậc thấp và thường không đủ để nhận biết vật thể cụ thể. Tuy nhiên, ở những lớp Convolutional Layers cuối cùng, các đặc trưng đã được tổng hợp từ các đặc trưng bậc thấp và trở nên phức tạp hơn. Những đặc trưng này, gọi là đặc trưng bậc cao, thường mang lại khả năng phân loại chính xác và mạnh mẽ cho các lớp classes. Trong quá trình transfer learning, chúng ta sẽ tận dụng lại các đặc trưng đã được học từ các pretrained-model. Để hiểu rõ hơn về cách thức chuyển giao này, chúng ta cùng điều tra kiến trúc của mô hình sử dụng transfer learning. - Phrase 1: Base Network là một mạng được sử dụng để trích xuất đặc trưng từ dữ liệu, và nó được cấu tạo từ các Convolutional 2D Layers. Base Network thường được trích xuất từ một phần của pretrained-model sau khi loại bỏ các top fully connected layers. Để dễ hiểu, chúng ta có thể giả định rằng pretrained-model được sử dụng là VGG16, một kiến trúc CNN phát triển bởi Google vào năm 2014. Điểm cải tiến của VGG16 so với các kiến trúc CNN trước đó là việc sử dụng nhiều Convolutional 2D Layers liên tiếp nhau. Cụ thể, các lớp này có cấu trúc [[Conv]_n-MaxPool]_m thay vì [Conv-MaxPool]_m, trong đó, m và n là số lần xuất hiện của các khối mạng được lặp lại và được bao bọc trong ngoặc vuông. ![phrase 1](https://hackmd.io/_uploads/SJnJoLgTp.jpg) Hình 3: Kiến trúc của mạng VGG16 được sử dụng làm base network trong transfer learning. - Phrase 2: Các Fully Connected Layers đóng vai trò quan trọng trong việc giảm chiều dữ liệu và tính toán phân phối xác suất tại output. Bản chất của Fully Connected Layers là một mạng MLP (Multiple Layer Perceptron), đây là một kiến trúc nguyên thủy nhất của thuật toán neural network. Số lượng các đơn vị ở output layer thường bằng với số lượng classes trong bài toán phân loại. Các trọng số của các fully connected layers thường được khởi tạo một cách ngẫu nhiên để bắt đầu quá trình huấn luyện. ![phrase 2](https://hackmd.io/_uploads/BJgMoUlpp.jpg) Hình 4: Kiến trúc base network kết hợp với fully connected layers. Trong quá trình khởi tạo mô hình, chúng ta sẽ tận dụng lại các trọng số của base_network. Dữ liệu ảnh sau khi đi qua base_network sẽ tạo ra các đặc trưng tốt, đây là đầu vào $\mathbf{X}$ cho mạng MLP để dự báo $\hat{\mathbf{y}}$. Các hệ số $\mathbf{W}$ và $\mathbf{b}$ của MLP sẽ được khởi tạo ngẫu nhiên, trong khi các trọng số của base network sẽ được tải lại từ pretrained model. Để minh họa và đánh giá hiệu quả của transfer learning, chúng ta có thể thực hành trên bộ dữ liệu chứa hình ảnh của 'dog' và 'cat'. # **III. Thực hành** ### **3.1. Dataset** Dữ liệu được sử dụng để minh họa cho phương pháp transfer learning là bộ dữ liệu [Sub Dog and Cat](https://github.com/ardamavi/Dog-Cat-Classifier) với khoảng 1400 ảnh. ```python= from google.colab import drive import os drive.mount("/content/gdrive") path = 'gdrive/My Drive/Colab Notebooks/TransferLearning' os.chdir(path) os.listdir() ``` Chạy lệnh bên dưới để download dữ liệu và cd vào thư mục gốc ```python= !git clone https://github.com/ardamavi/Dog-Cat-Classifier.git %cd Dog-Cat-Classifier ``` Thực hiện khảo sát dữ liệu trước khi huấn luyện model. ```python= import pandas as pd import glob2 import matplotlib.pyplot as plt dogs = glob2.glob('Data/Train_Data/dog/*.jpg') dog_labels = ['dog']*len(dogs) cats = glob2.glob('Data/Train_Data/cat/*.jpg') cat_labels = ['cat']*len(cats) labels = dog_labels + cat_labels image_links = dogs + cats data = pd.DataFrame({'labels': labels, 'image_links':image_links}) data.groupby(labels).image_links.count().plot.bar() plt.title('Number of images in each class') plt.show() ``` ![TransferLearning_13_0](https://hackmd.io/_uploads/BywSXvJaT.png) Ta thấy dữ liệu giữa 2 classes là cân bằng với mỗi loại khoảng 700 ảnh. Như vậy chúng ta không xảy ra hiện tượng mất cân bằng dữ liệu. #### **3.1.1.Phân chia tập train/validation** Một phần quan trọng của quá trình huấn luyện mô hình là phân chia tập dữ liệu thành tập train và tập validation. Dữ liệu sẽ được huấn luyện trên tập train và kiểm định trên tập validation. Một số quy trình phát triển mô hình còn phân chia thêm tập dev để điều chỉnh tham số giữa các mô hình và tập test để kiểm định mô hình trên dữ liệu thực tế mà người dùng sinh ra. Tuy nhiên, để đơn giản, chúng ta sẽ chỉ sử dụng tập train và tập validation. Sau khi chia tập dữ liệu thành tập train và tập test theo tỷ lệ 80/20, để đảm bảo cân bằng giữa các lớp trong hai tập dữ liệu, ta nên sử dụng hàm train_test_split của thư viện sklearn với tham số stratify=y. ```python= from sklearn.model_selection import train_test_split images_train, images_val, y_label_train, y_label_val = train_test_split(image_links, labels, stratify = labels) print('images_train len: {}, image_test shape: {}'.format(len(images_train), len(images_val))) ``` #### **3.1.2.Data Augumentation** Độ chính xác của một mô hình thường phụ thuộc vào hai yếu tố chính: kiến trúc của mô hình và kỹ thuật data augmentation. Đặc biệt đối với các bài toán có ít dữ liệu, việc áp dụng data augmentation sẽ giúp tăng số lượng mẫu huấn luyện và cải thiện chất lượng của mô hình. ##### **3.1.2.1. Định Nghĩa** Data augmentation là quá trình tạo ra các phiên bản mới của dữ liệu huấn luyện bằng cách áp dụng các phép biến đổi. Mục đích chính của data augmentation là tăng số lượng và sự đa dạng của dữ liệu huấn luyện, từ đó cải thiện khả năng và hiệu suất của mô hình. Một số phương thức data aumentation cơ bản cho thị giác máy: ![image](https://hackmd.io/_uploads/ByL6Pigaa.png) - Original (Ảnh gốc): Dĩ nhiên rằng, ảnh gốc luôn có sẵn cho chúng ta - Flip (Lật): Việc lật ảnh theo chiều dọc hoặc ngang, miễn là ý nghĩa của ảnh (label) được giữ nguyên hoặc suy ra được, được thực hiện. Ví dụ, trong trường hợp nhận dạng quả bóng tròn, dù lật ảnh theo bất kỳ hướng nào cũng sẽ vẫn nhận ra quả bóng. Tuy nhiên, với việc nhận dạng chữ viết tay, lật số 8 vẫn là 8, nhưng 6 sẽ trở thành 9 (theo chiều ngang), và không có số nào nếu lật theo chiều dọc. Trong trường hợp nhận dạng ảnh y tế, việc lật ảnh từ trên xuống dưới là không thể xảy ra trong thực tế, vì vậy không cần phải thực hiện việc lật ảnh. - Random crop (Cắt ngẫu nhiên): Khi cắt ngẫu nhiên một phần của bức ảnh, cần lưu ý rằng phần được cắt phải giữ nguyên thành phần chính mà ta quan tâm trong bức ảnh. Ví dụ, trong bài toán nhận diện vật thể, nếu phần ảnh bị cắt không chứa vật thể, thì nhãn của ảnh sẽ không chính xác. ![image](https://hackmd.io/_uploads/BkRTvjl6T.png) - Color shift (Chuyển đổi màu): Chuyển đổi màu của bức ảnh bằng cách thêm giá trị vào 3 kênh màu RGB có thể làm thay đổi sắc thái màu sắc của ảnh. Điều này có thể liên quan đến các ảnh chụp trong điều kiện ánh sáng không đồng đều hoặc bị nhiễu, gây ảnh hưởng đến màu sắc của ảnh. - Noise addition (Thêm nhiễu): Thêm nhiễu vào bức ảnh có thể làm thay đổi độ rõ nét và chất lượng của ảnh. Có nhiều loại nhiễu khác nhau, bao gồm nhiễu ngẫu nhiên, nhiễu có mẫu, nhiễu cộng, nhiễu nhân, nhiễu do nén ảnh, nhiễu mờ do chụp không lấy nét, và nhiễu mờ do chuyển động. Mỗi loại nhiễu có ảnh hưởng riêng đến chất lượng và độ rõ nét của ảnh, và cần được xử lý phù hợp tùy thuộc vào mục đích sử dụng của ảnh. - Information loss (Mất thông tin): Một phần của bức hình bị mất có thể được minh họa bằng trường hợp bị che khuất. Trong trường hợp này, một đối tượng hoặc một phần của đối tượng trong bức ảnh bị che khuất bởi các vật thể khác, cấu trúc bên ngoài hoặc vật cản khác. Việc bị che khuất có thể làm giảm sự trọn vẹn của hình ảnh và ảnh hưởng đến khả năng nhận diện hoặc hiểu đối tượng trong bức ảnh. - Constrast change (Đổi độ tương phản): Thay đổi độ tương phản và độ bão hòa của bức hình có thể làm thay đổi cảm nhận về màu sắc và sự sắc nét của ảnh. Độ tương phản là mức độ khác biệt giữa các điểm sáng và tối trong bức ảnh, trong khi độ bão hòa liên quan đến độ tươi sáng và độ sâu của màu sắc. Bằng cách điều chỉnh độ tương phản và độ bão hòa, chúng ta có thể tạo ra các hiệu ứng khác nhau trên ảnh, từ việc làm nổi bật các chi tiết đến việc tạo ra một không gian màu sắc phong phú hơn. Với class ImageDataGenerator thường có các thuộc tính sau : - zoom_range: thực hiện zoom ngẫu nhiên trong một phạm vi nào đó - width_shift_range: Dịch theo chiều ngang ngẫu nhiên trong một phạm vi nào đó - height_shift_range: Dịch ảnh theo chiều dọc trong một phạm vi nào đó - brightness_range: Tăng cường độ sáng của ảnh trong một phạm vi nào đó. - vertical_flip: Lật ảnh ngẫu nhiên theo chiều dọc - rotation_range: Xoay ảnh góc tối đa là 45 độ - shear_range: Làm méo ảnh ##### **3.1.2.2. Thực Hành** Để thực hiện data augumentation trên tensorflow, chúng ta có thể config ngay trên ImageDataGenerator. ```python= import numpy as np from tensorflow.keras.utils import Sequence, to_categorical import cv2 class DataGenerator(Sequence): 'Generates data for Keras' def __init__(self, all_filenames, labels, batch_size, index2class, input_dim, n_channels, n_classes=2, normalize=True, zoom_range=[0.8, 1], rotation=15, brightness_range=[0.8, 1], shuffle=True): ''' all_filenames: list toàn bộ các filename labels: nhãn của toàn bộ các file batch_size: kích thước của 1 batch index2class: index của các class input_dim: (width, height) đầu vào của ảnh n_channels: số lượng channels của ảnh n_classes: số lượng các class normalize: có chuẩn hóa ảnh hay không? zoom_range: khoảng scale zoom là một khoảng nằm trong [0, 1]. rotation: độ xoay ảnh. brightness_range: Khoảng biến thiên cường độ sáng shuffle: có shuffle dữ liệu sau mỗi epoch hay không? ''' self.all_filenames = all_filenames self.labels = labels self.batch_size = batch_size self.index2class = index2class self.input_dim = input_dim self.n_channels = n_channels self.n_classes = n_classes self.shuffle = shuffle self.normalize = normalize self.zoom_range = zoom_range self.rotation = rotation self.brightness_range = brightness_range self.on_epoch_end() def __len__(self): ''' return: Trả về số lượng batch/1 epoch ''' return int(np.floor(len(self.all_filenames) / self.batch_size)) def __getitem__(self, index): ''' params: index: index của batch return: X, y cho batch thứ index ''' # Lấy ra indexes của batch thứ index indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size] # List all_filenames trong một batch all_filenames_temp = [self.all_filenames[k] for k in indexes] # Khởi tạo data X, y = self.__data_generation(all_filenames_temp) return X, y def on_epoch_end(self): ''' Shuffle dữ liệu khi epochs end hoặc start. ''' self.indexes = np.arange(len(self.all_filenames)) if self.shuffle == True: np.random.shuffle(self.indexes) def __data_generation(self, all_filenames_temp): ''' params: all_filenames_temp: list các filenames trong 1 batch return: Trả về giá trị cho một batch. ''' X = np.empty((self.batch_size, *self.input_dim, self.n_channels)) y = np.empty((self.batch_size), dtype=int) # Khởi tạo dữ liệu for i, fn in enumerate(all_filenames_temp): # Đọc file từ folder name img = cv2.imread(fn) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, self.input_dim) img_reshape = img.reshape(-1, 3) if self.normalize: mean = np.mean(img_reshape, axis=0) std = np.std(img_reshape, axis=0) img = (img-mean)/std if self.zoom_range: zoom_scale = 1/np.random.uniform(self.zoom_range[0], self.zoom_range[1]) (h, w, c) = img.shape img = cv2.resize(img, (int(h*zoom_scale), int(w*zoom_scale)), interpolation = cv2.INTER_LINEAR) (h_rz, w_rz, c) = img.shape start_w = np.random.randint(0, w_rz-w) if (w_rz-w) > 0 else 0 start_h = np.random.randint(0, h_rz-h) if (h_rz-h) > 0 else 0 # print(start_w, start_h) img = img[start_h:(start_h+h), start_w:(start_w+w), :].copy() if self.rotation: (h, w, c) = img.shape angle = np.random.uniform(-self.rotation, self.rotation) RotMat = cv2.getRotationMatrix2D(center = (w, h), angle=angle, scale=1) img = cv2.warpAffine(img, RotMat, (w, h)) if self.brightness_range: scale_bright = np.random.uniform(self.brightness_range[0], self.brightness_range[1]) img = img*scale_bright label = 'dog' if 'dog' in fn else 'cat' label = self.index2class[label] X[i,] = img # Lưu class y[i] = label return X, y dict_labels = { 'dog': 0, 'cat': 1 } train_generator = DataGenerator( all_filenames = images_train, labels = y_label_train, batch_size = 32, index2class = dict_labels, input_dim = (224, 224), n_channels = 3, n_classes = 2, normalize = False, zoom_range = [0.5, 1], rotation = False, brightness_range=[0.8, 1], shuffle = True ) val_generator = DataGenerator( all_filenames = images_val, labels = y_label_val, batch_size = 16, index2class = dict_labels, input_dim = (224, 224), n_channels = 3, n_classes = 2, normalize = False, zoom_range = [0.5, 1], rotation = False, brightness_range =[0.8, 1], shuffle = False ) ``` Mình sẽ lý giải các bước xử lý chính: normalize: Có thể thực hiện việc thuẩn hóa mỗi ảnh theo phân phối chuẩn bằng cách trừ đi giá trị trung bình và chia cho độ lệch chuẩn của toàn bộ các pixels tương ứng trong mỗi kênh màu. Điều này giúp đưa các giá trị pixel về cùng một khoảng biến thiên và làm cho phân phối của chúng gần với phân phối chuẩn. zoom_range: Là một khoảng giá trị phóng đại ảnh: [lower, upper]. Giá trị phóng đại của một ảnh sẽ được sinh ngẫu nhiên trong khoảng zoom_range. Giá trị phóng đại này càng nhỏ, thì ảnh sẽ càng được phóng to. rotation: Góc xoay ngẫu nhiên của một bức ảnh thường được thiết lập từ 10 đến 20 độ. brightness_range: Khoảng điều chỉnh độ sáng cho bức ảnh được xác định bằng một giá trị ngẫu nhiên trong khoảng [minVal, maxVal]. #### **3.1.3. Kiểm tra dữ liệu Augumentation** Chúng ta không nên hoàn toàn phụ thuộc vào Augmentation mà cần kiểm tra lại xem các bước biến đổi trên pipeline đã làm thay đổi dữ liệu như thế nào. Cần xem xét liệu những biến đổi đó có tạo ra các mẫu phù hợp với thực tế không. Điều này là cần thiết trong quá trình huấn luyện mô hình để đảm bảo rằng dữ liệu được xử lý một cách chính xác và có ý nghĩa với bài toán cụ thể mà chúng ta đang làm việc. Để kiểm tra pipeline của ImageGenerator, chúng ta có thể khởi tạo một vòng lặp loop qua Generator như sau: ```python= check_aug=['Data/Train_Data/cat/cat.100.jpg']*32 check_generator = DataGenerator( all_filenames = check_aug, labels = y_label_val, batch_size = 20, index2class = dict_labels, input_dim = (224, 224), n_channels = 3, n_classes = 2, normalize = False, zoom_range = [0.5, 1], rotation = 15, brightness_range = [0.5, 1.5], shuffle = False ) ``` Lấy ra một batch với kích thước là 20. ```python= X_batch, y_batch = check_generator.__getitem__(0) print(X_batch.shape) print(y_batch.shape) ``` ```python= (20, 224, 224, 3) (20,) ``` Tiếp theo ta sẽ visualize các ảnh sau augumentation ```python= import matplotlib.pyplot as plt # Khởi tạo subplot với 4 dòng 5 cột. fg, ax = plt.subplots(4, 5, figsize=(20, 16)) fg.suptitle('Augumentation Images') for i in np.arange(4): for j in np.arange(5): ax[i, j].imshow(X_batch[i + j + j*i]/255.0) ax[i, j].set_xlabel('Image '+str(i+j+j*i)) ax[i, j].axis('off') plt.show() ``` (chèn ảnh con mèo 4 dòng 5 cột ở đây) Ta có thể thấy với cùng một bức ảnh, đã được sinh ra nhiều biến thể khác nhau. Các thay đổi tập trung chủ yếu ở 3 khía cạnh sau: Góc xoay của ảnh. Cường độ sáng của ảnh. Mức độ phóng đại của ảnh. # **IV. Huấn luyện Model** ### **4.1. Khởi tạo model huấn luyện** Tiếp theo, chúng ta sẽ bắt đầu huấn luyện mô hình. Việc đầu tiên cần thực hiện là khởi tạo một base network cho mô hình. Trên thư viện Keras, đã có sẵn hầu hết các mô hình pre-trained phổ biến trên bộ dữ liệu ImageNet. Lý do tác giả lựa chọn bộ dữ liệu này để huấn luyện các pretrained-model là vì nó bao gồm đến 1000 classes khác nhau. Do đó, hầu như mọi bài toán phân loại đều có nhãn xuất hiện trong ImageNet và có thể tái sử dụng các pretrained-model này. Ta khởi tạo model như sau: ```python= from tensorflow.keras.models import load_model, Sequential from tensorflow.keras.layers import Dense, Flatten from tensorflow.keras.applications import MobileNet from tensorflow.keras.optimizers import Adam base_network = MobileNet(input_shape=(224, 224, 3), include_top = False, weights = 'imagenet') flat = Flatten() den = Dense(1, activation='sigmoid') model = Sequential([base_network, flat, den]) model.compile(optimizer=Adam(), loss='binary_crossentropy', metrics = ['accuracy']) model.summary() ``` ### **4.2. Warm-up** Warm up là một quá trình cần thiết để giúp mô hình hội tụ nhanh hơn. Trong quá trình warm up, các layers CNN được đóng băng để giữ cho các hệ số của chúng không thay đổi, chỉ huấn luyện lại các Fully Connected Layers ở cuối cùng của mô hình. Mục đích của warm up là giữ nguyên các đặc trưng bậc cao (high-level) đã được học từ pretrained-model. Những đặc trưng này được coi là tốt vì được huấn luyện trên một bộ dữ liệu lớn hơn và có độ chính xác cao hơn so với việc khởi tạo hệ số ngẫu nhiên. Do đó, các layers ở Phrase 2 của mô hình không thay đổi input và coi như chúng ta chỉ đang huấn luyện lại mạng MLP. ```python= # Frozen base_network for layer in model.layers[:1]: layer.trainable = False for layer in model.layers: print('Layer: {} ; Trainable: {}'.format(layer, layer.trainable)) ``` Huấn luyện lại model trên 1 epoch ```python= import tensorflow as tf model.fit(train_generator, steps_per_epochs=len(train_generator), validation_data=val_generator, validation_steps=5, epochs=1) ``` ```python= 32/32 [==============================] - 203s 6s/step - loss: 1.1109 - accuracy: 0.8613 - val_loss: 5.8674 - val_accuracy: 0.6125 ``` Bạn sẽ nhận thấy độ chính xác (accuracy) sẽ được cải thiện rất nhanh chỉ sau epoch đầu tiên. Tuy nhiên, bài toán có xu hướng overfitting khi val_accuracy thấp hơn nhiều so với train_accuracy. Để giảm thiểu overfitting, chúng ta có thể thực hiện một số điều chỉnh đối với mô hình như sau: Mạng nơ ron có khả năng xấp xỉ được hầu hết các hàm số. Khi kiến trúc mạng càng phức tạp và bộ dữ liệu huấn luyện có kích thước nhỏ, khả năng học được chính xác trên từng điểm dữ liệu sẽ rất tốt. Tuy nhiên, việc học này có thể không tốt trên dữ liệu mới. Chúng ta có thể sử dụng Dropout Layer để giảm thiểu độ phức tạp trong kiến trúc của mô hình. Dropout sẽ loại bỏ ngẫu nhiên một số kết nối trong các lớp Fully Connected. Để giảm thiểu mức độ phức tạp của hàm số, chúng ta cũng có thể sử dụng các phương pháp hiệu chuẩn (regularization) bằng cách thêm vào loss function thành phần norm chuẩn Frobenius của ma trận hệ số các layers. ${L}_{reg}(\mathbf{W};\mathbf{X}) = \mathcal{L}(\mathbf{W}; \mathbf{X}) + \lambda ||\mathbf{W}||_{F}^{2}$ Trên TensorFlow, chúng ta có thể thêm thành phần hiệu chuẩn bằng cách khai báo trực tiếp vào tham số kernel_regularizer của các lớp trong Keras. ```python= from tensorflow.keras import regularizers your_model.add(Dense(64, input_dim=64, kernel_regularizer=regularizers.l2(0.01), activity_regularizer=regularizers.l2(0.01))) ``` - Một trong những nguyên nhân chủ yếu của overfitting là do dữ liệu huấn luyện có kích thước quá bé và không đại diện cho các trường hợp của ảnh một cách tổng quát. Trong trường hợp của bộ dữ liệu gốc dog and cat, có tới 25,000 ảnh, lớn gấp hàng chục lần so với dữ liệu huấn luyện chỉ có khoảng 1000 ảnh. Vì vậy, một giải pháp có thể cân nhắc để giảm thiểu overfitting là tăng cường dữ liệu huấn luyện bằng cách thêm vào tập train thêm các ảnh. Fine-tuning là quá trình điều chỉnh lại các layers của base network để cải thiện đặc trưng. Chúng ta sẽ trình bày chi tiết về quá trình này ở phần sau. # **V. Fine tuning Model** Mục đích chính của việc warm up model là để mô hình hội tụ nhanh hơn tới giá trị tối ưu toàn cục. Khi mô hình đạt ngưỡng tối ưu trên các Fully Connected Layers, sẽ rất khó để tăng thêm độ chính xác. Lúc này, chúng ta cần phá băng (unfreeze) các layers của base network và huấn luyện mô hình trên toàn bộ các layers từ pretrained model. Quá trình này được gọi là fine-tuning. ```python= for layer in model.layers[:1]: layer.trainable = True for layer in model.layers: print('Layer: {} ; Trainable: {}'.format(layer, layer.trainable)) ``` ```python= Layer: <tensorflow.python.keras.engine.training.Model object at 0x7f3130e83668> ; Trainable: True Layer: <tensorflow.python.keras.layers.core.Flatten object at 0x7f31333581d0> ; Trainable: True Layer: <tensorflow.python.keras.layers.core.Dense object at 0x7f3130eb1898> ; Trainable: True ``` ```python= model.fit(train_generator, validation_data = val_generator, batch_size = 32, epochs = 5) ``` ```python= Epoch 5/5 32/32 [==============================] - 209s 7s/step - loss: 0.4418 - accuracy: 0.9180 - val_loss: 2.4136 - val_accuracy: 0.7946 ``` Chúng ta có thể thấy rằng sau khi thực hiện fine-tuning, cả accuracy trên tập train và tập validation đều tăng lên và đạt tới ngưỡng >= 80%. Như vậy, fine-tuning đã giải quyết được đồng thời cả 2 vấn đề là overfitting và cải thiện độ chính xác của mô hình. # **VI. Kinh nghiệm transfer learning** ### **6.1. Transfer learning theo kích thước dữ liệu** ![pic5](https://hackmd.io/_uploads/HyU5wPyT6.jpg) Chiến lược áp dụng transfer learning. - Với dữ liệu nhỏ, việc huấn luyện lại toàn bộ các layers sẽ dẫn đến việc mất đi các đặc trưng đã được học từ mô hình pretrained và có thể dẫn tới việc mô hình dự báo không chính xác. Do đó, chúng ta chỉ nên huấn luyện lại các fully connected layers cuối cùng. - Với dữ liệu lớn và tương tự về domain, có thể huấn luyện lại mô hình trên toàn bộ các layers. Tuy nhiên, để quá trình huấn luyện nhanh hơn, chúng ta có thể thực hiện bước khởi động (warm-up) trước và sau đó mới thực hiện fine-tuning lại mô hình. - Với dữ liệu lớn và khác về domain, chúng ta nên huấn luyện lại mô hình từ đầu. Pretrained-model không tạo ra các đặc trưng tốt cho dữ liệu khác domain, do đó việc huấn luyện lại từ đầu sẽ giúp mô hình học được các đặc trưng phù hợp với dữ liệu mới. ### **6.2. Khi nào thực hiện transfer learning** Các trường hợp không hiệu quả khi áp dụng transfer learning có thể xuất phát từ các yếu tố sau: - **Không phù hợp về domain**: Transfer learning chỉ nên được thực hiện giữa hai mô hình có cùng domain dữ liệu. Nếu pretrained-model A và mô hình cần huấn luyện B không có chung domain về dữ liệu, các đặc trưng học được từ A có thể không hữu ích cho B. Ví dụ, nếu pretrained-model A được huấn luyện trên dữ liệu tiếng Anh trong khi mô hình B cần phân loại tiếng Việt, việc transfer learning có thể không phù hợp. - **Kích thước dữ liệu**: Dữ liệu huấn luyện của pretrained-model A cần phải lớn hơn so với mô hình B để các đặc trưng học được từ A có thể tổng quát hóa tốt cho B. Nếu pretrained-model được huấn luyện trên dữ liệu nhỏ, việc transfer learning có thể không mang lại hiệu quả cao cho mô hình B. - **Chất lượng của pretrained-model**: pretrained-model A cần phải là một mô hình có chất lượng tốt để các đặc trưng học được từ A có thể giúp cải thiện hiệu suất của mô hình B. Nếu pretrained-model không tốt, việc transfer learning cũng sẽ không mang lại kết quả mong muốn cho mô hình B. Chuẩn bị và đánh giá các yếu tố này trước khi quyết định sử dụng transfer learning sẽ giúp đảm bảo hiệu quả của quá trình huấn luyện mô hình. # **VII.Tổng kết** Chính xác, transfer learning là một phương pháp hiệu quả khi áp dụng cho các tác vụ học máy, đặc biệt là trong trường hợp dữ liệu có kích thước nhỏ. Áp dụng transfer learning có thể giúp cải thiện độ chính xác của mô hình bằng cách sử dụng các tri thức đã được học từ một mô hình trước đó. Đồng thời, nó cũng giảm thiểu thời gian huấn luyện và tài nguyên cần thiết để huấn luyện một mô hình từ đầu. # **VIII.Tài liệu** 1. [Transfer learning for deep learning - Machine learning mastery](https://machinelearningmastery.com/transfer-learning-for-deep-learning/) 2. [How to improve performance with transfer learning - Machine learning mastery](https://machinelearningmastery.com/how-to-improve-performance-with-transfer-learning-for-deep-learning-neural-networks/) 3. [Tổng hợp transfer learning SOTA - forum machine learning cơ bản](https://forum.machinelearningcoban.com/t/tong-hop-transfer-learning/5388) 4. [A comprehensive hands on guide to transfer learning with real world applications in deep learning](https://towardsdatascience.com/a-comprehensive-hands-on-guide-to-transfer-learning-with-real-world-applications-in-deep-learning-212bf3b2f27a) 5. [Transfer Learning - C3W2L07 - Andrew Ng](https://www.youtube.com/watch?v=yofjFQddwHE)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully