天天看點

第五章 深度學習用于計算機視覺(二)

5.2 在小型資料集上從頭開始訓練一個卷積神經網絡

  • 資料集是Kaggle中的dogs_vs_cats是一個典型的圖像分類問題
  • 可能需要使用GPU,GPU如果沒有可以使用Google Colab中的免費GPU。

        Kaggle中的這個資料集中一共有25000張圖檔,其中貓狗各有12500張。資料集中已經分好了測試資料和訓練資料。當然現在機器學習算法發展迅速,我們可以僅僅使用4000張貓狗的圖檔(2000張貓,2000張狗)使得訓練結果就非常好。我們将2000張圖像用于訓練,1000張用于驗證,1000張用于測試。(當然資料集越大訓練結果越好,但是這裡研究的是小資料集,因為後面還會介紹資料增強等内容,是以小資料集再合适不過了)

        首先要進行資料的下載下傳工作,直接從kaggle下載下傳就可以了https://www.kaggle.com/c/dogs-vs-cats/data。

第五章 深度學習用于計算機視覺(二)

        檔案夾中已經分好了測試集和訓練集。kaggle賬号注冊很簡單,但是要下載下傳資料集需要驗證你的手機号,這一步有時候并不太容易做到。那麼就去網上找找吧,應該很容易找到,CSDN也有。

第五章 深度學習用于計算機視覺(二)
第五章 深度學習用于計算機視覺(二)

        這是資料集中的内容,将檔案解壓到你電腦的相應位址就可以在jupyter notebook上進行學習了。但是jupyter notebook使用的是本地的CPU(如果你沒有GPU的話,有就當我沒說),訓練速度比較慢。

要使用Google Colab首先要挂載Google Drive ,操作方法可以參考這個博文https://blog.csdn.net/qq_43028656/article/details/119849938。

        我們要使用4000張圖檔,下面進行資料的整理:

import os,shutil

original_dataset_dir = 'D:/ALL_code\Anaconda/Deep_Learning_Study/chapter5/kaggle_original_data/train' #設定原始資料的路徑

base_dir = 'D:/ALL_code/Anaconda/Deep_Learning_Study/chapter5/kaggle_original_data/cats_and_dogs_small'
os.mkdir(base_dir) #由于隻使用資料中的一部分 兩千張cat兩千張dog,是以在檔案夾中建立一個較小的檔案集合用以存放部分資料

train_dir = os.path.join(base_dir, 'train')
#将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)
train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir)
#在train檔案夾裡建立cats和dogs的檔案夾,存儲用于訓練的圖檔

validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir)
validation_dogs_dir = os.path.join(validation_dir, 'dogs')
os.mkdir(validation_dogs_dir)
#在validation檔案夾裡建立兩個檔案夾,cats和dogs,存儲用于驗證的圖檔

test_cats_dir = os.path.join(test_dir, 'cats')
os.mkdir(test_cats_dir)
test_dogs_dir = os.path.join(test_dir, 'dogs')
os.mkdir(test_dogs_dir)
#在test中建立兩個檔案夾,用于存取測試用的圖檔

fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(train_cats_dir, fname)
    shutil.copyfile(src, dst)
#将前1000張貓的圖檔複制到train_cats_dir

fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_cats_dir, fname)
    shutil.copyfile(src, dst)
# 将接下來500張貓的圖像複制到validation_cats_dir

fnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_cats_dir, fname)
    shutil.copyfile(src, dst)
# 将接下來500張貓的圖像複制到test_cats_dir

fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(train_dogs_dir, fname)
    shutil.copyfile(src, dst)
#将前1000張狗的圖檔複制到train_dogs_dir

fnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_dogs_dir, fname)
    shutil.copyfile(src, dst)
# 将接下來500張狗的圖像複制到validation_dogs_dir

fnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_dogs_dir, fname)
    shutil.copyfile(src, dst)
# 将接下來500張狗的圖像複制到test_dogs_dir
# 自己的硬碟大概運作45s
           
第五章 深度學習用于計算機視覺(二)

 完成後将會看到檔案夾裡面的内容是這樣的,每個檔案夾裡都有cat和dog檔案夾,裡面分别存放着貓和狗的圖檔。到這裡我們需要用到的資料就整理好了。

 接下來是模型建構和配置,資料預處理以及訓練:

from keras import layers 
from keras import models

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(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

#第一個conv2d要進行參數計算是896 896=(9*3+1)*32 9是(3,3)的濾鏡資料量,原市資料(150, 150, 3)通道數為3 是以要9*3 +1是截距項
#一共有32層 是以×32

#配置用于訓練的模型
from keras import optimizers
model.compile(loss='binary_crossentropy', 
              optimizer=optimizers.RMSprop(lr=1e-4),
             metrics=['acc'])
           

資料預處理

将資料輸入神經網絡之前,應該将資料格式化為胫骨哦預處理的浮點數張量

步驟如下:

  • 讀取圖像檔案
  • 将JPEG檔案解碼為RGB像素網格
  • 将這些像素網格轉換為浮點數張量
  • 将像素值(0~255範圍内)縮放到[0,1]區間

keras擁有自動完成這些步驟的工具

圖像輔助子產品: keras.preprocessing.image包含ImageDataGenerator類,可以快速建立python生成器

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale=1./255)
test_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 = test_datagen.flow_from_directory(
    validation_dir, 
    target_size=(150, 150),
    batch_size=20, 
    class_mode='binary')
           

 運作後有如下輸出,說明我們需要使用的資料已經預處理完成

Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
           
#使用批量生成器拟合模型
history = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
validation_steps=50)

model.save('cats_and_dogs_small_1.h5')#儲存模型
           

        這個過程在我自己的CPU上跑一個epoch大概需要55s,在雲端的GPU上跑一個epoch隻需要13s, 但是第一個epoch比較慢(我跑了1305s)具體原因我也沒有找到,但是整體來說還是GPU跑得快。

#繪制損失曲線和精度曲線
import matplotlib.pyplot as plt
acc =  history.history['acc']
val_acc =  history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title("Training and Validation accuracy")
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss,'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()
           

 繪制結果如下:

第五章 深度學習用于計算機視覺(二)
第五章 深度學習用于計算機視覺(二)

        從這些圖像可以看出過拟合的特征,訓練精度随着時間線性增加,直到接近100%,而驗證精度則一直停留在70%~72%。驗證損失在第5輪以後就達到了最小值,然後保持不變,而訓練損失則一直線性下降直到0。深度學習處理圖像時的幾乎都會使用到資料增強來解決過拟合。

資料增強 ( data augmentation)

  • 計算機視覺領域經常使用的處理過拟合的方法
  • 實作:利用多種能夠生成可信圖像的随機變換來增加樣本
  • keras中使用ImageDataGenerator執行個體讀取的圖像執行多次随機變換來實作
original_dataset_dir = 'D:/ALL_code/Anaconda/Deep_Learning_Study/chapter5/kaggle_original_data' 

base_dir = 'D:/ALL_code/Anaconda/Deep_Learning_Study/chapter5/kaggle_original_data/cats_and_dogs_small'
# os.mkdir(base_dir) 
train_dir = 'D:/ALL_code/Anaconda/Deep_Learning_Study/chapter5/kaggle_original_data/cats_and_dogs_small/train'
validation_dir = 'D:/ALL_code/Anaconda/Deep_Learning_Study/chapter5/kaggle_original_data/cats_and_dogs_small/validation'
test_dir = 'D:/ALL_code/Anaconda/Deep_Learning_Study/chapter5/kaggle_original_data/cats_and_dogs_small/test'

from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
    rotation_range=40, #角度值,表示圖像随機旋轉的角度範圍
    width_shift_range=0.2, #水準方向平移的範圍
    height_shift_range=0.2,
    shear_range=0.2, # 随機錯切變換的角度
    zoom_range=0.2, # 随機縮放的範圍
    horizontal_flip=True, # 随機将一半圖像水準翻轉
    )# 用于填充新建立像素的方法
           

        使用了資料增強以後還不能完全消除過拟合,由于資料來自于少量的原市圖像,是以網絡看到的輸入仍然是高度相關的。為了進一步降低過拟合,向模型中添加一個Dropout層,添加到密集連接配接分類器之前。

#定義一個包含dropout的新卷積神經網絡
from keras import layers 
from keras import models
from keras import optimizers

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.Dropout(0.5))
model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(loss='binary_crossentropy',
             optimizer=optimizers.RMSprop(lr=1e-4),
             metrics=['acc'])
           

 訓練模型:

#使用資料增強生成器訓練卷積神經網絡
train_datagen = ImageDataGenerator(
    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, )

test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
    train_dir, 
    target_size=(150, 150),
    batch_size=32, 
    class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
    validation_dir, 
    target_size=(150, 150),
    batch_size=32, 
    class_mode='binary')

history = model.fit_generator(
    train_generator,
    steps_per_epoch=100,
    epochs=100,
    validation_data=validation_generator,
    validation_steps=50)

model.save('cats_and_dogs_small_2.h5')
           

        這一過程在CPU上面一個epoch要持續90s左右,100個epoch跑了兩個半小時,在GPU上隻跑了半個小時。注意:發現一個問題,在GPU上跑的時候設定batch_size=32,會報錯,說訓練的範圍查過了資料的範圍,由于隻有2000個訓練資料,設定32個epoch會超出2000的範圍,是以我訓練的時候将32改回了原來的20。奇怪的是在本地CPU上跑的時候并沒有報這個錯誤,查資料也沒查出個是以然。。。

#繪制損失曲線和精度曲線
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title("Training and Validation accuracy")
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss,'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()
           

 繪制結果如下:

第五章 深度學習用于計算機視覺(二)
第五章 深度學習用于計算機視覺(二)

 現在得到的精度達到了84%左右,比未正則的模型提高了15%(相對比例),通過進一步的正則以及調節網絡參數可以使結果更好,接下來的内容會繼續講述。

繼續閱讀