Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)

这篇是tensorflow版本,pytorch版本会在下一篇博客给出
友情提示:尽量上GPU,博主CPU上跑一个VGG16花了1.5h。。。

Tensorflow实现kaggle猫狗识别

数据集获取

  1. 网盘下载
    链接:https://pan.baidu.com/s/1kqfkr2X7mMkuFXb6C3KgTg
    提取码:xzyh
  2. kaggle官网自行下载

一共包含25000张猫狗图像,每个类别有12500张。

网络设计从简单到复杂,让你一步步感受精度的提升

数据准备

创建新的数据集。猫和狗分别包含1000个测试集、500个验证集和500个测试集。

[En]

Create a new dataset. Cats and dogs each contain 1000 test sets, 500 verification sets, and 500 test sets.

创建一个新的文件夹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

Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)

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)结果展示

Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)
可以看到迭代2000张数据30次后,验证集识别精度可达到73%左右,这个精度远远不够目标,下面进行优化

; 2.数据增强后的CNN(82%)

1)数据增强(data augmentation)

通过几何变换,让有限的样本生成更多的训练数据。

[En]

Let the limited samples generate more training data through geometric transformation.

这里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()

结果展示:

Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)

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)结果展示

Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)
数据增强后,验证集acc可达80%+,还需进一步提升

; 3.使用预训练的卷积神经网(90%)

CNN包含两部分:

  1. 一系列卷机层和池化层(卷积基)
  2. 全连接分类器

卷积基学到的的特征更佳通用,更适合复用。我们采用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)网络结构

Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)
实例化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)结果展示

Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)
验证集精确度大约90%,下面进一步进行提高

; 5)注意点

这里只是使用vgg16提取一些公用的特征,并不会重新训练vgg16,所以传入vgg16的图片不应该进行数据增强。若将数据增强后图片传入,经过30轮训练会降低2个百分点。

4.使用数据增强的特征提取(95%)

这里与方法3的区别在于,虽然冻结了vgg16参数更新,但是每一轮训练都会经过vgg16进行特征提取。由于vgg16有1千多万参数,网络向前传播进行提取特征将会是非常慢的, 强烈建议上GPU,cpu至少花费好几个小时,然后风扇还呜呜呜呜叫唤。

1)网络结构

注意需要冻结vgg16的参数。
网络结构与前一个相同,网络定义明细代码需要稍作修改。

[En]

The network structure is the same as the previous one, and the network definition detail code needs to be changed slightly.

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)结果展示

电脑冒烟了,不能运行了。

[En]

The computer is smoking and can’t run.

大约可以得到95%的精确度

5.在4基础上进行VGG16网络层微调(97%)

1)如何微调

  1. 卷机基更靠近底部的层编码更加具有通用性,而更靠近顶部的层编码更具有专业化特征。
  2. 训练的参数越多,过拟合风险越大

所以,对于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)结果展示

暂无

总结

站在前辈的肩膀上,练就自己的本领。

[En]

Stand on the shoulders of your predecessors and build your own skills.

END!

Original: https://blog.csdn.net/qq_41317652/article/details/121685940
Author: 跨考上浙大
Title: Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/511706/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球