这篇是tensorflow版本,pytorch版本会在下一篇博客给出 友情提示:尽量上GPU,博主CPU上跑一个VGG16花了1.5h。。。
数据集获取
- 网盘下载
链接:https://pan.baidu.com/s/1kqfkr2X7mMkuFXb6C3KgTg 提取码:xzyh - kaggle官网自行下载
一共包含25000张猫狗图像,每个类别有12500张。
网络设计从简单到复杂,让你一步步感受精度的提升
数据准备
创建一个新的数据集,猫狗各含1000个测试集,500个验证集,500个测试集。 创建一个新的文件夹dogs_and_cats_small,在该文件夹下,创建‘train’,‘validation’,‘test’,在这三个子文件下,再分别创建‘dogs’,‘cats’,然后将对应数据放到对应文件夹下(友情提示需要给出软件读写文件的权限)
import os,shutil
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import models
from tensorflow.keras import layers,optimizers
from tensorflow.keras.applications import VGG16
original_dataset_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/kaggle/train"
base_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/cat_and_dog_small"
os.mkdir(base_dir)
train_dir=os.path.join(base_dir,'train')
os.mkdir(train_dir)
validation_dir=os.path.join(base_dir,'validation')
os.mkdir(validation_dir)
test_dir=os.path.join(base_dir,'test')
os.mkdir(test_dir)
train_cats_dir=os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
validation_cats_dir=os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)
test_cats_dir=os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)
train_dogs_dir=os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)
validation_dogs_dir=os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)
test_dogs_dir=os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)
fnames=['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_dogs_dir,fname)
shutil.copyfile(src,dst)
网络设计
1.简单的CNN(73%)
1)网络结构
def build_model():
model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Flatten())
model.add(layers.Dense(256,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))
return model
3)完整代码:
import os,shutil
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import models
from tensorflow.keras import layers,optimizers
from tensorflow.keras.applications import VGG16
original_dataset_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/kaggle/train"
base_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/cat_and_dog_small"
os.mkdir(base_dir)
train_dir=os.path.join(base_dir,'train')
os.mkdir(train_dir)
validation_dir=os.path.join(base_dir,'validation')
os.mkdir(validation_dir)
test_dir=os.path.join(base_dir,'test')
os.mkdir(test_dir)
train_cats_dir=os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
validation_cats_dir=os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)
test_cats_dir=os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)
train_dogs_dir=os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)
validation_dogs_dir=os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)
test_dogs_dir=os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)
fnames=['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_dogs_dir,fname)
shutil.copyfile(src,dst)
def build_model():
model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Flatten())
model.add(layers.Dense(256,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))
return model
def draw(history):
loss=history.history['loss']
epochs=range(1,len(loss)+1)
plt.subplot(1,2,1)
plt.plot(epochs,loss,'bo',label='Training loss')
plt.title("Training loss")
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.subplot(1,2,2)
accuracy=history.history['accuracy']
plt.plot(epochs,accuracy,'bo',label='Training accuracy')
plt.title("Training accuracy")
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.suptitle("Train data")
plt.legend()
plt.show()
if __name__=='__main__':
model=build_model()
optimizer=optimizers.RMSprop(lr=1e-4)
model.compile(optimizer=optimizer,loss='binary_crossentropy',metrics=['accuracy'])
train_datagen=ImageDataGenerator(rescale=1./255,)
validation_datagen=ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_directory(
train_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
validation_generator=validation_datagen.flow_from_directory(
validation_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
history=model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
validation_steps=50
)
draw(history)
model.save('model_first.h5')
4)结果展示
可以看到迭代2000张数据30次后,验证集识别精度可达到73%左右,这个精度远远不够目标,下面进行优化
2.数据增强后的CNN(82%)
1)数据增强(data augmentation)
让有限的样本通过几何变换生成更多训练数据。 这里tensorflow提供各一个ImageDataGenerator供我们进行数据增
train_datagen=ImageDataGenerator(rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
其他更多参数ommand+B浏览源码查阅 如何显示增强后的数据:
def display_cat(train_cats_dir,train_datagen):
fnames=[os.path.join(train_cats_dir,fname) for fname in os.listdir(train_cats_dir)]
img_path=fnames[3]
img=image.load_img(img_path,target_size=(150,150))
x=image.img_to_array(img)
x=x.reshape((1,)+x.shape)
i=0
for batch in train_datagen.flow(x,batch_size=1):
plt.figure(i)
imgplot=plt.imshow(image.array_to_img(batch[0]))
i+=1
if(i%4==0):
break
plt.show()
结果展示:
2)小tip
使用数据增强来训练网络,网络将不会看到两次同样的输入。但是,看到的输入仍然是高度相关的,因为输入来源于少量的原始输入。无法生成新信息,只能混淆现有信息。为了进一步降低过拟合,可以添加dropout层于全连接分类器之前。
3)完整代码
import os,shutil
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing import image
from tensorflow.keras import models
from tensorflow.keras import layers,optimizers
from tensorflow.keras.applications import VGG16
original_dataset_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/kaggle/train"
base_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/cat_and_dog_small"
os.mkdir(base_dir)
train_dir=os.path.join(base_dir,'train')
os.mkdir(train_dir)
validation_dir=os.path.join(base_dir,'validation')
os.mkdir(validation_dir)
test_dir=os.path.join(base_dir,'test')
os.mkdir(test_dir)
train_cats_dir=os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
validation_cats_dir=os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)
test_cats_dir=os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)
train_dogs_dir=os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)
validation_dogs_dir=os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)
test_dogs_dir=os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)
fnames=['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_dogs_dir,fname)
shutil.copyfile(src,dst)
def display_cat(train_cats_dir,train_datagen):
fnames=[os.path.join(train_cats_dir,fname) for fname in os.listdir(train_cats_dir)]
img_path=fnames[3]
img=image.load_img(img_path,target_size=(150,150))
x=image.img_to_array(img)
x=x.reshape((1,)+x.shape)
i=0
for batch in train_datagen.flow(x,batch_size=1):
plt.figure(i)
imgplot=plt.imshow(image.array_to_img(batch[0]))
i+=1
if(i%4==0):
break
plt.show()
def build_model():
model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(256,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))
return model
def draw(history):
val_loss=history.history['val_loss']
epochs=range(1,len(val_loss)+1)
plt.subplot(1,2,1)
plt.plot(epochs,val_loss,'bo',label='Validation loss')
plt.title("Validation loss")
plt.xlabel('Epochs')
plt.ylabel('Val_Loss')
plt.legend()
plt.subplot(1,2,2)
val_accuracy=history.history['val_accuracy']
plt.plot(epochs,val_accuracy,'bo',label='Validation accuracy')
plt.title("Validation accuracy")
plt.xlabel('Epochs')
plt.ylabel('Val_accurary')
plt.suptitle("Validation data")
plt.legend()
plt.show()
if __name__=='__main__':
model=build_model()
optimizer=optimizers.RMSprop(lr=1e-4)
model.compile(optimizer=optimizer,loss='binary_crossentropy',metrics=['accuracy'])
train_datagen = ImageDataGenerator(rescale=1. / 255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
validation_datagen=ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_directory(
train_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
validation_generator=validation_datagen.flow_from_directory(
validation_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
history=model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
validation_steps=50
)
draw(history)
model.save('data_augmentation_model_two.h5')
4)结果展示
数据增强后,验证集acc可达80%+,还需进一步提升
3.使用预训练的卷积神经网(90%)
CNN包含两部分:
- 一系列卷机层和池化层(卷积基)
- 全连接分类器
卷积基学到的的特征更佳通用,更适合复用。我们采用vgg16卷积基,它可以识别1000类,是一个经典的网络结构。我们需要在它基础上添加一些全连接层和dropout层打造一个猫狗识别的专用分类器。
1)基于VGG16进行特征过滤
特征过滤模块:
def extract_featuers(directory,sample_count,datagen,batch_size):
features=np.zeros(shape=(sample_count,4,4,512))
labels=np.zeros(shape=(sample_count))
generator=datagen.flow_from_directory(
directory,
target_size=(150,150),
batch_size=batch_size,
class_mode='binary'
)
i=0
for input_batch,label_batch in generator:
features_batch=con_base.predict(input_batch)
features[i*batch_size:(i+1)*batch_size]=features_batch
labels[i*batch_size:(i+1)*batch_size]=label_batch
i+=1
if i*batch_size >= sample_count:
break
return features,labels
这里只使用vgg16进行特征提取,进而训练自己的全连接层。
2)网络结构
实例化vgg16
def instantiate_vgg16():
'''
实例化vgg16
weights:模型初始化的权重检查点
include_top:指模型是否包含最后的全连接分类器,默认对应imageNet的1000个类别
input_shape:输入到网络的张量形状,默认可处理任意形状输入
'''
return VGG16(weights='imagenet',include_top=False,input_shape=(150,150,3))
3)完整代码
import os,shutil
import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import models
from tensorflow.keras import layers,optimizers
from tensorflow.keras.applications import VGG16
base_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/cat_and_dog_small"
train_dir=os.path.join(base_dir,'train')
validation_dir=os.path.join(base_dir,'validation')
test_dir=os.path.join(base_dir,'test')
def build_model():
model=models.Sequential()
model.add(layers.Dense(256,activation='relu',input_dim=4*4*512))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1,activation='sigmoid'))
return model
def extract_featuers(directory,sample_count,datagen,batch_size):
features=np.zeros(shape=(sample_count,4,4,512))
labels=np.zeros(shape=(sample_count))
generator=datagen.flow_from_directory(
directory,
target_size=(150,150),
batch_size=batch_size,
class_mode='binary'
)
i=0
for input_batch,label_batch in generator:
features_batch=con_base.predict(input_batch)
features[i*batch_size:(i+1)*batch_size]=features_batch
labels[i*batch_size:(i+1)*batch_size]=label_batch
i+=1
if i*batch_size >= sample_count:
break
return features,labels
def draw(history):
val_loss=history.history['val_loss']
epochs=range(1,len(val_loss)+1)
plt.subplot(1,2,1)
plt.plot(epochs,val_loss,'bo',label='Validation loss')
plt.title("Validation loss")
plt.xlabel('Epochs')
plt.ylabel('Val_Loss')
plt.legend()
plt.subplot(1,2,2)
val_accuracy=history.history['val_accuracy']
plt.plot(epochs,val_accuracy,'bo',label='Validation accuracy')
plt.title("Validation accuracy")
plt.xlabel('Epochs')
plt.ylabel('Val_accurary')
plt.suptitle("Validation data")
plt.legend()
plt.show()
if __name__=='__main__':
model=build_model()
model.compile(optimizer=optimizers.RMSprop(lr=1e-5),loss='binary_crossentropy',metrics=['accuracy'])
train_datagen = ImageDataGenerator(rescale=1. / 255)
validation_datagen=ImageDataGenerator(rescale=1./255)
test_datagen=ImageDataGenerator(rescale=1./255)
con_base=VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
train_features,train_labels=extract_featuers(train_dir,2000,datagen=train_datagen,batch_size=20)
validation_features,validation_labels=extract_featuers(validation_dir,1000,datagen=validation_datagen,batch_size=20)
test_features,test_labels=extract_featuers(test_dir,1000,datagen=test_datagen,batch_size=20)
train_features=np.reshape(train_features,(2000,4*4*512))
validation_features=np.reshape(validation_features,(1000,4*4*512))
test_features=np.reshape(test_features,(1000,4*4*512))
history=model.fit(train_features,train_labels,
epochs=30,
batch_size=20,
validation_data=(validation_features,validation_labels)
)
draw(history)
model.save('base_vgg16_model_three.h5')
4)结果展示
验证集精确度大约90%,下面进一步进行提高
5)注意点
这里只是使用vgg16提取一些公用的特征,并不会重新训练vgg16,所以传入vgg16的图片不应该进行数据增强。若将数据增强后图片传入,经过30轮训练会降低2个百分点。
4.使用数据增强的特征提取(95%)
这里与方法3的区别在于,虽然冻结了vgg16参数更新,但是每一轮训练都会经过vgg16进行特征提取。由于vgg16有1千多万参数,网络向前传播进行提取特征将会是非常慢的,强烈建议上GPU,cpu至少花费好几个小时,然后风扇还呜呜呜呜叫唤。
1)网络结构
注意需要冻结vgg16的参数。 网络结构同上一个,网络定义细节代码需要稍加改动
def instantiate_vgg16():
'''
实例化vgg16
weights:模型初始化的权重检查点
include_top:指模型是否包含最后的全连接分类器,默认对应imageNet的1000个类别
input_shape:输入到网络的张量形状,默认可处理任意形状输入
'''
return VGG16(weights='imagenet',include_top=False,input_shape=(150,150,3))
def build_model():
model=models.Sequential()
conv_base=instantiate_vgg16()
conv_base.trainable = False
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))
return model
小疑问 为什么这种网络写法,随着训练进行验证集精度初次就固定了
model=models.Sequential()
model.add(instantiate_vgg16())
model.trainable=False
model.add(layers.Flatten())
两种写法网络layer的trainable是一致啊??????
2)完整代码
import os,shutil
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import models
from tensorflow.keras import layers,optimizers
from tensorflow.keras.applications import VGG16
original_dataset_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/kaggle/train"
base_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/cat_and_dog_small"
os.mkdir(base_dir)
train_dir=os.path.join(base_dir,'train')
os.mkdir(train_dir)
validation_dir=os.path.join(base_dir,'validation')
os.mkdir(validation_dir)
test_dir=os.path.join(base_dir,'test')
os.mkdir(test_dir)
train_cats_dir=os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
validation_cats_dir=os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)
test_cats_dir=os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)
train_dogs_dir=os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)
validation_dogs_dir=os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)
test_dogs_dir=os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)
fnames=['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_dogs_dir,fname)
shutil.copyfile(src,dst)
def instantiate_vgg16():
'''
实例化vgg16
weights:模型初始化的权重检查点
include_top:指模型是否包含最后的全连接分类器,默认对应imageNet的1000个类别
input_shape:输入到网络的张量形状,默认可处理任意形状输入
'''
return VGG16(weights='imagenet',include_top=False,input_shape=(150,150,3))
def thaw_vgg16():
conv_base = instantiate_vgg16()
for layer in conv_base.layers:
if(layer== 'block5_conv1' or layer== 'block5_conv2' or layer== 'block5_conv3'):
layer.trainable=True
else:
layer.trainable=False
return conv_base
def build_model():
model=models.Sequential()
conv_base=instantiate_vgg16()
conv_base.trainable = False
model.add(conv_base)
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))
return model
def draw(history):
loss=history.history['loss']
epochs=range(1,len(loss)+1)
plt.subplot(1,2,1)
plt.plot(epochs,loss,'bo',label='Training loss')
plt.title("Training loss")
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.subplot(1,2,2)
accuracy=history.history['accuracy']
plt.plot(epochs,accuracy,'bo',label='Training accuracy')
plt.title("Training accuracy")
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.suptitle("Train data")
plt.legend()
plt.show()
if __name__=='__main__':
model=build_model()
optimizer=optimizers.RMSprop(lr=1e-4)
model.compile(optimizer=optimizer,loss='binary_crossentropy',metrics=['accuracy'])
train_datagen=ImageDataGenerator(rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
validation_datagen=ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_directory(
train_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
validation_generator=validation_datagen.flow_from_directory(
validation_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
history=model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=100,
validation_data=validation_generator,
validation_steps=50
)
draw(history)
model.save('base_vgg16.h5')
3)结果展示
电脑冒烟了,跑不动了。。。 大约可以得到95%的精确度
5.在4基础上进行VGG16网络层微调(97%)
1)如何微调
- 卷机基更靠近底部的层编码更加具有通用性,而更靠近顶部的层编码更具有专业化特征。
- 训练的参数越多,过拟合风险越大
所以,对于vgg16,我们解冻其后三层,其他层参数保持不动。更新网络部分函数:
def thaw_vgg16():
conv_base = instantiate_vgg16()
for layer in conv_base.layers:
if(layer== 'block5_conv1' or layer== 'block5_conv2' or layer== 'block5_conv3'):
layer.trainable=True
else:
layer.trainable=False
return conv_base
def build_model():
model=models.Sequential()
model.add(thaw_vgg16())
model.trainable=False
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))
return model
2)完整代码
验证集精度大约97% 相对于4提升两个百分点。
import os,shutil
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import models
from tensorflow.keras import layers,optimizers
from tensorflow.keras.applications import VGG16
original_dataset_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/kaggle/train"
base_dir="/Users/zhangcaihui/Downloads/kaggle猫狗大战/cat_and_dog_small"
os.mkdir(base_dir)
train_dir=os.path.join(base_dir,'train')
os.mkdir(train_dir)
validation_dir=os.path.join(base_dir,'validation')
os.mkdir(validation_dir)
test_dir=os.path.join(base_dir,'test')
os.mkdir(test_dir)
train_cats_dir=os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
validation_cats_dir=os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)
test_cats_dir=os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)
train_dogs_dir=os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)
validation_dogs_dir=os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)
test_dogs_dir=os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)
fnames=['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_dogs_dir,fname)
shutil.copyfile(src,dst)
def instantiate_vgg16():
'''
实例化vgg16
weights:模型初始化的权重检查点
include_top:指模型是否包含最后的全连接分类器,默认对应imageNet的1000个类别
input_shape:输入到网络的张量形状,默认可处理任意形状输入
'''
return VGG16(weights='imagenet',include_top=False,input_shape=(150,150,3))
def thaw_vgg16():
conv_base = instantiate_vgg16()
for layer in conv_base.layers:
if(layer== 'block5_conv1' or layer== 'block5_conv2' or layer== 'block5_conv3'):
layer.trainable=True
else:
layer.trainable=False
return conv_base
def build_model():
model=models.Sequential()
conv_base=thaw_vgg16()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(256,activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
return model
def draw(history):
loss=history.history['loss']
epochs=range(1,len(loss)+1)
plt.subplot(1,2,1)
plt.plot(epochs,loss,'bo',label='Training loss')
plt.title("Training loss")
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.subplot(1,2,2)
accuracy=history.history['accuracy']
plt.plot(epochs,accuracy,'bo',label='Training accuracy')
plt.title("Training accuracy")
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.suptitle("Train data")
plt.legend()
plt.show()
if __name__=='__main__':
model=build_model()
optimizer=optimizers.RMSprop(lr=2e-5)
model.compile(optimizer=optimizer,loss='binary_crossentropy',metrics=['accuracy'])
train_datagen=ImageDataGenerator(rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
validation_datagen=ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_directory(
train_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
validation_generator=validation_datagen.flow_from_directory(
validation_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
history=model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
validation_steps=50
)
draw(history)
model.save('base_vgg16.h5')
3)结果展示
暂无
总结
站在前人的肩膀上打造自己的专属技能。 END!
|