Tìm hiểu và thử Transfer Learning Google Inception Net với bài toán phân loại ảnh oto

Chào tuần mới anh em Mì AI, hôm nay chúng ta sẽ cùng tìm hiểu về Goolge Inception Net V3 và thử một bài toán CNN Classifier bằng cách áp dụng Transfer Learning với mạng này nhé.

Nào, bắt đầu thôi!

Phần 1 – Google Inception Net có gì hot?

Thực ra thì như này, như mình vẫn nói, đó là không hề có một công thức nào trong việc thiết kế các mạng NN cả. Không hề có một phép tính mà sau khi điền số tầng, số lớp, số neural… vào là nó tính ra được xem mạng này hiểu quả, mạng kia kém hiệu quả…blah blah.

Tất cả đều là nghĩ, kinh nghiệm và thực nghiệm nhé các bạn!

Inception Net ra đời cũng vậy, do Tây họ thực nghiệm xây một cấu trúc và thấy nó tốt mà thôi. Tất nhiên là để có thể vẽ ra thì kinh nghiệm họ cùng đầy mình rồi anh em ạ :D. Ok, bây giờ chúng ta sẽ đi tìm nguyên nhân và cảm hứng của họ là gì khi xây mạng này.

Inception Net v1 ra đời vào năm 2014 bởi Google với các suy nghĩ như sau.

Thứ nhất, các vật thể, các thông tin trong các ảnh rất khác nhau, lúc to, lúc nhỏ dẫn đến việc chọn kích thước kernel cho Conv Layer khá khó. Chọn to quá thì chỉ capture được các thông tin mang tính tổng quát mà nhỏ quá thì chỉ lấy được các món cụ tỷ… Do dó các mạng CNN trước giờ chỉ chủ yếu giải quyết bằng cách là go deeper, với nhiều tầng lớp kernel khác nhau để capture thông tin. Điều đó dẫn tới vừa có chi phí tính toán cao vừa dễ tạo ra Overfit cho mạng. Còn với Inception Net, họ có ý tưởng tại sao không đi theo chiều rộng thay vì sâu. Thay vì sử dụng nhiều tầng filter Conv thì họ sử dụng nhiều filter Conv với các kích thước khác nhau tại cùng một tầng, sau đó concat lại với nhau. Mỗi một cụm như vậy họ gọi là một Inception Cell hay Inception Module (xem hình dưới)

inception net
Nguồn: Tại đây

Như hình trên các bạn thấy họ áp dụng 3 Conv layer lên input với 3 size khác nhau là 1×1, 3×3 và 5×5 (khuyến mại thêm quả maxpool 3×3 nữa).

Thế rồi, để giảm chi phí tính toán, họ lại nghĩ ra trò thêm 1×1 Conv vào để giảm kích thước input channels:

inception net
Nguồn: Tại đây

Ngoài ra, họ còn thêm các bộ phân loại bổ trợ (dịch nghe hơi ngu tý, nguyên bản là auxiliary classifiers) để với mục đích làm cho phần giữa của mạng (nơi thường ít được train do triệt tiêu Gradient) tham gia vào quá trình train. Cách làm là họ cho Loss của các auxiliary classifiers này tham gia vào hàm Total loss. Cụ thể ở đây là:

total_loss = real_loss + 0.3 * aux_loss_1 + 0.3 * aux_loss_2

Rồi tóm lại là sau khi lắp ghép nhiều Inception Module/Cell lại với nhau, ghép thêm 2 bộ phân loại bổ trợ thì ta có được cái mạng có kiến trúc như sau:

inception net
Nguồn: Tại đây

Phải gọi là quá đẹp luôn!

Thế rồi sau đó họ chỉnh lên chỉnh xuống, chỉnh trái chỉnh phải, chỉnh trong chỉnh ngoài… thì ra được cái version 3 mà chúng ta đang tìm hiểu ở đây. Mình nghĩ với việc áp dụng thì chúng ta cũng không cần tìm hiểu sâu thêm vì họ cũng chỉ là thêm mắm muối thôi.

Tóm lại là ta chỉ cần nhớ cái hướng đi của Inception Net là rộng hơn sâu, tách nhiều lớp thành nhiều filter trong một lớp và kết hợp các bộ phân loại bổ trợ để hỗ trợ việc train. Thế là đủ!

Còn tất nhiên bạn nào cần nghiên cứu kỹ hơn về V3 thì link đây và V4 thì link đây nhé!

Phần 2 – Xây dựng bài toán phân loại ảnh bằng InceptionNet v3

Ở đây mình dùng kỹ thuật Transfer Learning nhé, giống như những gì mình đã làm với bài toán nhận diện tiền Việt Nam bằng VGG16 ấy.

Transfer Learning là kiểu như “chuyển giao công nghệ ấy” mà các bạn. Chúng ta sẽ sử dụng một mạng đã được train ngon nghẻ với nhiều dữ liệu rồi (mạng nó khôn rồi) để phục vụ cho bài toán của chúng ta. Và mạng ngon nghẻ lần này là Inception Net V3 đã được train với bộ ảnh khủng ImageNet.

Và bài toán cụ thể chúng ta làm ở đây là bài toán phân loại ảnh oto. Nghĩa là khi đưa cho máy tính một ảnh xe oto, máy phải cho chúng ta biết đó là hãng xe gì, model nào 😀

Phải nói đây là một bài toán khó, kể cả với con người vì các chiếc xe oto khá giống nhau (nếu không xem logo). Mình chỉ làm để demo việc tiền xử lý dữ liệu tải về trên mạng và transfer learning chứ có thể accuracy sẽ không cao nhé các bạn.

Rồi, bắt đầu từng bước nhé!

Dữ liệu ở đâu để train và test?

Đúng, làm DL mà không có data thì móm. May sao trong Thư viện Mì AI: https://miai.vn/thu-vien-mi-ai đã có sẵn một bộ dữ liệu về xe của Stanford. Các bạn có thể tải về tại đây. Sau khi tải xong các bạn nhớ giải nén ra sẽ thấy 2 thư mục car_train và car_test như sau:

data folder train

Bây giờ các bạn tải thông tin gán nhãn tại đây và giải nén để có thư mục car_devkit (đặt cùng thư mục với CarDataSet như hình. Tiếp theo ta tạo thư mục data và 2 thư mục con train và test trong thư mục data. Vậy là xong bước tải dữ liệu.

Tiền xử lý dữ liệu

Dữ liệu nói trên ta chưa thể đưua ngay vào model để train được, ta phải tiền xử lý dữ liệu bằng code sau:

import scipy.io
import os
import shutil
import random

# Create label.csv
with open("data\\labels.csv","w") as f:
    mat = scipy.io.loadmat("car_devkit\\cars_meta.mat")
    print(mat)
    for anno in mat["class_names"][0]:
        f.write(anno[0] +"\n")


# Process test folder
train_dir = "data\\test"
mat = scipy.io.loadmat("car_devkit\\cars_test_annos_withlabels.mat")
for anno in mat["annotations"][0]:
    print(anno)

    if random.random()<0.8:
        train_dir = "data\\train"
    else:
        train_dir = "data\\test"
    # Create folder in train
    try:
        print("Make folder : ", anno[4][0][0])
        os.mkdir(train_dir + "\\" + str(anno[4][0][0]))
    except:
        pass

    # Copy file
    print("Copy file: ",anno[5][0])
    shutil.copy("CarDataSet\\cars_test\\" + str(anno[5][0]), train_dir + "\\" + str(anno[4][0][0]) + "\\" + str(anno[5][0]) )


# Process train folder
train_dir = "data\\train"
mat = scipy.io.loadmat("car_devkit\\cars_train_annos.mat")
for anno in mat["annotations"][0]:
    print(anno)
    # Create folder in train
    try:
        print("Make folder : ", anno[4][0][0])
        os.mkdir(train_dir + "\\" + str(anno[4][0][0]))
    except:
        pass

    # Copy file
    print("Copy file: ",anno[5][0])
    shutil.copy("CarDataSet\\cars_train\\" + str(anno[5][0]), train_dir + "\\" + str(anno[4][0][0]) + "\\" + str(anno[5][0]) )Code language: PHP (php)

Các bạn chú ý code trên mình chạy trên Window, các bạn chạy Linux đổi lại đường dãn cho phù hợp nhé.

Sau khi chạy xong các bạn để ý thư mục data\train và data\test sẽ có đầy đủ dữ liệu cần thiết.

Ok, tiếp nào anh em!

Transfer Learning, cách 01

Với các này chúng ta sẽ thực hiện như sau:

  • Bỏ đi phần Fully Connect của InceptionNet V3
  • Trích output của InceptionNet và coi đó là input cho một số lớp tiếp theo do chúng ta thêm vào để classify

Do sự nổi tiếng của mình nên InceptionNetV3 đã được Keras tích hợp sẵn rồi nên việc triển khai khá đơn giản. Ở đây mình sử dụng pretrain weight ImageNet nha:

incept_model = InceptionV3(input_shape=IMG_SIZE, include_top = False, weights = "imagenet")

# Đóng băng các layer của InceptionNet
for layer in incept_model.layers:
    layer.trainable = False

# Thêm vào các layer FC
x = Flatten()(incept_model.output)
x = Dense(512, activation="relu")(x)
x = Dropout(0.5)(x)
x = Dense(CLASS_NUM, activation="softmax")(x)Code language: PHP (php)

Các hyper param hoàn toàn do mình chế ra theo sở thích, các bạn có thể thay đổi tùy nhu cầu nhé.

Transfer Learning, cách 02

Cách thứ 2 khác cách số 1 ở một số chỗ như sau:

  • Ta vẫn bỏ đi khúc FC Classify của InceptionNetV3
  • Nhưng sau đó ta không sử dụng toàn bộ các layer còn lại của IncepionNet mà bỏ đi 1 khúc nào đó tùy ý để giảm bớt sự phức tạp của model.
  • Ta sẽ trích output của phần còn lại và làm input cho phần mạng tiếp theo tương tự như cách 1.

Ví dụ ở đây mình thấy trên mạng họ hay trích của layer có tên mixed7 như sau:

inception net
incept_model = InceptionV3(input_shape=IMG_SIZE, include_top = False, weights = "imagenet")

# Cắt bỏ và chỉ giữ lại đến layer có tên mixed7
last_layer = incept_mode.get_layer('mixed7')
last_output = last_layer.output

# Đóng băng các layer của InceptionNet
for layer in incept_model.layers:
    layer.trainable = False

# Thêm vào các layer FC
x = Flatten()(last_output)
x = Dense(512, activation="relu")(x)
x = Dropout(0.5)(x)
x = Dense(CLASS_NUM, activation="softmax")(x)Code language: PHP (php)
Train model nào!!!

Rồi sau khi đã ghép nối thành công, chúng ta sẽ tiến hành train model. Ở đây tránh tràn bộ nhớ nên mình train bằng data_flow của Keras. Bạn nào chưa nắm được món này có thể xem qua link này nhé.

train_datagen = ImageDataGenerator(rescale=1./255, rotation_range=40, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)

train_dir = "data/train"
test_dir = "data/test"

train_generator = train_datagen.flow_from_directory(train_dir, batch_size=BATCH_SIZE, class_mode="categorical", target_size=IMG_SIZE[:-1])
test_generator = test_datagen.flow_from_directory(test_dir, batch_size=BATCH_SIZE, class_mode="categorical", target_size=IMG_SIZE[:-1])

print(train_generator.class_indices)

model.fit_generator(train_generator, validation_data=test_generator, steps_per_epoch=train_generator.n//BATCH_SIZE, epochs = EPOCHS, 
                    validation_steps=test_generator.n//BATCH_SIZE,verbose=1 )
model.save("mymodel.h5")Code language: PHP (php)

Mình xin nhấn mạnh một chút là bài này mình muốn demo việc transfer learning InceptionNetv3 là chính nên mình chưa chú ý đến accuracy của model nhé, các bạn có thể tự fine tune, điều chỉnh hyper param xem như nào nha.

Phần 3 – Kết luận

Qua bài này chúng ta có thể thấy rằng Transfer Learning thực sự amazing! Nó mạng lại nhiều lợi ích, tiết kiệm về thời gian và công sức rất nhiều trong lĩnh vực Computer Vision.

Trong bài này chúng ta cần chú ý:

  • InceptionNetV3 khá phức tạp nhưng hiệu quả cũng ngon.
  • Ta có thể transfer learning bằng việc sử dụng toàn bộ layer và weights của mạng (sau khi bỏ đi đống FC) hoặc thích thì trích 1 phần mạng để dùng (có thể áp dụng với tất cả các mạng khác chứ ko riêng InceptionNet)

Vậy thôi, chúc các bạn thành công! Mình xin chia sẻ github cho bạn nào cần: https://github.com/thangnch/MIAI_Inception_Net

Hãy join cùng cộng đồng Mì AI nhé!

Fanpage: http://facebook.com/miaiblog
Group trao đổi, chia sẻ: https://www.facebook.com/groups/miaigroup
Website: https://miai.vn
Youtube: http://bit.ly/miaiyoutube

Tài liệu tham khảo: https://medium.com/analytics-vidhya/transfer-learning-using-inception-v3-for-image-classification-86700411251b

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *