Tensorflow實現圖像數據增強(Data Augmentation)


在我們處理有關圖像的任務,比如目標檢測,分類,語義分割等等問題當中,我們常常需要對訓練集當中的圖片進行數據增強(data augmentation),這樣會讓訓練集的樣本增多,同時讓神經網絡模型的泛化能力更強。在進行圖片的數據增強時,我們一般會對圖像進行翻轉,剪裁,灰度變化,對比度變化,顏色變化等等方式生成新的訓練集,這就是計算機視覺當中的數據增強。我們來看看使用圖像增強的手段,對一個貓狗圖像分類的具體問題是怎么處理的。源碼可以在https://github.com/Geeksongs/Computer_Vision/tree/master/Image%20augmentation

進行查看。

首先我們導入各種包,像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當中的圖像數據增強的使用方法,希望大家能夠學到些東西。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM