迁移学习
当我们自己的训练数据不够时,我们可以借助别人已经训练好的模型,在别人模型的基础上进行二次训练。预训练好的模型一般是基于大量数据训练出来的,已经提取了一些特征。我们无需训练那些层,只需利用即可。然后加上我们自己的层以及输出层训练。做了一个小测试,基于inception模型,搭建自己的图片识别
自己的训练图片只有300张左右。
下载inception权重数据
!wget --no-check-certificate \
https://storage.googleapis.com/mledu-datasets/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5 \
-O inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5
import os
import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras import Model
from tensorflow.keras.applications.inception_v3 import InceptionV3
加载InceptionV3模型
local_weights_file = "model/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5"
pre_trained_model=InceptionV3(input_shape =(200,200,3),
include_top=False,
weights=None)
#加载权重
pre_trained_model.load_weights(local_weights_file)
# 因为是使用预训练好的模型,无需训练,所以将每一层设置为不可训练
for layer in pre_trained_model.layers:
layer.trainable=False
#pre_trained_model.summary()
#获取某一层的输出当做我们的输入,即我们从选定的一层开始,之前的层次都无需训练
last_layer = pre_trained_model.get_layer("mixed7")
last_output = last_layer.output
print(f"last output shape is {last_output.shape}")
Callback
class myCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self,epoch,logs={}):
if(logs.get("acc") > 0.99):
print("\n Reached 99% accuracy,so cancelling training")
self.model.stop_training=True
加入我们自己的层,构建模型
from tensorflow.keras.optimizers import Adam
#将Inception模型选择的输出层变成1维数据
x = layers.Flatten()(last_output)
#加全连接层
x = layers.Dense(1024,activation="relu")(x)
x = layers.Dropout(0.2)(x)
#输出层
x = layers.Dense(1,activation="sigmoid")(x)
model = Model(pre_trained_model.input,x)
model.compile(optimizer=Adam(lr=0.0001),
loss = "binary_crossentropy",
metrics=['acc'])
#model.summary()
加载数据,训练
train_dir = "images/trainning/"
validation_dir = "images/validation/"
train_dogs_dir = os.path.join(train_dir,"dogs")
train_humans_dir = os.path.join(train_dir,"humans")
validation_dogs_dir = os.path.join(validation_dir,"dogs")
validation_humans_dir = os.path.join(validation_dir,"humans")
print(f"size of training dogs:{len(os.listdir(train_dogs_dir))}")
print(f"size of training humans:{len(os.listdir(train_humans_dir))}")
print(f"size of validation dogs:{len(os.listdir(validation_dogs_dir))}")
print(f"size of validation humans:{len(os.listdir(validation_humans_dir))}")
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale=1./255.,
rotation_range=40,
shear_range=0.2,
zoom_range=0.3,
horizontal_flip=True)
validation_datagen = ImageDataGenerator(rescale=1./255.)
train_generator = train_datagen.flow_from_directory(train_dir,
batch_size=20,
target_size=(200,200),
class_mode="binary")
validation_generator = validation_datagen.flow_from_directory(validation_dir,
batch_size=20,
target_size=(200,200),
class_mode="binary")
history = model.fit_generator(train_generator,
steps_per_epoch=10,
epochs=10,
validation_data=validation_generator,
validation_steps=2,
verbose=2,
callbacks=[myCallback()]
)
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history["val_acc"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
epochs = range(len(acc))
plt.plot(epochs,acc,"r",label="Training accuracy")
plt.plot(epochs,val_acc,"b",label="validation_accuracy")
#plt.legend(loc=0)
plt.show()
预测
使用predict_generator进行预测。需要注意的是,预测的图片文件和训练时一样,放在文件夹下。
test_dir指向文件夹,文件夹下有子文件夹,然后再是图片。
使用filenames可以获取所有预测的图片。如果这样,则在predict_generator时需要设置几个参数,
才能使预测的结果和图片对应
1.shuffle:设置为False
2.batch_size:设置大小与测试图片大小一致
3.class_mode:None
test_datagen = ImageDataGenerator(rescale=1/255.)
test_dir = "images/test/"
test_size = len(os.listdir("images/test/all"))
test_generator = test_datagen.flow_from_directory(test_dir,
batch_size=test_size,
target_size=(200,200),
shuffle=False,
class_mode=None)
pred_y = model.predict_generator(test_generator,steps=1,verbose=1)
import numpy as np
logits = np.where(pred_y > 0.5,1,0)
pred_y = np.squeeze(pred_y)
import matplotlib.image as mpimg
columns = 5
test_size = len(test_generator.filenames)
test_dir = os.path.join('images/test/')
rows = int(test_size/5)
if test_size%5 != 0:
rows = rows+1
f,ax = plt.subplots(rows,columns,figsize=(10,10))
for i in range(0,test_size):
# predicting image
filename = test_generator.filenames[i]
path = test_dir + filename
if(pred_y[i] == 1):
label="human"
else:
label = "dog"
ax_idx_row = int(i/columns)
ax_idx_col = int(i%columns)
img_data = mpimg.imread(path)
ax[ax_idx_row][ax_idx_col].imshow(img_data)
ax[ax_idx_row][ax_idx_col].set_title(label,color="red")
ax[ax_idx_row][ax_idx_col].axis("off")
plt.show()
总结:
1.下载权重数据
2.加载预训练模型
3.选择输出层次
4.在3的基础上加载自己的layer。