参考书目:陈允杰.TensorFlow与Keras——Python深度学习应用实战.北京:中国水利水电出版社,2021
本系列基本不讲数学原理,只从代码角度去让读者们利用最简洁的Python代码实现深度学习方法。
迁移学习是指将那些别人研究训练好的厉害的网络拿来直接用,在自己的数据集上简单训练微调一下就可以用来做自己的数据集分类。下面展示两个网络ResNet50和MobileNet在Cifar-10上的迁移学习。都是图片分类的案例。文本类型的模型也有,但是较为复杂,以后再出。
ResNet50迁移学习
首先导入包和数据
import numpy as np
from keras.datasets import cifar10
from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input
from tensorflow.keras.applications import MobileNet
from keras.models import Sequential
from keras.layers import Dense, Dropout, GlobalAveragePooling2D
from tensorflow.keras.utils import to_categorical
from PIL import Image
# 指定乱数种子
seed = 10
np.random.seed(seed)
# 载入数据集
(X_train, Y_train), (X_test, Y_test) = cifar10.load_data()
# 打乱 2 个 Numpy 阵列
def randomize(a, b):
permutation = list(np.random.permutation(a.shape[0]))
shuffled_a = a[permutation]
shuffled_b = b[permutation]
return shuffled_a, shuffled_b
由于数据量太大,只取10%数据
X_train, Y_train = randomize(X_train, Y_train)
X_test, Y_test = randomize(X_test, Y_test)
# 取出10%训练, 10%测试
X_train = X_train[:5000]
Y_train = Y_train[:5000]
X_test = X_test[:1000]
Y_test = Y_test[:1000]
# One-hot编码
Y_train = to_categorical(Y_train, 10)
Y_test = to_categorical(Y_test, 10)
进行训练,将迁移模型对数据进行转化
# 载入ResNet50 模型
resnet_model = ResNet50(weights="imagenet",
include_top=False,
input_shape=(200, 200, 3))
# 调整X_train的图片尺寸
print("调整X_train的图片尺寸...")
X_train_new = np.array(
[np.asarray(Image.fromarray(X_train[i]).resize(
(200, 200))) for i in range(0, len(X_train))])
X_train_new = X_train_new.astype("float32")
# 训练数据的数据前处理
train_input = preprocess_input(X_train_new)
# 使用 ResNet50 模型预测训练数据的特征数据
print("使用 ResNet50 模型预测训练数据的特征数据 ...")
train_features = resnet_model.predict(train_input)
测试集一样
# 调整X_test的图片尺寸
print("调整X_test的图片尺寸...")
X_test_new = np.array([np.asarray(Image.fromarray(X_test[i]).resize((200, 200))) for i in range(0, len(X_test))])
X_test_new = X_test_new.astype("float32")
# 测试数据的数据前处理
test_input = preprocess_input(X_test_new)
# 使用 ResNet50 模型预测测试数据的特征数据
print("使用 ResNet50 模型预测测试数据的特征数据 ...")
test_features = resnet_model.predict(test_input)
构建并训练分类模型
# 定义模型
model = Sequential()
model.add(GlobalAveragePooling2D(
input_shape=train_features.shape[1:]))
model.add(Dropout(0.5))
model.add(Dense(10, activation="softmax"))
#编译模型
model.compile(loss="categorical_crossentropy", optimizer="adam",metrics=["accuracy"])
#训练模型
history = model.fit(train_features, Y_train,validation_data=(test_features, Y_test),
epochs=14, batch_size=32, verbose=1)
评估
# 评估模型
print("\nTesting ...")
loss, accuracy = model.evaluate(test_features, Y_test)
print("测试数据集的准确度 = {:.2f}".format(accuracy))
画损失变化
#显示图表来分析模型的训练过程
import matplotlib.pyplot as plt
# 显示训练和验证损失
loss = history.history["loss"]
epochs = range(1, len(loss)+1)
val_loss = history.history["val_loss"]
plt.plot(epochs, loss, "bo-", label="Training Loss")
plt.plot(epochs, val_loss, "ro--", label="Validation Loss")
plt.title("Training and Validation Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()
画准确率变化
# 显示训练和验证准确度
acc = history.history["accuracy"]
epochs = range(1, len(acc)+1)
val_acc = history.history["val_accuracy"]
plt.plot(epochs, acc, "bo-", label="Training Acc")
plt.plot(epochs, val_acc, "ro--", label="Validation Acc")
plt.title("Training and Validation Accuracy")
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
plt.show()
MobileNet迁移学习
前面预处理是一样的,就是模型预训练和定义不一样:
mobilenet_model = MobileNet(weights="imagenet",
include_top=False,
input_shape=(224, 224, 3))
#调整X_train的图片尺寸
print("调整X_train的图片尺寸...")
X_train_new = np.array(
[np.asarray(Image.fromarray(X_train[i]).resize(
(224, 224))) for i in range(0, len(X_train))])
X_train_new = X_train_new.astype("float32")
# 训练数据的数据前处理
train_input = preprocess_input(X_train_new)
# 调整X_test的图片尺寸
print("调整X_test的图片尺寸...")
X_test_new = np.array(
[np.asarray(Image.fromarray(X_test[i]).resize(
(224, 224))) for i in range(0, len(X_test))])
X_test_new = X_test_new.astype("float32")
# 测试数据的数据前处理
test_input = preprocess_input(X_test_new)
# 定义模型
model = Sequential()
model.add(mobilenet_model)
model.add(Dropout(0.5))
model.add(GlobalAveragePooling2D())
model.add(Dropout(0.5))
model.add(Dense(10, activation="softmax"))
model.summary() # 示模型摘要资讯
# 冻结上层模型
mobilenet_model.trainable = False
# 编译模型
model.compile(loss="categorical_crossentropy", optimizer="adam",
metrics=["accuracy"])
后面的评估也是一样的