卷积神经网络增强数据

本文介绍了如何使用Python和Keras库在TensorFlow环境下构建一个卷积神经网络(CNN),对猫狗图像进行二分类。包括数据预处理、模型结构设计、训练与验证过程以及调整模型参数以提高性能。最终保存模型以供测试和后续使用。
摘要由CSDN通过智能技术生成

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import scipy
import keras
# 设置GPU设备
gpus = tf.config.experimental.list_physical_devices('GPU')
try:
    if gpus:
        tf.config.experimental.set_visible_devices(gpus[0], 'GPU')
        tf.config.experimental.set_memory_growth(gpus[0], True)
        print("GPU set successfully!")
except Exception as e:
    print(e)
import os,shutil
# basedir是我要建的文件夹根目录,下面要有train,test,yz三个文件夹
#train,test,yz文件夹下有cats,dogs文件夹,cats,dogs装猫狗图片
basedir='E:\jupyter_rgzn\datasets\cats_dogs_s'
#这个是下载的猫狗图片,很多张,我们要取的是train,2000,1000张猫,1000张狗
#,yz,1000,test,1000
src='E:\\jupyter_rgzn\\深度学习\\cat_dog\\train'
# 创建文件夹
def make_dirs(f_dir,c_dir):
    path_=os.path.join(f_dir,c_dir)
    os.makedirs(path_)
train_dir=os.path.join(basedir,'train')
test_dir=os.path.join(basedir,'test')
yz_dir=os.path.join(basedir,'yz')
#E:\\jupyter_rgzn\\datasets\\cats_dogs_s\\train\\cats
train_cats_dir=os.path.join(basedir+'\\train','cats')
test_cats_dir=os.path.join(basedir+'\\test','cats')
yz_cats_dir=os.path.join(basedir+'\\yz','cats')
train_dogs_dir=os.path.join(basedir+'\\train','dogs')
test_dogs_dir=os.path.join(basedir+'\\test','dogs')
yz_dogs_dir=os.path.join(basedir+'\\yz','dogs')
#复制文件
def copy_file(src,dst,names):
    for name in names:
        src_=os.path.join(src,name)
        dst_=os.path.join(dst,name)
        shutil.copyfile(src_,dst_)
from keras import layers
from keras import models
model=models.Sequential()
#过滤层,抓取一些简单的图形,3x3的卷积核扫描,会少两行两列,所以过滤后
#size-2,补padding的话要补一圈0,一圈0就包含两行两列,是在扫描前补0
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
#抓大放小,2x2的扫描器,只抓取区域内的最大值,2x2变成1x1,而且步长是2,扫描区域不重复
#所以最后图片变成之前一半,学名,池化层
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)))
# 这个flatten是把高维弄成一维,其实很简单,循环遍历,
# 之后把每个元素都装进一个-维的ndarray
model.add(layers.Flatten())
# 密集连接层
model.add(layers.Dense(512,activation='relu'))
# 二分类问题,sigmoid,输出层
model.add(layers.Dense(1,activation='sigmoid'))
# 要估计的参数
#(3*3*3+1)*32,(3*3*32+1)*64,(3*3*64+1)*128,
#(3*3*128+1)*128,flatten:7*7*128
#(6272+1)*512,(512+1)*1
model.summary()
from keras import optimizers
# 优化器,损失函数,指标
model.compile(optimizer=optimizers.RMSprop(learning_rate=1e-4),\
                           loss='binary_crossentropy',metrics=['accuracy'])
# 图片转化为数据
from keras.preprocessing.image import ImageDataGenerator

# rescale,缩放因子,将图片(ndarray)中每个数字*rescale的值
train_gen=ImageDataGenerator(rescale=1./255)
vald_gen=ImageDataGenerator(rescale=1./255)
#生成器,训练数据里既有猫,又有狗,而且被自动设置了标签,二分类
train_generator=train_gen.flow_from_directory(
    train_dir,#目标图片文件夹,这个文件夹内有几个,就被归结为几类
    target_size=(150,150),#要设置的图片大小,对应model接收
    batch_size=20,#每个批次
    class_mode='binary'#二分类
)
vald_generator=vald_gen.flow_from_directory(
    yz_dir,
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)
import keras as ks
import scipy
cnt=0
# batch_size=20是之前设置的
#data_batch是小批次的20个样本图片,labels_batch是对应的是猫还是狗的标签
for data_batch,labels_batch in train_generator:
    print(type(data_batch),type(labels_batch),data_batch.shape,labels_batch.shape)
    print('labels:',labels_batch)
    plt.imshow(data_batch[-1])
    if cnt>3:
        break
    cnt+=1
print(cnt)
his=model.fit_generator(train_generator,  
    epochs=30,  # 训练轮数  
    verbose=2,  # 日志显示模式  
    steps_per_epoch=len(train_generator),  # 每个epoch需要完成的步数,通常设置为训练集的总样本数除以批次大小  
    validation_data=vald_generator,  # 如果有验证集的话,这里也应该是另一个DirectoryIterator实例  
    validation_steps=len(vald_generator),  # 验证集的步数 
    shuffle=True
)
 len(vald_generator),验证loss在第9次epoch最小
np.argmin(his.history['val_loss'])
xl_loss=his.history['loss']
yz_loss=his.history['val_loss']
xl_acc=his.history['accuracy']
yz_acc=his.history['val_accuracy']
plt.rcParams['font.size'] = 22
plt.figure(figsize=(20,9),dpi=100)
plt.subplot((121))
x=range(1,len(xl_loss)+1)
plt.plot(x,xl_loss,'b',label='xl_loss')
plt.plot(x,yz_loss,'bo',label='yz_loss')
plt.legend()
plt.subplot((122))
plt.plot(x,xl_acc,'r',label='xl_acc')
plt.plot(x,yz_acc,'ro',label='yz_acc')
plt.legend()
plt.show()
#得到训练文件夹下的所有猫图片的路径,listdir是顺序打乱的
train_cats_path=[os.path.join(train_cats_dir,name) for name in os.listdir(train_cats_dir)]
from keras.preprocessing import image  
import numpy as np  
from PIL import Image  
im_path=train_cats_path[8]#获得索引8的那个图片

# 把图片加载进来,变成4个维度的张量
img=Image.open(im_path)
img=img.resize((150,150))
x=image.image_utils.img_to_array(img)
x=x.reshape((1,)+x.shape)# 前面增加个维度,是样本数
x.shape
#改变图片的方式
data_gen=ImageDataGenerator(
    rotation_range=40,#旋转角度
    width_shift_range=0.2,#水平平移
    height_shift_range=0.2,#上下平移,高度乘以0.2当成我们平移的距离
    shear_range=0.2,#拉的斜一些
    zoom_range=0.2,#变大变小
    horizontal_flip=True,#有些图片会被随机的翻转过来
    fill_mode='nearest'#用临近的像素填充被移出的区域
)
查看data_gen作用在图片上的效果,图片发生了一些平移之类的变化
i=0
for batch in data_gen.flow(x,batch_size=1):
    # 如果已经存在具有该标识符的图形,那么这个图形会被设为当前活动图形并返回。
    plt.figure(i)
    plt.imshow(image.image_utils.array_to_img(batch[0]))
    i+=1
    if i%4==0:
        break
plt.show()
from keras import optimizers
model=models.Sequential()
#过滤层,抓取一些简单的图形,3x3的卷积核扫描,会少两行两列,所以过滤后
#size-2,补padding的话要补一圈0,一圈0就包含两行两列,是在扫描前补0
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
#抓大放小,2x2的扫描器,只抓取区域内的最大值,2x2变成1x1,而且步长是2,扫描区域不重复
#所以最后图片变成之前一半,学名,池化层
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)))
# 这个flatten是把高维弄成一维,其实很简单,循环遍历,
# 之后把每个元素都装进一个-维的ndarray
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))#加了一个dropout层
#输出层
model.add(layers.Dense(512,activation='relu'))
# 二分类问题,sigmoid
model.add(layers.Dense(1,activation='sigmoid'))
model.summary()
model.compile(optimizer=optimizers.RMSprop(learning_rate=1e-4),loss='binary_crossentropy',metrics=['acc'])
from keras.preprocessing.image import ImageDataGenerator
#因为训练准确率高,所以给训练增加难度,又是旋转
#又是平移,让电脑能抓住本质
train_datagen=ImageDataGenerator(
        #图片数据*rescale设定值
        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
)
#验证资料就不要旋转平移
yz_datagen=ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_directory(
    train_dir,
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)
vald_generator=yz_datagen.flow_from_directory(
    yz_dir,
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)
his_=model.fit(train_generator,  
    epochs=80,  # 训练轮数  
    verbose=2,  # 日志显示模式  
    steps_per_epoch=100,  # 每个epoch需要完成的步数,通常设置为训练集的总样本数除以批次大小  
    validation_data=vald_generator,  # 如果有验证集的话,这里也应该是另一个DirectoryIterator实例  
    validation_steps=50,  # 验证集的步数 
    shuffle=True
)
np.argmin(his_.history['val_loss'])# 第80次迭代验证loss最小,还没出现overfiting
xl_loss=his_.history['loss']
yz_loss=his_.history['val_loss']
xl_acc=his_.history['acc']
yz_acc=his_.history['val_acc']
plt.rcParams['font.size'] = 22
plt.figure(figsize=(20,9),dpi=100)
plt.subplot((121))
x=range(1,len(xl_loss)+1)
plt.plot(x,xl_loss,'b',label='xl_loss')
plt.plot(x,yz_loss,'g',label='yz_loss')
plt.legend()
plt.subplot((122))
plt.plot(x,xl_acc,'r',label='xl_acc')
plt.plot(x,yz_acc,'b',label='yz_acc')
plt.legend()
plt.show()
test_datagen=ImageDataGenerator(rescale=1./255)
test_generator=test_datagen.flow_from_directory(
    test_dir,
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)
loss_,acc_=model.evaluate(test_generator)
model.save('../data/cats_and_dogs_small2.h5')

  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值