zoukankan      html  css  js  c++  java
  • Tensorflow实现图像数据增强(Data Augmentation)

    在我们处理有关图像的任务,比如目标检测,分类,语义分割等等问题当中,我们常常需要对训练集当中的图片进行数据增强(data augmentation),这样会让训练集的样本增多,同时让神经网络模型的泛化能力更强。在进行图片的数据增强时,我们一般会对图像进行翻转,剪裁,灰度变化,对比度变化,颜色变化等等方式生成新的训练集,这就是计算机视觉当中的数据增强。我们来看看使用图像增强的手段,对一个猫狗图像分类的具体问题是怎么处理的。

    首先我们导入各种包,像tensorflow之类的就不说了,其中的一个包叫做glob,这个包主要是用于读取本地计算机上的图片数据所用的,使用起来十分方便,只需几行代码即可将图片数据读入进来,比pathlib包读取图片方便多了,代码如下所示:

    import tensorflow as tf
    from tensorflow import keras
    import matplotlib.pyplot as plt
    import numpy as np
    import glob
    import os

    然后读取图片,我把我的猫狗图片数据都放在了train文件夹下,这个文件夹下又有两个文件夹,分别是dog和cat,在调用glob库写图片路径的同时,我们直接用“*”号来表示一个文件夹下的所有文件都读取,代码如下所示:

    #首先获取图片,glob这个库明显感觉更加好用
    train_image_path=glob.glob('F://UNIVERSITY STUDY/AI/dataset/catdog/train/*/*.jpg')
    #加上*号是为了将当前目录下的所有文件,再加上一个星号是为了提取当前目录下的所有jpg文件
    train_image_label=[int(p.split("\")[1]=='cat') for p in train_image_path ]
    #经过一个列表推倒式就可以得到所有label

    后面的第二行代码是一个列表推导式,我们观察图片数据集的名称可以发现每一张图片名称上面都有cat或者dog。这样我们就可以直接切分名称上的dog和cat,然后进行索引用split切片出来的第二个字符串,这个字符串正好表示了图片是猫还是狗,运用如上所示的列表推导式的话,如果图片为cat那么标签就为1,如果为dog标签就为0。下面我们来看看数据集当中的名称是长啥样的:

     从中观察可得,名称都是用句号进行分割,图片的格式为jpg。

    我们现在已经得到了所有图片的路径,以及标签了,现在就来到了最激动人心的部分,图片的数据增强啦!!!

    我们编写一个专门用于图片的预处理,包括用作图片数据增强的函数:load_preprosess_image()。在这个函数当中我们对图片进行预处理,之后再进行调用即可。这个函数的代码如下:

    #现在我们的jpg文件进行解码,变成三维矩阵
    def load_preprosess_image(path,label):
        #读取路径
        image=tf.io.read_file(path)
        #解码
        image=tf.image.decode_jpeg(image,channels=3)#彩色图像为3个channel
        #将图像改变为同样的大小,利用裁剪或者扭曲,这里应用了扭曲
        image=tf.image.resize(image,[360,360])
        #随机裁剪图像
        image=tf.image.random_crop(image,[256,256,3])
        #随机上下翻转图像
        image=tf.image.random_flip_left_right(image)
        #随机上下翻转
        image=tf.image.random_flip_up_down(image)
        #随机改变图像的亮度
        image=tf.image.random_brightness(image,0.5)
        #随机改变对比度
        image=tf.image.random_contrast(image,0,1)
        #改变数据类型
        image=tf.cast(image,tf.float32)
        #将图像进行归一化
        image=image/255
        #现在还需要对label进行处理,我们现在是列表[1,2,3],
        #需要变成[[1].[2].[3]]
        label=tf.reshape(label,[1])
        return image,label

    注释我相信已经写得很详细了,里面首先对数据集里后缀为jpg格式的图片进行解码,将jpg格式转化为一个个三维的矩阵,之后将图片进行resize,resize之后进行剪裁为256*256,因为我之后要搭建的神经网络如果图片的size是256*256的话,那么这个网络准确率的表现将会变得更好一些。当然你也可以自己动手设计自己的神经网络,或使用Resnet,VGG16等等卷积神经网络对图片进行分类,这些网络对图片的尺寸都会有一定的要求,因此一定要对我们拿到的图片进行预处理,并不是每一个数据集里的图片的大小是已经大小一致方便训练的。然后我们创建datasets容器用于数据的装载,同时制作每一个batch的数据,代码如下所示:

    #现在开始创建dataset
    train_image_ds=tf.data.Dataset.from_tensor_slices((train_image_path,train_image_label))
    AUTOTUNE=tf.data.experimental.AUTOTUNE#根据计算机性能进行运算速度的调整
    train_image_ds=train_image_ds.map(load_preprosess_image,num_parallel_calls=AUTOTUNE)
    #后面的参数表示处理并行运算的CPU运行数量
    #现在train_image_ds就读取进来了,现在进行乱序和batchsize的规定
    BATCH_SIZE=32
    train_count=len(train_image_path)
    #现在设置batch和乱序
    train_image_ds=train_image_ds.shuffle(train_count).batch(BATCH_SIZE)
    train_image_ds=train_image_ds.prefetch(AUTOTUNE)#预处理一部分处理,准备读取
    imags,labels=iter(train_image_ds).next()#放到生成器里,单独取出数据

    现在搭建神经网络:

    #现在开始创建模型
    model=keras.Sequential([
    tf.keras.layers.Conv2D(64,(3,3),input_shape=(256,256,3),activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(128,(3,3),activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(512,(3,3),activation='relu'),
    tf.keras.layers.GlobalAveragePooling2D(),
    tf.keras.layers.Dense(256,activation='relu'),
    tf.keras.layers.Dense(1)
    ])

    开始自定义训练,如果使用keras式的编程,我们直接model.compile,model.fit模型就训练完了。但是这里为了能够看到训练当中的模型的变化,我们使用自定义训练,这也是Tensotflow2.0版本的优越性,既可以自定义训练也可以使用更加方便的keras方式进行训练,比Pytorch简单了不少。自定义训练的代码如下:

    loss=tf.keras.losses.BinaryCrossentropy()#用这个来计算交叉熵
    #定义优化器
    optimizer=tf.keras.optimizers.Adam()
    epoch_loss_avg=tf.keras.metrics.Mean('train_loss')#定义平均损失
    train_accuracy=tf.keras.metrics.Accuracy()
    
    def train_step(model,image,labels):
        with tf.GradientTape() as t:
            pred=model(image)
            #计算损失,比较标签值和预测值的区别
            loss_step=tf.keras.losses.BinaryCrossentropy(from_logits=True)(labels,pred)
        grads=t.gradient(loss_step,model.trainable_variables)#计算梯度
        optimizer.apply_gradients(zip(grads,model.trainable_variables))#根据梯度进行优化
        epoch_loss_avg(loss_step)
        train_accuracy(labels,tf.cast(pred>0,tf.int32))
    
    train_loss_results=[]
    train_acc_resuls=[]
    
    num_epochs=30
    for epoch in range(num_epochs):
        for imgs_,labels_ in train_image_ds:
            train_step(model,imgs_,labels_)
            print('.',end=' ')#每一个batch就打印一个点
        print()#换行
        #还可以把train——loss拿进来
        train_loss_results.append(epoch_loss_avg.result())
        train_acc_resuls.append(train_accuracy)
        
        print('Epoch :{}.loss: {:.3f},acc:{:.3f}'.format(epoch+1,epoch_loss_avg.result(),train_accuracy.result()))
        
        epoch_loss_avg.reset_states()#重置目前的loss,这样就可以只用到了目前的平均loss
        train_accuracy.reset_states()

    我还没训练完,就给大家看看前面两个epoch的输出吧!

    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
    Epoch :1.loss: 0.695,acc:0.491
    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
    Epoch :2.loss: 0.693,acc:0.500

    这就是tensorflow当中的图像数据增强的使用方法,希望大家能够学到些东西。

  • 相关阅读:
    JQuery 点击子控件事件,不会触发父控件的事件
    JQuery对Style和css设置
    2019vue学习视频(入门到精通)
    新建一个vue项目
    FIS3 构建
    node环境变量
    阿里云重启ssh
    msf 获取session 之后
    acccheck (暴力破解使用SMB协议的Windows密码)
    利用 Cut 指定输出内容
  • 原文地址:https://www.cnblogs.com/geeksongs/p/13322377.html
Copyright © 2011-2022 走看看