下载地址:https://www.kaggle.com/c/dogs-vs-cats/data网络
下载的训练集中有2.5W张猫猫狗狗的图片,我这里只用训练测试集压缩包就好了,验证集和测试集均可以从中切分。app
观察图片可得知命名方式,猫图片为cat.数字.jpg,狗图片为dog.数字.jpg,各有12500张。测试
数据须要分红三份:训练集、验证集和测试集。lua
我打算使用1.9W张图片做为训练集,4000张图片做为验证集,2000张图片做为测试集。spa
import os,shutil from tensorflow import keras import matplotlib.pyplot as plt from tensorflow.keras.applications.inception_v3 import InceptionV3 from tensorflow.keras import layers #原始图片存放目录 origin_dir = './origin/train' #训练数据集存储位置 base_dir = './data' #训练集 验证集 测试集 train_dir = base_dir + '/train' validation_dir = base_dir + '/validation' test_dir = base_dir + '/test' #若是目录存在先删掉 if True == os.path.exists(base_dir) : shutil.rmtree(base_dir) os.makedirs(base_dir) #建立子目录 validation_dog_dir = validation_dir + '/dog' validation_cat_dir = validation_dir + '/cat' test_dog_dir = test_dir + '/dog' test_cat_dir = test_dir + '/cat' train_dog_dir = train_dir + '/dog' train_cat_dir = train_dir + '/cat' #建立目录 os.makedirs(validation_dog_dir) os.makedirs(validation_cat_dir) os.makedirs(test_dog_dir) os.makedirs(test_cat_dir) os.makedirs(train_dog_dir) os.makedirs(train_cat_dir) #复制2000张狗图片到验证数据集狗目录 files = ['dog.{}.jpg'.format(i) for i in range(2000)] for file in files : src = os.path.join(origin_dir,file) dst = os.path.join(validation_dog_dir,file) shutil.copy(src,dst) #复制2000张猫图片到验证数据集猫目录 files = ['cat.{}.jpg'.format(i) for i in range(2000)] for file in files : src = os.path.join(origin_dir,file) dst = os.path.join(validation_cat_dir,file) shutil.copy(src,dst) #复制1000张狗图片到测试数据集狗目录 files = ['dog.{}.jpg'.format(i) for i in range(2000,3000)] for file in files : src = os.path.join(origin_dir,file) dst = os.path.join(test_dog_dir,file) shutil.copy(src,dst) #复制1000张猫图片到测试数据集狗目录 files = ['cat.{}.jpg'.format(i) for i in range(2000,3000)] for file in files : src = os.path.join(origin_dir,file) dst = os.path.join(test_cat_dir,file) shutil.copy(src,dst) #复制9500张狗图片到训练数据集狗目录 files = ['dog.{}.jpg'.format(i) for i in range(3000,12500)] for file in files : src = os.path.join(origin_dir,file) dst = os.path.join(train_dog_dir,file) shutil.copy(src,dst) #复制9500张猫图片到训练数据集猫目录 files = ['cat.{}.jpg'.format(i) for i in range(3000,12500)] for file in files : src = os.path.join(origin_dir,file) dst = os.path.join(train_cat_dir,file) shutil.copy(src,dst)
我将使用在ImageNet上训练好的大型卷积神经网络Inception-V3进行迁移,ImageNet数据集包含140万张图片,1000多个分类,包含了不少动物类别,猫和狗天然也在其中,在ImageNet上训练好的模型还有Eception、VGG1六、VGG1九、ResNet、MobileNet等。code
conv_base = InceptionV3(weights='imagenet',include_top=False,input_shape=(299,299,3))
include_top=False表示不须要网络顶层,也就是输出层,由于我只须要它提取的特征,在其基础上我要添加网络层继续训练。orm
在训练以前必定要将迁移的网络进行冻结,InceptionV3模型有两千一百万个参数,不冻结的话,其中的权重会在训练过程当中被修改,这会对原网络的优秀性形成破坏,再者说,不冻结的话至关于本身从新训练一个InceptionV3模型,我估计我这电脑跑一个月都不必定能跑的完。blog
可是呢,我不能将它冻结完,由于迁移的模型是以识别1000个类别而诞生的,我这里只有猫和狗2个类别,因此我须要微调模型让它更能适应处理我此时此刻面对的问题,怎么解决呢?办法是冻结,但不冻结所有,留几层出来参与训练。图片
InceptionV3的网络结构是由一块一块的Inception组成,每一块Inception包含了多种不一样尺寸的卷积核、池化层、批标准化等组合。我解冻最后两块Inception,经过观察网络结构能够定位到从第249层开始解冻。get
conv_base.trainable = True for layer in conv_base.layers[:249]: layer.trainable = False for layer in conv_base.layers[249:]: layer.trainable = True
在Inception的基础上,我再怼上两层全接连网络,正则化和Dropout也怼上,让个人曲线更加丝滑柔顺。
model = keras.models.Sequential([ conv_base, keras.layers.Flatten(), keras.layers.Dropout(0.3), keras.layers.Dense(256,activation='relu',kernel_regularizer=keras.regularizers.l2()), keras.layers.Dropout(0.3), keras.layers.Dense(1,activation='sigmoid') ])
model.compile(optimizer=keras.optimizers.SGD(lr=0.0001,momentum=0.9),loss='binary_crossentropy', metrics=['accuracy'])
img_width=299 img_height=299 img_channel = 3 batch_size=32 epochs = 6 train_datagen = keras.preprocessing.image.ImageDataGenerator(rescale=1. / 255) validation_datagen = keras.preprocessing.image.ImageDataGenerator(rescale=1. / 255) test_datagen = keras.preprocessing.image.ImageDataGenerator(rescale=1. / 255) train_generator = train_datagen.flow_from_directory( train_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary') validation_generator = validation_datagen.flow_from_directory( validation_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary') test_generator = test_datagen.flow_from_directory( test_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary')
history = model.fit( train_generator, steps_per_epoch=train_generator.n // batch_size, epochs=epochs, validation_data=validation_generator, validation_steps=validation_generator.n // batch_size, verbose=1)
这个生成器的训练之前是model.fit_generator方法,从TensorFlow2.1开始就废弃了,可直接使用model.fit方法传入生成器。
score = model.evaluate(test_generator, steps=test_generator.n // batch_size) print('测试准确率:{}, 测试loss值: {}'.format(score[1], score[0]))
plt.rcParams['font.sans-serif']=['SimHei'] acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] plt.subplot(1, 2, 1) plt.plot(acc, label='训练Acc') plt.plot(val_acc, label='测试Acc') plt.title('Acc曲线') plt.legend() plt.subplot(1, 2, 2) plt.plot(loss, label='训练Loss') plt.plot(val_loss, label='测试Loss') plt.title('Loss曲线') plt.legend() plt.show()