首页 > 其他分享 >猫狗识别-CNN与VGG实现

猫狗识别-CNN与VGG实现

时间:2022-10-11 17:02:31浏览次数:46  
标签:loss None val df VGG train CNN 识别 accuracy

本次项目首先使用CNN卷积神经网络模型进行训练,最终训练效果不太理想,出现了过拟合的情况。准确率达到0.72,loss达到0.54。使用预训练的VGG模型后,在测试集上准确率达到0.91,取得了不错的改进效果。

数据集

本次项目使用The Asirra 数据集,Asirra(Animal Species Image Recognition for Restricting Access)是一套人机交互证明系统(Human Interactive Proof),它使用猫和狗的图片来验证网站访问者是真人还是机器人。
Asirra使用的猫狗图片来自于世界上最大的流浪动物救助网站petfinder.com,图片被数千个流浪动物救助者进行手动分类和标准。它也为微软研究院提供了超过300万张猫狗图片。
我们使用的数据集包含25000张已标注的猫狗图片,和12500张未标注的测试图片。

数据处理

由于测试数据集的图片没有标签,所以我们从训练集中划出一部分作为测试集。

import numpy as np
import pandas as pd 
from keras.preprocessing.image import ImageDataGenerator, load_img
from tensorflow.keras.utils import to_categorical
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import random
import os

filenames= os.listdir("./train")

categories=[]

for filename in filenames:
    #从文件名中分离标签,0代表猫,1代表狗
    category=filename.split(".")[0]
    if category=="dog":
        categories.append(1)
    else:   
       categories.append(0)
        
        
df=pd.DataFrame({'filename':filenames,
                  'category':categories
                })    
df.shape #(25000,2)
df.head()

随机展示一张图片。

random_Img=random.choice(filenames)
image=load_img("./train/"+random_Img)
plt.imshow(image)

image.png
我们也可以发现数据集中的图片尺寸并不一致,有些图片中的猫狗太小不足以识别,或者只露了部分部位,这些都是属于质量不高的数据。
image.png image.png image.png

卷积神经网络

我们尝试使用卷积神经网络来进行模型训练

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization

model1 = Sequential()

model1.add(Conv2D(128, (3, 3), activation='relu', input_shape=(128,128,3)))
model1.add(BatchNormalization())
model1.add(MaxPooling2D(pool_size=(2, 2)))
model1.add(Dropout(0.25))

model1.add(Conv2D(64, (3, 3), activation='relu'))
model1.add(BatchNormalization())
model1.add(MaxPooling2D(pool_size=(2, 2)))
model1.add(Dropout(0.25))

model1.add(Conv2D(64, (3, 3), activation='relu'))
model1.add(BatchNormalization())
model1.add(MaxPooling2D(pool_size=(2, 2)))
model1.add(Dropout(0.25))

model1.add(Flatten())
model1.add(Dense(512, activation='relu'))
model1.add(BatchNormalization())
model1.add(Dropout(0.2))
model1.add(Dense(2, activation='softmax')) # 2 because we have cat and dog classes

model1.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

使用sklearn的train_test_split把数据集划分为训练集和测试集,测试集的比例test_size设置为0.20,随机数种子random_state设置为任意整数,这样不管重复多少次划分结果都是一致的。该函数默认参数 shuffle为True,对数据集进行随机打散。

train_df,validate_df=train_test_split(df,test_size=.20,random_state=4)
train_df=train_df.reset_index(drop=True)
validate_df=validate_df.reset_index(drop=True)

total_train=train_df.shape[0]
total_validate=validate_df.shape[0] #5000
batch_size=16

数据增强

为了避免过拟合,增加我们的训练数据集大小,通过对图片进行旋转、移位、缩放、亮度改变、色调改变、增加噪音等转换成一张与已有图片类似但却稍有不同的新图片。对于人眼来说这些图片很相似,但是对于一个未训练完成的机器学习模型来说却是不同的。卷积神经网络可以学习图片的细节特征,对于旋转、移位等具有不变性。通过数据增强可以强化我们训练出的模型的鲁棒性。
keras中提供了ImageDataGenerator类来进行图像数据增强,可以在训练过程中进行图像的随机变化,增加训练数据;还附带赠送了获取数据batch生成器对象的功能,省去了手工再去获取batch数据的部分。该类可以对图像进行多种变换操作,默认的初始化参数如下:

# keras/preprocessing/image.py
class ImageDataGenerator(image.ImageDataGenerator):
    def __init__(self,
                 featurewise_center=False,
                 samplewise_center=False,
                 featurewise_std_normalization=False,
                 samplewise_std_normalization=False,
                 zca_whitening=False,
                 zca_epsilon=1e-6,
                 rotation_range=0,
                 width_shift_range=0.,
                 height_shift_range=0.,
                 brightness_range=None,
                 shear_range=0.,
                 zoom_range=0.,
                 channel_shift_range=0.,
                 fill_mode='nearest',
                 cval=0.,
                 horizontal_flip=False,
                 vertical_flip=False,
                 rescale=None,
                 preprocessing_function=None,
                 data_format=None,
                 validation_split=0.0,
                 dtype=None):

在这里我们对训练数据进行旋转、标准化、剪切范围、缩放范围、水平翻转、宽度变换、高度变换。对测试集的图片就无需进行数据增强了,只需要按照训练集一样进行rescaling标准化。
ImageDataGenerator的flow_from_dataframe用于从pandas的DataFrame中载入图片数据,同时自动进行数据增强和生成批数据。我们之前定义的tran_df,一列为图片文件名,一列为图片对于的分类。传入flow_from_dataframe后,会通过我们定义的dataframe、文件路径读取图片,target_size设置目标图像尺寸,batch_size则是批大小,x_col和y_col为dataframe中的图片名和标签列名称。对于class_mode的设置,‘categorical’为one-hot编码。该方法shuffle参数默认为True,即也默认打散数据。

train_datagen=ImageDataGenerator(
    rotation_range=30,
    rescale=1./255,
    shear_range=0.4,
    zoom_range=0.4,
    horizontal_flip=True,
    width_shift_range=0.4,
    height_shift_range=0.4
)

train_generator=train_datagen.flow_from_dataframe(
    
    train_df,
    "./train",
    x_col='filename',
    y_col='category',
    target_size=(128,128),
    class_mode='categorical',
    batch_size=batch_size
    
)

validate_datagen=ImageDataGenerator(
    rescale=1./255
)

validate_generator=validate_datagen.flow_from_dataframe(
    validate_df,
    "./train",
    x_col='filename',
    y_col='category',
    target_size=(128,128),
    class_mode='categorical',
    batch_size=batch_size
    
)

回调函数callback

回调函数是一个函数的合集,会在训练的阶段中所使用。你可以使用回调函数来查看训练模型的内在状态和统计。你可以传递一个列表的回调函数(作为 callbacks 关键字参数)到 Sequential 或 Model 类型的 .fit() 方法。在训练时,相应的回调函数的方法就会被在各自的阶段被调用。通过定义回调函数,我们可以检测训练过程并在符合条件时执行我们的回调函数。
EarlyStop用于监测定义的指标,当它不再提升时就停止训练。用于在训练中监测loss指标,防止过拟合。

EarlyStopping
keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=0, verbose=0, mode='auto', baseline=None, restore_best_weights=False)
当被监测的数量不再提升,则停止训练。

参数

monitor: 被监测的数据。
min_delta: 在被监测的数据中被认为是提升的最小变化, 例如,小于 min_delta 的绝对变化会被认为没有提升。
patience: 没有进步的训练轮数,在这之后训练就会被停止。
verbose: 详细信息模式。
mode: {auto, min, max} 其中之一。 在 min 模式中, 当被监测的数据停止下降,训练就会停止;在 max 模式中,当被监测的数据停止上升,训练就会停止;在 auto 模式中,方向会自动从被监测的数据的名字中判断出来。
baseline: 要监控的数量的基准值。 如果模型没有显示基准的改善,训练将停止。
restore_best_weights: 是否从具有监测数量的最佳值的时期恢复模型权重。 如果为 False,则使用在训练的最后一步获得的模型权重。

ReduceLROnPlateau用于评估当模型停止提升时降低学习率。

keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=10, verbose=0, mode='auto', min_delta=0.0001, cooldown=0, min_lr=0)
当标准评估停止提升时,降低学习速率。

当学习停止时,模型总是会受益于降低 2-10 倍的学习速率。 这个回调函数监测一个数据并且当这个数据在一定「有耐心」的训练轮之后还没有进步, 那么学习速率就会被降低。

例子

reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
                              patience=5, min_lr=0.001)
model.fit(X_train, Y_train, callbacks=[reduce_lr])
参数

monitor: 被监测的数据。
factor: 学习速率被降低的因数。新的学习速率 = 学习速率 * 因数
patience: 没有进步的训练轮数,在这之后训练速率会被降低。
verbose: 整数。0:安静,1:更新信息。
mode: {auto, min, max} 其中之一。如果是 min 模式,学习速率会被降低如果被监测的数据已经停止下降; 在 max 模式,学习塑料会被降低如果被监测的数据已经停止上升; 在 auto 模式,方向会被从被监测的数据中自动推断出来。
min_delta: 对于测量新的最优化的阀值,只关注巨大的改变。
cooldown: 在学习速率被降低之后,重新恢复正常操作之前等待的训练轮数量。
min_lr: 学习速率的下边界。

在这里我们定义Early Stopping的patience为10,即val_loss十轮训练后没有下降则训练停止。定义ReduceLROnPlateau的监测参数monitor为'val_acc'即验证集的accuracy,patience为2,减小因子为0.5(学习率每次更次为上次的0.5),学习率下边界为0.00001(学习率降到0.00001后不再下降)。

from keras.callbacks import EarlyStopping, ReduceLROnPlateau

earlystop = EarlyStopping(patience=10)
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', 
                                            patience=2, 
                                            verbose=1, 
                                            factor=0.5, 
                                            min_lr=0.00001)
callbacks = [earlystop, learning_rate_reduction]

训练卷积神经网络模型

history1=model1.fit_generator(
    train_generator,
    steps_per_epoch=total_train//batch_size, 
    epochs=10, 
    verbose=1,
    callbacks=callbacks, 
    validation_data=validate_generator,
    validation_steps=total_validate//batch_size,
)

训练过程如下:
image.png

加载预训练VGG模型

TensorFlow为我们提供了预训练的VGG模型,我们可以很方便的调用它。VGG预训练模型在大规模图像数据集上训练完成后,在图像识别和分类任务上表现良好。我们可以使用预训练模型进行迁移学习(transfer learning),在类似的图片识别任务上取得良好的效果。

from tensorflow.keras.applications import VGG16
from keras.models import Model
from keras.layers import Dense,Dropout
from keras.backend import pool2d
from keras.layers.pooling import GlobalAveragePooling2D

base_model = VGG16(input_shape = (128, 128, 3), # Shape of our images
include_top = False, # Leave out the last fully connected layer
weights = 'imagenet')

我们不需要训练VGG模型,可以以它为基础,添加更多的隐藏层。只有后面被添加的层才会被训练。我们在VGG模型的基础上添加了输出为512维的全连接层,一个平均池化层,一个rate为0.5的Dropout层,一个softmax全连接层。

base_model.trainable=False

model=base_model.output

model=Dense(512, activation='relu')(model)
model= GlobalAveragePooling2D()(model)
model=Dropout(rate=0.5)(model)
model=Dense(2, activation='softmax')(model)
model=Model(inputs=base_model.inputs, outputs=model)

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

model.summary()

定义好后的模型结构如下:

Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 128, 128, 3)]     0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 128, 128, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 128, 128, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 64, 64, 64)        0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 64, 64, 128)       73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 64, 64, 128)       147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 32, 32, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 32, 32, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 32, 32, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 32, 32, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 16, 16, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 16, 16, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 16, 16, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 8, 8, 512)         0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 8, 8, 512)         2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 8, 8, 512)         2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 8, 8, 512)         2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 4, 4, 512)         0         
_________________________________________________________________
dense_2 (Dense)              (None, 4, 4, 512)         262656    
_________________________________________________________________
global_average_pooling2d (Gl (None, 512)               0         
_________________________________________________________________
dropout_4 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 2)                 1026      
=================================================================
Total params: 14,978,370
Trainable params: 263,682
Non-trainable params: 14,714,688
_________________________________________________________________

VGG模型训练

与之前CNN网络模型训练一样,我们进行数据集的载入和处理,打散之后生成批训练数据。

from sklearn.model_selection import train_test_split
from tqdm import tqdm
import cv2
from sklearn.utils import shuffle

df["category"] = df["category"].replace({0: 'cat', 1: 'dog'})

#进行数据集划分交叉验证
train_df, validate_df = train_test_split(df, test_size=0.20, random_state=42)
train_df = train_df.reset_index(drop=True)
validate_df = validate_df.reset_index(drop=True)

total_train = train_df.shape[0]
total_validate = validate_df.shape[0]
batch_size=4

#生成训练数据
train_datagen=ImageDataGenerator(
    rescale=1/255
)

train_generator=train_datagen.flow_from_dataframe(train_df,
                                                      './train',
                                                      x_col='filename', 
                                                      y_col='category',
                                                      weight_col=None,
                                                      target_size=(128, 128),
                                                      class_mode='categorical', 
                                                      batch_size=batch_size,
                                                     )
#生成测试数据
validation_datagen = ImageDataGenerator(rescale=1./255)
validation_generator = validation_datagen.flow_from_dataframe(
    validate_df, 
    "./train", 
    x_col='filename',
    y_col='category',
    target_size=(128,128),
    class_mode='categorical',
    batch_size=batch_size
)
#定义回调函数
earlystop = EarlyStopping(patience=10)
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', 
                                            patience=2, 
                                            verbose=1, 
                                            factor=0.5, 
                                            min_lr=0.00001)
callbacks = [earlystop, learning_rate_reduction]
#进行模型训练
history = model.fit_generator(
    train_generator, 
    epochs=12,
    validation_data=validation_generator,
    validation_steps=total_validate//batch_size,
    steps_per_epoch=total_train//batch_size,
    callbacks=callbacks,
    verbose=1
)

训练的过程如下,最终在验证集上accuracy达到0.91。

Epoch 1/12
5000/5000 [==============================] - 99s 20ms/step - loss: 0.3466 - accuracy: 0.8461 - val_loss: 0.2575 - val_accuracy: 0.8920
Epoch 2/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2886 - accuracy: 0.8752 - val_loss: 0.2365 - val_accuracy: 0.8992
Epoch 3/12
5000/5000 [==============================] - 89s 18ms/step - loss: 0.2625 - accuracy: 0.8877 - val_loss: 0.2296 - val_accuracy: 0.9016
Epoch 4/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2415 - accuracy: 0.8970 - val_loss: 0.2215 - val_accuracy: 0.9076
Epoch 5/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2358 - accuracy: 0.9004 - val_loss: 0.2331 - val_accuracy: 0.8982
Epoch 6/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2195 - accuracy: 0.9074 - val_loss: 0.2387 - val_accuracy: 0.9002
Epoch 7/12
5000/5000 [==============================] - 89s 18ms/step - loss: 0.2106 - accuracy: 0.9096 - val_loss: 0.2237 - val_accuracy: 0.9094
Epoch 8/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2028 - accuracy: 0.9155 - val_loss: 0.2173 - val_accuracy: 0.9126
Epoch 9/12
5000/5000 [==============================] - 95s 19ms/step - loss: 0.1908 - accuracy: 0.9204 - val_loss: 0.2285 - val_accuracy: 0.9076
Epoch 10/12
5000/5000 [==============================] - 94s 19ms/step - loss: 0.1821 - accuracy: 0.9247 - val_loss: 0.2242 - val_accuracy: 0.9112
Epoch 11/12
5000/5000 [==============================] - 94s 19ms/step - loss: 0.1740 - accuracy: 0.9278 - val_loss: 0.2364 - val_accuracy: 0.9044
Epoch 12/12
5000/5000 [==============================] - 94s 19ms/step - loss: 0.1644 - accuracy: 0.9322 - val_loss: 0.2335 - val_accuracy: 0.9106

标签:loss,None,val,df,VGG,train,CNN,识别,accuracy
From: https://www.cnblogs.com/d42z/p/16779785.html

相关文章

  • pytorch-实现天气识别
    一前期工作 环境:python3.6,1080ti,pytorch1.10(实验室服务器的环境......
  • 【自然语言处理(NLP)】基于LSTM的命名实体识别(进阶)
    【自然语言处理(NLP)】基于LSTM的命名实体识别(进阶)作者简介:在校大学生一枚,华为云享专家,阿里云专家博主,腾云先锋(TDP)成员,云曦智划项目总负责人,全国高等学校计算机教学与产......
  • 车牌识别(2)-搭建车牌识别模型
    上一期分享了模拟生成车牌的方法,今天分享一下搭建要给简单的车牌识别模型,模拟生成车牌的方法参看:​​车牌识别(1)-车牌数据集生成​​生成的车牌如下图准备数据集,图片放在path......
  • 基于Ernie-3.0 CAIL2019法研杯要素识别多标签分类任务
    相关项目:​​Paddlenlp之UIE模型实战实体抽取任务【打车数据、快递单】​​​​Paddlenlp之UIE分类模型【以情感倾向分析新闻分类为例】含智能标注方案)​​​​应用实践:分类......
  • 基于AIE的贵阳市两湖一库水体区域识别
    贵阳市两湖一库水体区域识别通过计算归一化水体指数NDWI指数提取贵阳市水体区域。初始化环境importaieaie.Authenticate()aie.Initialize()Landsat-8数据检索......
  • Class1 语音识别概述
    title:Class1语音识别综述excerpt:hands-freetags:[语音识别,ASR]categories:[学习,语音识别]index_img:https://picture-store-repository.oss-cn-hangzhou......
  • Class5 基于GMM-HMM的语音识别系统
    title:Class5基于GMM-HMM的语音识别系统excerpt:hands-freetags:[语音识别,ASR,HMM,Viterbi,孤立词,单音素,三音素,决策树,状态绑定]categories:[学习,......
  • Class 3 电子相册搭建(人脸、表情识别)
    title:Class3电子相册搭建(人脸、表情识别)excerpt:达摩院特别版-视觉AI训练营tags:[阿里云,达摩院,AI,应用,视觉,图像识别,人脸识别,表情识别,自动标,......
  • IoT智能终端识别技术
    IoT智能终端识别技术1.SIM卡(SubscriberIdentityModule,用户识别模块))SIM卡是GSM系统的移动用户所持有的IC卡,称为用户识别卡,主要用于识别用户。GSM系统通过SIM卡来识别G......
  • 基于LSTM网络的视觉识别研究与实现——简化版
    1.问题描述:        以人脸图像的视觉识别为研究对象,研究了基于LSTM长短期记忆单元网络的视觉识别算法,通过使用卷积神经网络学习人脸图像的特征信息,然后使用LSTM网......