IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计) -> 正文阅读

[人工智能]Tensorflow实现kaggle猫狗识别(循序渐进进行网络设计)

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

数据集获取

  1. 网盘下载
    链接:https://pan.baidu.com/s/1kqfkr2X7mMkuFXb6C3KgTg
    提取码:xzyh
  2. 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:
    #前1000张猫头像复制到train_cats_dir目录下
    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:
    #接下来500张猫头像复制到validationcats_dir目录下
    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:
    #接下来500张猫头像复制到test_cats_dir目录下
    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:
    #前1000张猫头像复制到train_dogs_dir目录下
    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:
    #接下来500张猫头像复制到validation_dogs_dir目录下
    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:
    #接下来500张猫头像复制到test_dogs_dir目录下
    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

!](https://img-blog.csdnimg.cn/af734d36704441aea5b1f136ea53e3c0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Leo6ICD5LiK5rWZ5aSn,size_20,color_FFFFFF,t_70,g_se,x_16)

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:
    #前1000张猫头像复制到train_cats_dir目录下
    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:
    #接下来500张猫头像复制到validationcats_dir目录下
    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:
    #接下来500张猫头像复制到test_cats_dir目录下
    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:
    #前1000张猫头像复制到train_dogs_dir目录下
    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:
    #接下来500张猫头像复制到validation_dogs_dir目录下
    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:
    #接下来500张猫头像复制到test_dogs_dir目录下
    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,#相对于总高度0水平移动比例
                                 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)#转Numpy数组
    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:
    #前1000张猫头像复制到train_cats_dir目录下
    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:
    #接下来500张猫头像复制到validationcats_dir目录下
    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:
    #接下来500张猫头像复制到test_cats_dir目录下
    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:
    #前1000张猫头像复制到train_dogs_dir目录下
    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:
    #接下来500张猫头像复制到validation_dogs_dir目录下
    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:
    #接下来500张猫头像复制到test_dogs_dir目录下
    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)#转Numpy数组
    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,  # 相对于总高度0水平移动比例
                                       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'
    )
    #display_cat(train_cats_dir,train_datagen)
    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包含两部分:

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

卷积基学到的的特征更佳通用,更适合复用。我们采用vgg16卷积基,它可以识别1000类,是一个经典的网络结构。我们需要在它基础上添加一些全连接层和dropout层打造一个猫狗识别的专用分类器。

1)基于VGG16进行特征过滤

特征过滤模块:

def extract_featuers(directory,sample_count,datagen,batch_size):
    #初始化VGG16最后一层的返回格式
    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

#vgg16提取特征
def extract_featuers(directory,sample_count,datagen,batch_size):
    #VGG16最后一层的返回格式
    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)
                                       # rotation_range=40,  # 随机旋转角度范围
                                       # width_shift_range=0.2,  # 相对于总宽水平移动比例
                                       # height_shift_range=0.2,  # 相对于总高度0水平移动比例
                                       # shear_range=0.2,  # 随机错切角度
                                       # zoom_range=0.2,  # 随机缩放范围
                                       # horizontal_flip=True,  # 随机将一半图片翻转
                                       # fill_mode='nearest')
    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)
    #提取特征为(samples,4,4,512),展开为(samples,4*4*512)送入自定义分类器
    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:
    #前1000张猫头像复制到train_cats_dir目录下
    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:
    #接下来500张猫头像复制到validationcats_dir目录下
    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:
    #接下来500张猫头像复制到test_cats_dir目录下
    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:
    #前1000张猫头像复制到train_dogs_dir目录下
    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:
    #接下来500张猫头像复制到validation_dogs_dir目录下
    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:
    #接下来500张猫头像复制到test_dogs_dir目录下
    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()
    #实例化优化器0
    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,#相对于总高度0水平移动比例
                                     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')
    #test_loss,test_acc=model.evaluate(test_generator,steps=50)
    # print('test_loss: ',test_loss,' test_acc: ',test_acc)

3)结果展示

电脑冒烟了,跑不动了。。。
大约可以得到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:
    #前1000张猫头像复制到train_cats_dir目录下
    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:
    #接下来500张猫头像复制到validationcats_dir目录下
    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:
    #接下来500张猫头像复制到test_cats_dir目录下
    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:
    #前1000张猫头像复制到train_dogs_dir目录下
    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:
    #接下来500张猫头像复制到validation_dogs_dir目录下
    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:
    #接下来500张猫头像复制到test_dogs_dir目录下
    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()
    #实例化优化器0
    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,#相对于总高度0水平移动比例
                                     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')
    #test_loss,test_acc=model.evaluate(test_generator,steps=50)
    # print('test_loss: ',test_loss,' test_acc: ',test_acc)

3)结果展示

暂无

总结

站在前人的肩膀上打造自己的专属技能。
END!

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-12-06 15:15:13  更:2021-12-06 15:17:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 2:35:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码