数据集是猫狗分类的 网上很多资源
数据集:https://download.csdn.net/download/zqx951102/12675761
""""
#深度学习006-移花接木-用Keras迁移学习提升性能 https://www.jianshu.com/p/4e3d13a7f4bf
#此处我们用VGG16的卷积层统一提取所有图片的特征,将这些特征保存,然后直接加载特征来训练,加载数字比加载图片要快的多,故而训练也快得多
#可以看出,主要调整Conv block 5,前面的4个block不需调整。 https://www.jianshu.com/p/5c766be9a9d7
import numpy as np
import os,random,shutil
np.random.seed(7)
# 1, 准备数据集
#1,指定一些超参数:
train_data_dir='D:/Kaggle/dogsvscats/cats_and_dogs_small/train'
val_data_dir='D:/Kaggle/dogsvscats/cats_and_dogs_small/test' # keras中将测试集称为validation set
train_samples_num=2000 # train set中全部照片数
val_samples_num=800
IMG_W,IMG_H,IMG_CH=150,150,3 # 单张图片的大小
batch_size=16 # 不能是32,因为2000/32不能整除,后面会有影响。
epochs=180 # 用比较少的epochs数目做演示,节约训练时间
# 此处的训练集和测试集并不是原始图片的train set和test set,而是用VGG16对图片提取的特征,这些特征组成新的train set和test set
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras import applications
def save_bottlebeck_features():
datagen = ImageDataGenerator(rescale=1. / 255) # 不需图片增强 #生成一个 生成器
# build the VGG16 network
model = applications.VGG16(include_top=False, weights='imagenet')
# 使用imagenet的weights作为VGG16的初始weights,由于只是特征提取,故而只取前面的卷积层而不需要DenseLayer,故而include_top=False
generator = datagen.flow_from_directory( # 产生train set 以文件夹路径为参数,生成经过数据提升/归一化后的数据,在一个无限循环中无限产生batch数据
train_data_dir, #train数据集扩充
target_size=(IMG_W, IMG_H),
batch_size=batch_size,
class_mode=None, #shuffle函数的是将序列中的所有元素随机排序
shuffle=False) # 必须为False,否则顺序打乱之后,和后面的label对应不上。
bottleneck_features_train = model.predict_generator( #预训练
generator, train_samples_num // batch_size) # 如果是32,这个除法得到的是62,抛弃了小数,故而得到1984个sample
np.save('D:/bottleneck_features_train.npy', bottleneck_features_train)
print('bottleneck features of train set is saved.')
generator = datagen.flow_from_directory(
val_data_dir,
target_size=(IMG_W, IMG_H),
batch_size=batch_size,
class_mode=None,
shuffle=False)
bottleneck_features_validation = model.predict_generator(
generator, val_samples_num // batch_size) #这个验证 相当于 test数据集
np.save('D:/bottleneck_features_val.npy',bottleneck_features_validation)
print('bottleneck features of test set is saved.')
save_bottlebeck_features()
#上述通过扩充train和验证(test)数据集,然后在模型中预训练 提取特征 include_top=False保证了顶端的分类层失活
def my_model():
'''
自定义一个模型,该·模型仅仅相当于一个分类器,只包含有全连接层,对提取的特征进行分类即可
:return:
'''
# 模型的结构
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:])) # 将所有data进行flatten train_data:训练图片集的所有图片
model.add(Dense(256, activation='relu')) # 256个全连接单元
model.add(Dropout(0.5)) # dropout正则
model.add(Dense(1, activation='sigmoid')) # 此处定义的模型只有后面的全连接层,由于是本项目特殊的,故而需要自定义 2分类的模型结构
# 模型的配置
model.compile(optimizer='rmsprop',
loss='binary_crossentropy', metrics=['accuracy']) # model的optimizer等
return model
# 只需要训练分类器模型即可,不需要训练特征提取器
train_data = np.load('D:/bottleneck_features_train.npy') # 加载训练图片集的所有图片的VGG16-notop特征
train_labels = np.array(
[0] * int((train_samples_num / 2)) + [1] * int((train_samples_num / 2)))
# label是1000个cat,1000个dog,由于此处VGG16特征提取时是按照顺序,故而[0]表示cat,1表示dog
validation_data = np.load('D:/bottleneck_features_val.npy')
validation_labels = np.array(
[0] * int((val_samples_num / 2)) + [1] * int((val_samples_num / 2)))
#label是400个cat,400个dog,由于此处VGG16特征提取时是按照顺序,故而[0]表示cat,1表示dog
# 构建分类器模型
clf_model=my_model()
history_ft = clf_model.fit(train_data, train_labels,
epochs=epochs,
batch_size=batch_size,
validation_data=(validation_data, validation_labels))
# 画图,将训练时的acc和loss都绘制到图上
import matplotlib.pyplot as plt
def plot_training(history):
plt.figure(12)
plt.subplot(121) #第一幅子图
train_acc = history.history['acc']
val_acc = history.history['val_acc']
epochs = range(len(train_acc))
plt.plot(epochs, train_acc, 'b', label='train_acc')
plt.plot(epochs, val_acc, 'r', label='test_acc')
plt.title('Train and Test accuracy')
plt.legend()
plt.subplot(122) #第二幅子图
train_loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(train_loss))
plt.plot(epochs, train_loss, 'b', label='train_loss')
plt.plot(epochs, val_loss, 'r', label='test_loss')
plt.title('Train and Test loss')
plt.legend()
plt.show()
plot_training(history_ft)
# 将本模型保存一下
clf_model.save_weights('D:/top_FC_model')
# Found 2000 images belonging to 2 classes.
# bottleneck features of train set is saved.
# Found 1000 images belonging to 2 classes.
# bottleneck features of test set is saved.
# Train on 2000 samples, validate on 800 samples
#loss: 0.0014 - acc: 0.9990 - val_loss: 3.0336 - val_acc: 0.7825 300代结果
"""""
loss: 0.0058 - acc: 0.9985 - val_loss: 2.7147 - val_acc: 0.7863 训练180代结果
#深度学习007-Keras微调进一步提升性能 https://www.jianshu.com/p/5c766be9a9d7
import numpy as np
import os,random,shutil
np.random.seed(7)
# 1, 准备数据集
#1,指定一些超参数:
train_data_dir='D:/Kaggle/dogsvscats/cats_and_dogs_small/train'
val_data_dir='D:/Kaggle/dogsvscats/cats_and_dogs_small/test' # keras中将测试集称为validation set
train_samples_num=2000 # train set中全部照片数
val_samples_num=800
IMG_W,IMG_H,IMG_CH=150,150,3 # 单张图片的大小
batch_size=16 # 不能是32,因为2000/32不能整除,后面会有影响。
epochs=20 # 用比较少的epochs数目做演示,节约训练时间
# 2,准备图片数据流
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator( # 单张图片的处理方式,train时一般都会进行图片增强
rescale=1. / 255, # 图片像素值为0-255,此处都乘以1/255,调整到0-1之间
shear_range=0.2, # 斜切
zoom_range=0.2, # 放大缩小范围
horizontal_flip=True) # 水平翻转
train_generator = train_datagen.flow_from_directory(# 从文件夹中产生数据流
train_data_dir, # 训练集图片的文件夹
target_size=(IMG_W, IMG_H), # 调整后每张图片的大小
batch_size=batch_size,
class_mode='binary') # 此处是二分类问题,故而mode是binary
# 3,同样的方式准备测试集
val_datagen = ImageDataGenerator(rescale=1. / 255) # 只需要和trainset同样的scale即可,不需增强
val_generator = val_datagen.flow_from_directory(
val_data_dir,
target_size=(IMG_W, IMG_H),
batch_size=batch_size,
class_mode='binary')
# 4,构建模型
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras import applications
from keras import optimizers
from keras.models import Model
def build_model():
base_model = applications.VGG16(weights='imagenet', include_top=False, input_shape=(IMG_W, IMG_H, IMG_CH))
# 此处我们只需要卷积层不需要全连接层,故而inclue_top=False,一定要设置input_shape,否则后面会报错
# 这一步使用applications模块自带的VGG16函数直接加载了模型和参数,作为我们自己模型的“身子”
# 下面定义我们自己的分类器,作为我们自己模型的“头”
top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:])) # 如果没有设置input_shape,这个地方报错,显示output_shape有很多None
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(1, activation='sigmoid')) # 二分类问题
top_model.load_weights('D:/top_FC_model')
# 上面定义了模型结构,此处要把训练好的参数加载进来,
my_model = Model(inputs=base_model.input, outputs=top_model(base_model.output)) # 将“身子”和“头”组装到一起
# my_model就是我们组装好的完整的模型,也已经加载了各自的weights
# 普通的模型需要对所有层的weights进行训练调整,但是此处我们只调整VGG16的后面几个卷积层,所以前面的卷积层要冻结起来
for layer in my_model.layers[:17]: # 25层之前都是不需训练的
layer.trainable = False
# 模型的配置 fine-Tune的核心是对原始的骨架网络(此处为VGG16)进行参数的微调,所以需要用非常小的学习率,而且要用SGD优化器。
my_model.compile(loss='binary_crossentropy',
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), # 使用一个非常小的lr来微调
metrics=['accuracy'])
return my_model
# 开始用train set来微调模型的参数
print('start to fine-tune my model')
my_model=build_model()
history_ft = my_model.fit_generator(
train_generator,
steps_per_epoch=train_samples_num // batch_size, #2000/16=125批量
epochs=epochs,
validation_data=val_generator,
validation_steps=val_samples_num // batch_size)
# 画图,将训练时的acc和loss都绘制到图上
import matplotlib.pyplot as plt
def plot_training(history):
plt.figure(12)
plt.subplot(121)
train_acc = history.history['acc']
val_acc = history.history['val_acc']
epochs = range(len(train_acc))
plt.plot(epochs, train_acc, 'b', label='train_acc')
plt.plot(epochs, val_acc, 'r', label='test_acc')
plt.title('Train and Test accuracy')
plt.legend()
plt.subplot(122)
train_loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(train_loss))
plt.plot(epochs, train_loss, 'b', label='train_loss')
plt.plot(epochs, val_loss, 'r', label='test_loss')
plt.title('Train and Test loss')
plt.legend()
plt.show()
plot_training(history_ft)
print(len(my_model.layers)) #查看模型的整个层数 20层
#loss: 0.0912 - acc: 0.9700 - val_loss: 1.1004 - val_acc: 0.8675 等 于17层时候 15太乱 25全冻结了
0.1747 - acc: 0.9385 - val_loss: 0.3562 - val_acc: 0.8988 17层 20代 图看着凌乱了,,,再来试试100
loss: 0.0116 - acc: 0.9960 - val_loss: 0.7997 - val_acc: 0.8939 100代 结果