Giới thiệu về Transfer learning

Mở đầu

Trong quá trình xây dựng một mô hình học máy, chắc hẳn các bạn đã gặp phải một số vấn đề như mô hình dự đoán có độ chính xác thấp dù đã dùng một kiến trúc phức tạp, hay lượng dữ liệu quá ít để có thể huấn luyện một mô hình hoàn chỉnh. Thông thường, một mô hình có kết quả dự báo kém là do một số nguyên nhân sau

  • Dữ liệu nhỏ không đại diện: Bộ dữ liệu của chúng ta có kích thước quá bé so với mô hình được huấn luyện, khiến cho mô hình không học được các đặc trưng của ảnh để giải quyết các bài toán cụ thể như phân loại, nhận dạng, …

  • Mô hình mất cân bằng dữ liệu: Khi mà tập dữ liệu của chúng ta có sự chênh lệch lớn giữa các nhóm, ví dụ như chỉ có 100 ảnh cho con chó và 100.000 ảnh cho con mèo, tất nhiên mô hình sẽ “thiên vị” dự đoán nghiêng về con mèo nhiều hơn

  • Kiến trúc mô hình quá phức tạp: Khi ta có bộ dữ liệu lớn tới vài trăm triệu ảnh thì tất nhiên kiến trúc mô hình phức tạp có thể mang lại độ chính xác cao. Tuy nhiên đối với những bộ dữ liệu nhỏ, vừa phải thì mô hình quá phức tạp lại đem lại độ chính xác không cao. Cần chọn kiến trúc mô hình phù hợp với lượng data chúng ta làm việc cùng

  • Quá trình tối ưu hóa gặp khó khăn: Có thể các hyperparameter được thiết lập chưa tốt như learning rate khiến cho mô hình huấn luyện lâu hội tụ hoặc chưa đạt tới điểm global optimal

Vậy khi chúng ta có một lượng data nhỏ nhưng muốn hoàn thiện một bài toán sử dụng mô hình hoàn chỉnh, làm thế nào để mô hình đó hoạt động tốt? Transfer Learning có thế giải quyết điều đó.

Introduction

Transfer learning – Học chuyển giao bao gồm việc sử dụng các tính năng đã học về một vấn đề và tận dụng chúng vào một vấn đề mới nhưng tương tự. Ví dụ, các tính năng từ một mô hình đã học để xác định các loài chim có thể hữu ích để khởi động một mô hình dùng để xác định tanukis(1 loài lửng của Nhật Bản).

Học chuyển giao thường được thực hiện cho các nhiệm vụ mà tập dữ liệu của bạn có quá ít dữ liệu để đào tạo một mô hình quy mô đầy đủ từ đầu.

Hiện thân phổ biến nhất của học chuyển tiếp trong học sâu là quy trình làm việc sau:

  • Lấy các lớp từ một mô hình đã được đào tạo trước đó.
  • Đóng băng(Freeze) chúng, để tránh phá hủy bất kỳ thông tin nào mà chúng chứa trong các đợt huấn luyện trong tương lai.
  • Thêm một số lớp mới, có thể đào tạo lên trên các lớp đã đóng băng. Chúng sẽ học cách biến các tính năng cũ thành dự đoán trên một tập dữ liệu mới.
  • Đào tạo các lớp mới trên tập dữ liệu của bạn.

Bước cuối cùng (tùy chọn), là tinh chỉnh, bao gồm việc mở toàn bộ mô hình bạn đã thu được ở trên (hoặc một phần của nó) và đào tạo lại nó trên dữ liệu mới với tỷ lệ học tập rất thấp. Điều này có thể đạt được những cải tiến có ý nghĩa, bằng cách từng bước điều chỉnh các tính năng được đào tạo trước cho phù hợp với dữ liệu mới.

Đầu tiên, chúng ta sẽ xem xét chi tiết về API có thể train của Keras, làm cơ sở cho hầu hết các quy trình học tập và tinh chỉnh chuyển giao.

Sau đó, chúng tôi sẽ chứng minh quy trình làm việc điển hình bằng cách lấy một mô hình được đào tạo trước trên tập dữ liệu ImageNet và đào tạo lại nó trên tập dữ liệu phân loại Kaggle "mèo vs chó".

Điều này được điều chỉnh từ Deep Learning với Python và bài đăng trên blog năm 2016 "xây dựng các mô hình phân loại hình ảnh mạnh mẽ bằng cách sử dụng rất ít dữ liệu".

Các lớp đóng băng: hiểu thuộc tính trainable (có thể đào tạo)

Các lớp và mô hình có ba thuộc tính trọng số:

  • weight (trọng số) : danh sách tất cả các biến trọng số của lớp.
  • trainable_weights (trọng số có thể đào tạo) : danh sách những thứ cần được cập nhật (thông qua gradient descent) để giảm thiểu tổn thất trong quá trình đào tạo.
  • non_trainable_weights (trọng số không thể đào tạo): là danh sách những thứ không được đào tạo. Thông thường, chúng được cập nhật bởi mô hình trong quá trình chuyển tiếp.

Ví dụ : lớp Dense có 2 trainable_weights (kernel & bias)

layer = keras.layers.Dense(3)
layer.build((None, 4))  # Khởi tạo trọng số

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 2
trainable_weights: 2
non_trainable_weights: 0

Nói chung, tất cả các trọng số đều có thể huấn luyện được. Lớp tích hợp duy nhất có trọng số không thể đào tạo là lớp BatchNormalization. Nó sử dụng trọng số không thể đào tạo để theo dõi giá trị trung bình và phương sai của các đầu vào trong quá trình đào tạo. Để tìm hiểu cách sử dụng trọng số không thể đào tạo trong các lớp tùy chỉnh của riêng bạn, hãy xem hướng dẫn viết các lớp mới từ đầu.

Ví dụ: lớp BatchNormalization có 2 trainable_weights và 2 non_trainable_weights

layer = keras.layers.BatchNormalization()
layer.build((None, 4))  # Khởi tạo trọng số

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 4
trainable_weights: 2
non_trainable_weights: 2

Các lớp và mô hình cũng có thuộc tính boolean có thể đào tạo. Giá trị của nó có thể được thay đổi. Đặt layer.trainable thành False sẽ di chuyển tất cả trọng lượng của lớp từ có thể huấn luyện sang không thể huấn luyện. Đây được gọi là "đóng băng" lớp: trạng thái của lớp bị đóng băng sẽ không được cập nhật trong quá trình đào tạo (khi đào tạo với fit() hoặc khi đào tạo với bất kỳ vòng lặp tùy chỉnh nào dựa vào trainable_weights để áp dụng cập nhật gradient).

Ví dụ: đặt trainable thành False

layer = keras.layers.Dense(3)
layer.build((None, 4))  # Khởi tạo trọng số
layer.trainable = False  # Đóng băng layer

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 2
trainable_weights: 0
non_trainable_weights: 2

Khi trọng số trainable trở thành non-trainable, giá trị của nó sẽ không còn được cập nhật trong quá trình huấn luyện.

# Tạo mô hình với 2 layer
layer1 = keras.layers.Dense(3, activation="relu")
layer2 = keras.layers.Dense(3, activation="sigmoid")
model = keras.Sequential([keras.Input(shape=(3,)), layer1, layer2])

# Đóng băng layer1
layer1.trainable = False

# Giữ lại một bản sao trọng số của layer1 để tham khảo sau này
initial_layer1_weights_values = layer1.get_weights()

# Huấn luyện mô hình
model.compile(optimizer="adam", loss="mse")
model.fit(np.random.random((2, 3)), np.random.random((2, 3)))

# Kiểm tra trọng số của layer1 không hề thay đổi trong quá trình training
final_layer1_weights_values = layer1.get_weights()
np.testing.assert_allclose(
    initial_layer1_weights_values[0], final_layer1_weights_values[0]
)
np.testing.assert_allclose(
    initial_layer1_weights_values[1], final_layer1_weights_values[1]
)
1/1 [==============================] - 0s 333ms/step - loss: 0.1007

Cài đặt đệ quy của thuộc tính trainable

Nếu bạn đặt trainable = False trong một model hoặc một lớp có nhiều lớp con, tất cả lớp con sẽ trở thành non-trainable Ví dụ :

inner_model = keras.Sequential(
    [
        keras.Input(shape=(3,)),
        keras.layers.Dense(3, activation="relu"),
        keras.layers.Dense(3, activation="relu"),
    ]
)

model = keras.Sequential(
    [keras.Input(shape=(3,)), inner_model, keras.layers.Dense(3, activation="sigmoid"),]
)

model.trainable = False  # Đóng băng model 

assert inner_model.trainable == False  # Tất cả lớp thuộc `model` dều bị đóng băng
assert inner_model.layers[0].trainable == False

Transfer learning workflow

Một workflow điển hình của transfer learning được thực thi trong Keras:

  1. Khởi tạo mô hình cơ sở và tải các trọng số đã được đào tạo trước vào đó.
  2. Cố định tất cả các lớp trong mô hình cơ sở bằng cách đặt trainable = False.
  3. Tạo một mô hình mới trên đầu ra của một (hoặc một số) lớp từ mô hình cơ sở.
  4. Train mô hình mới trên tập dữ liệu mới của bạn.

Lưu ý rằng có thể là một quy trình thay thế nhẹ hơn :

  1. Khởi tạo mô hình cơ sở và tải các trọng số đã được đào tạo trước vào đó.
  2. Chạy tập dữ liệu mới của bạn thông qua nó và ghi lại kết quả của một (hoặc một số) lớp từ mô hình cơ sở. Đây được gọi là feature extraction.
  3. Sử dụng đầu ra đó làm dữ liệu đầu vào cho một mô hình mới nhỏ hơn.

Một ưu điểm chính của quy trình làm việc thứ hai đó là bạn chỉ chạy mô hình cơ sở một lần trên dữ liệu của mình, thay vì một lần cho mỗi epoch đào tạo. Vì vậy, nó nhanh hơn và tiết kiệm tài nguyên hơn rất nhiều.

Tuy nhiên, một vấn đề với quy trình làm việc thứ hai đó là nó không cho phép bạn tự động sửa đổi dữ liệu đầu vào của mô hình mới trong quá trình đào tạo, ví dụ như bắt buộc khi thực hiện tăng dữ liệu. Học chuyển giao thường được sử dụng cho các nhiệm vụ khi tập dữ liệu mới của bạn có quá ít dữ liệu để đào tạo mô hình quy mô đầy đủ từ đầu và trong các tình huống như vậy, việc tăng dữ liệu là rất quan trọng. Vì vậy, trong những gì tiếp theo, chúng ta sẽ tập trung vào quy trình làm việc đầu tiên.

Đây là quy trình làm việc đầu tiên trong Keras:

Đầu tiên, khởi tạo một mô hình cơ sở với các trọng lượng được đào tạo trước.

base_model = keras.applications.Xception(
    weights='imagenet',  # Load trọng số pre-trained tại ImageNet.
    input_shape=(150, 150, 3),
    include_top=False)  # Không bao gồm lớp phân loại ImageNet ở trên cùng

Sau đó, đóng băng mô hình cơ sở

base_model.trainable = False

Tạo một mô hình mới trên đầu trang.

inputs = keras.Input(shape=(150, 150, 3))
# Đảm bảo base_model đang chạy chế độ inference ở đây,
# bằng cách sử dụng `training=False`. Điều này rất quan trọng cho fine-tuning, 
# mà tôi sẽ nhắc tới ở phần sau
x = base_model(inputs, training=False)
# Chuyển đổi các thuộc tính cấu hình của `base_model.output_shape[1:]` thành vectors
x = keras.layers.GlobalAveragePooling2D()(x)
# Một bộ phân loại Dense với một đơn vị duy nhất (phân loại nhị phân)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

Train model với dữ liệu mới

model.compile(optimizer=keras.optimizers.Adam(),
              loss=keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=[keras.metrics.BinaryAccuracy()])
model.fit(new_dataset, epochs=20, callbacks=..., validation_data=...)

Kết luận

Trên đây là tổng quan về Transfer Learning. Ở bài viết tiếp theo chúng ta sẽ tìm hiểu về Fine-tuning, một kỹ thuật Transfer Leaning.

Thanks for reading

Tham khảo https://keras.io/guides/

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.