深度學習之圖像分類ResNet50學習

深度學習之圖像分類ResNet50

這次採用遷移學習並微調。通常的建議是:api

使用預先訓練的模型進行特徵提取:使用小型數據集時,一般的作法是利用在相同域中的較大數據集上訓練的模型中學習的特徵。這是經過實例化預訓練的模型並在頂部添加徹底鏈接的分類器來完成的。預先訓練的模型是「凍結的」,訓練過程當中僅更新分類器的權重。在這種狀況下,卷積基礎提取了與每一個圖像關聯的全部特徵,而您剛剛訓練了一個分類器,該分類器根據給定的提取特徵集肯定圖像類。app

對預訓練模型進行微調:爲了進一步提升性能,可能須要經過微調將預訓練模型的頂層從新用於新的數據集。在這種狀況下,您須要調整權重,以使模型學習到特定於數據集的高級功能。一般在訓練數據集很大而且與訓練前的模型很是類似的原始數據集很是類似時,建議使用此技術。dom

ResNet50實戰

官方示例代碼用的二分類,貓狗分類。
另外遷移學習使用的是MobileNet V2 model。性能

因此此次的更改無非就是更改一下分類層,和引入ResNet便可了。學習

環境準備

可能有些沒有用到!fetch

from tensorflow.keras.applications import ResNet50
from tensorflow.keras import layers
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras import Model
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications.resnet50 import preprocess_input
from tensorflow.keras.preprocessing import image
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.optimizers import Adam
import tensorflow as tf
import matplotlib.pyplot as plt
import PIL
import numpy as np

數據集

使用的是官方的花朵圖像的分類。官方也很無語,圖像分類用的是花朵圖像,到遷移學習的時候又換成了狗和貓的分類。大數據

import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)

拆分數據集

batch_size = 32
img_height = 180
img_width = 180

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)

class_names = train_ds.class_names
print(class_names)

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

查看數據集

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")

定義model

data_augmentation = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal'),
  tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),
])
for image, _ in train_ds.take(1):
  plt.figure(figsize=(10, 10))
  first_image = image[0]
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    augmented_image = data_augmentation(tf.expand_dims(first_image, 0))
    plt.imshow(augmented_image[0] / 255)
    plt.axis('off')

base_model = ResNet50(include_top=False, weights='imagenet',input_shape=(180,180,3))
base_model.trainable = False
inputs = tf.keras.Input(shape=(180,180,3))
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x,training=False)
print(base_model.output.shape)
x = GlobalAveragePooling2D()(x)
y = Dense(5, activation='softmax')(x) #final layer with softmax activation
model = Model(inputs=inputs, outputs=y, name="ResNet50")
model.summary()

編譯模型

loss = tf.keras.losses.SparseCategoricalCrossentropy()
metrics = tf.metrics.SparseCategoricalAccuracy()
model.compile(optimizer='Adam', loss=loss, metrics=metrics)
len(model.trainable_variables)

訓練模型

history = model.fit(train_ds,
                    epochs=10,
                    validation_data=val_ds)

基本上就能達到92的準確率。
92/92 [==============================] - 19s 206ms/step - loss: 0.0186 - sparse_categorical_accuracy: 1.0000 - val_loss: 0.2470 - val_sparse_categorical_accuracy: 0.9292ui

微調遷移學習模型

按理說數據量不大,微調可能給不了太大提高。試一下就是了。this

175層凍結前面100層google

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

從新編譯模型和訓練模型

從未微調的最後一次訓練接着訓練10個epochs。

loss = tf.keras.losses.SparseCategoricalCrossentropy()
metrics = tf.metrics.SparseCategoricalAccuracy()
model.compile(optimizer='Adam', loss=loss, metrics=metrics)
len(model.trainable_variables)

fine_tune_epochs = 10
total_epochs =  10 + fine_tune_epochs

history_fine = model.fit(train_ds,
                         epochs=total_epochs,
                         initial_epoch=history.epoch[-1],
                         validation_data=val_ds)

結果反而還下降了。
92/92 [==============================] - 31s 341ms/step - loss: 0.1780 - sparse_categorical_accuracy: 0.9440 - val_loss: 0.3261 - val_sparse_categorical_accuracy: 0.9183

預測下數據

image_batch,label_batch = val_ds.as_numpy_iterator().next()
print(label_batch)
predictions = model.predict_on_batch(image_batch)

for i in range(0,predictions.shape[0]):
  print(np.argmax(predictions[i]))
  prediction = np.argmax(predictions[i])
  
  if (prediction != label_batch[i]):
    plt.figure(figsize=(10, 10))
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[label_batch[i]] + "-" + class_names[prediction])
    plt.show()

附錄

相關文章
相關標籤/搜索