乐趣区

关于tensorflow:深度学习之图像分类ResNet50学习

深度学习之图像分类 ResNet50

此次采纳迁徙学习并微调。个别的倡议是:

应用事后训练的模型进行特征提取:应用小型数据集时,通常的做法是利用在雷同域中的较大数据集上训练的模型中学习的特色。这是通过实例化预训练的模型并在顶部增加齐全连贯的分类器来实现的。事后训练的模型是“解冻的”,训练过程中仅更新分类器的权重。在这种状况下,卷积根底提取了与每个图像关联的所有特色,而您刚刚训练了一个分类器,该分类器依据给定的提取特色集确定图像类。

对预训练模型进行微调:为了进一步提高性能,可能须要通过微调将预训练模型的顶层从新用于新的数据集。在这种状况下,您须要调整权重,以使模型学习到特定于数据集的高级性能。通常在训练数据集很大并且与训练前的模型十分类似的原始数据集十分类似时,倡议应用此技术。

ResNet50 实战

官网示例代码用的二分类,猫狗分类。
另外迁徙学习应用的是 MobileNet V2 model。

所以这次的更改无非就是更改一下分类层,和引入 ResNet 即可了。

环境筹备

可能有些没有用到!

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.9292

微调迁徙学习模型

按理说数据量不大,微调可能给不了太大晋升。试一下就是了。

175 层解冻后面 100 层

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()

附录

  • 官网示例代码迁徙学习和微调
  • 官网示例代码图像分类
退出移动版