天天看點

圖像分類-flower_photos 實驗研究

資料集: flower_photos

  1. daisy: 633張圖檔 雛菊
  2. dandelion: 898張圖檔 蒲公英
  3. roses: 641張圖檔 玫瑰
  4. sunflowers: 699張圖檔 向日葵
  5. tulips: 799張圖檔 郁金香

資料存儲在本地磁盤,讀取用的是 tf.keras.preprocessing.image_dataset_from_directory(),其中的 image_size 用作 image resize,batch_size 用作 batch

最後的 train_ds = train_ds.shuffle().cache().prefetch(),這樣做的目的是減少 IO blocking

下面是模型搭建的代碼:

model = tf.keras.Sequential([
    tf.keras.layers.experimental.preprocessing.Rescaling(1. / 255),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(num_classes)
])           

此處把 pixel 的 rescale 放進了 Sequential,當做模型搭建的一部分,有利于模型部署

callbacks 裡面用到了 ReduceLROnPlateau,Tensorboard,EarlyStopping

圖像分類-flower_photos 實驗研究

上圖是訓練模型四次的 log 記錄圖,其中 val_acc 的區間在 [0.6499, 0.6785],這個是正常現象,是以訓練出來的模型準确率是會存在波動的

圖像分類-flower_photos 實驗研究

代碼位址:

https://github.com/MaoXianXin/Tensorflow_tutorial

,但是需要在如上圖的地方 flower dataset 這個 commit 處開一個新分支,然後找到 3.py 這個腳本,就能重複上圖的實驗了

因為上面的實驗,準确率才 [0.6499, 0.6785],我們需要進行優化,第一個改進是添加 data augmentation,此處我們直接在模型搭建環節添加,代碼如下所示

model = tf.keras.Sequential([
    tf.keras.layers.experimental.preprocessing.Rescaling(1. / 255),
    augmentation_dict[args.key],
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(num_classes)
])           

augmentation_dict[args.key],這個就是添加的 data augmentation,此處我們隻添加單種,具體 data augmentation 種類如下所示

augmentation_dict = {
    'RandomFlip': tf.keras.layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
    'RandomRotation': tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),
    'RandomContrast': tf.keras.layers.experimental.preprocessing.RandomContrast(0.2),
    'RandomZoom': tf.keras.layers.experimental.preprocessing.RandomZoom(height_factor=0.1, width_factor=0.1),
    'RandomTranslation': tf.keras.layers.experimental.preprocessing.RandomTranslation(height_factor=0.1, width_factor=0.1),
    'RandomCrop': tf.keras.layers.experimental.preprocessing.RandomCrop(img_height, img_width),
    'RandomFlip_prob': RandomFlip_prob("horizontal_and_vertical"),
    'RandomRotation_prob': RandomRotation_prob(0.2),
    'RandomTranslation_prob': RandomTranslation_prob(height_factor=0.1, width_factor=0.1),
}           

接下來我們看下實驗結果的 log 記錄圖

圖像分類-flower_photos 實驗研究

可以看到,val_acc 大于 0.6785 (未添加資料增強) 的有 RandomTranslation > RandomRotation_prob > RandomRotation > RandomFlip_prob = RandomFlip > RandomZoom > RandomTranslation_prob

從結果看來,資料增強是有效的,接下來我們進行第二個改進,更換更強的網絡模型,我們這裡選擇 MobileNetV2

這裡我們分兩種情況進行實驗,第一種是把 MobileNetV2 當做 feature extraction 來使用,這個要求我們 freeze 模型的 卷積部分,隻訓練添加進去的 top-classifier 部分,下面上代碼

data_augmentation = tf.keras.Sequential([
    augmentation_dict[args.key],
])

preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
base_model = tf.keras.applications.MobileNetV2(input_shape=img_size,
                                               include_top=False,
                                               weights='imagenet')
base_model.trainable = False

inputs = tf.keras.Input(shape=img_size)
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x, training=False)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = tf.keras.layers.Dense(num_classes)(x)
model = tf.keras.Model(inputs, outputs)
print(model.summary())           

實驗結果如下圖所示

圖像分類-flower_photos 實驗研究

可以看到,準确率提升很顯著,從資料增強的 0.7316 提升到了 0.8937,這主要得益于 pre-trained model 是在 ImageNet 大資料集上做過訓練,提取到的特征泛化性更好

為了進一步提升模型的準确率,我們采用第二種方式,對 pre-trained model 做 fine-tune,就是在第一種方式的基礎上,我們 unfreeze 部分卷積層,因為淺層的卷積提取的特征都是很基礎的特征,意味着很通用,但是深層的卷積提取的特征都是和資料集高度相關的,這裡我們要解決的是 flower_photos,是以可以對深層的一部分卷積做訓練,以進一步提高模型的準确率

下面上代碼

data_augmentation = tf.keras.Sequential([
    augmentation_dict[args.key],
])

preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
base_model = tf.keras.applications.MobileNetV2(input_shape=img_size,
                                               include_top=False,
                                               weights='imagenet')
base_model.trainable = True
# Let's take a look to see how many layers are in the base model
print("Number of layers in the base model: ", len(base_model.layers))

# Fine-tune from this layer onwards
fine_tune_at = 100

# Freeze all the layers before the `fine_tune_at` layer
for layer in base_model.layers[:fine_tune_at]:
    layer.trainable = False

inputs = tf.keras.Input(shape=img_size)
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x, training=False)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = tf.keras.layers.Dense(num_classes)(x)
model = tf.keras.Model(inputs, outputs)
model.load_weights('./save_models')
print(model.summary())

optimizer = tf.keras.optimizers.Adam(learning_rate=1e-4)
model.compile(
    optimizer=optimizer,
    loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy'])
K.set_value(model.optimizer.learning_rate, 1e-4)           

這裡有個特别需要注意的地方是 learning_rate 的設定,K.set_value(model.optimizer.learning_rate, 1e-4),這個地方還是我特地檢視了下 learning_rate 的 log 記錄圖才發現的不對勁

圖像分類-flower_photos 實驗研究

可以看到,進行 fine-tune 的話,模型準确率進一步提升,從 0.8937 ---> 0.9482

到此為止,我們實作了在 flower_photos 資料集上 val_acc = 0.9482,下一步可能會用 RandAugment 或者 Semi-supervised 來提升模型的泛化能力

繼續閱讀