100天搞定機器學習|day40-42 Tensorflow Keras識別貓狗

100天搞定機器學習|1-38天100天搞定機器學習|day39 Tensorflow Keras手寫數字識別git

前文咱們用keras的Sequential 模型實現mnist手寫數字識別,準確率0.9713。今天咱們完成day40-42的課程,實現貓、狗的識別。github

本文數據集下載地址https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_3367a.zip算法

本文須要用到OpenCV和Tqdm。OpenCV是跨平臺計算機視覺庫,能夠實現了圖像處理和計算機視覺方面的不少通用算法。Tqdm是用來顯示進度條的,使用很直觀(在循環體裏邊加個tqdm),基本不影響原程序效率。安裝都很簡單,只須要pip install便可:瀏覽器

image

一、數據預處理

數據集各有12501張貓和狗的圖像,先對這些圖像進行尺寸統一和顏色處理。網絡

導入庫app

import numpy as np
import matplotlib.pyplot as plt
import osimport cv2
from tqdm import tqdm複製代碼

看一張轉換後的圖片dom

DATADIR = "...\\PetImages" # 數據集的路徑,請根據須要修改
CATEGORIES = ["Dog", "Cat"]
for category in CATEGORIES:     
    path = os.path.join(DATADIR,category)  # 建立路徑    
    for img in os.listdir(path):  # 迭代遍歷每一個圖片
        img_array = cv2.imread(os.path.join(path,img) ,cv2.IMREAD_GRAYSCALE)  # 轉化成array
        plt.imshow(img_array, cmap='gray')  # 轉換成圖像展現
        plt.show()  # display!
        break  # 咱們做爲演示只展現一張,因此直接break了    break  #同上複製代碼

機器學習

image

看下array中存儲的圖像數據:學習

print(img_array)複製代碼

[[117 117 119 … 133 132 132][118 117 119 … 135 134 134][119 118 120 … 137 136 136]…[ 79  74  73 …  80  76  73][ 78  72  69 …  72  73  74][ 74  71  70 …  75  73  71]]看下array的形狀:測試

print(img_array.shape)複製代碼

(375, 500)咱們能夠看到這是一張很大的圖片,而且擁有RGB3個通道,這並非咱們想要的,因此接下來咱們將要進行的操做會使圖像變小,而且只剩下灰度:

IMG_SIZE = 50
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
plt.imshow(new_array, cmap='gray')
plt.show()複製代碼

image

SIZE設置成50有一些模糊,嘗試下100:

IMG_SIZE = 100
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
plt.imshow(new_array, cmap='gray')
plt.show()複製代碼

image

接下來,咱們將要建立全部這些培訓數據,可是,首先,咱們應該留出一些圖像進行最終測試。我將手動建立一個名爲Testing的目錄,而後在其中建立2個目錄,一個用於Dog,一個用於Cat。從這裏開始,我將把Dog和Cat的前15張圖像移到訓練版本中。確保移動它們,而不是複製。咱們將使用它進行最終測試。

training_data = []
def create_training_data():
    for category in CATEGORIES: 
         path = os.path.join(DATADIR,category)
          class_num = CATEGORIES.index(category)  # 獲得分類,其中 0=dog 1=cat
        for img in tqdm(os.listdir(path)):
              try: 
               img_array = cv2.imread(os.path.join(path,img) ,cv2.IMREAD_GRAYSCALE) 
                 new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))  # 大小轉換
                training_data.append([new_array, class_num])  # 加入訓練數據中
            except Exception as e:  # 爲了保證輸出是整潔的
                pass            #except OSError as e: 
           #    print("OSErrroBad img most likely", e, os.path.join(path,img)) 
           #except Exception as e: 
           #    print("general exception", e, os.path.join(path,img))create_training_data()print(len(training_data))複製代碼

100%|██████████| 12501/12501 [00:36<00:00, 12501="" 342.82it="" s]100%|██████████|="" [00:39<00:00,="" 320.35it="" s]24946咱們有大約25,000張圖片。咱們要作的一件事是確保咱們的數據是平衡的。在這個數據集的狀況下,我能夠看到數據集開始時是平衡的。平衡,個人意思是每一個班級都有相同數量的例子(相同數量的狗和貓)。若是不平衡,要麼將類權重傳遞給模型,以便它能夠適當地測量偏差,或者經過將較大的集修剪爲與較小集相同的大小來平衡樣本。如今數據集中要麼全是dog要麼全是cat,所以接下來要引入隨機:<="" p="">

import random
random.shuffle(training_data)複製代碼

咱們的training_data是一個列表,這意味着它是可變的,因此它如今很好地改組了。咱們能夠經過迭代幾個初始樣本並打印出類來確認這一點:

for sample in training_data[:10]: 
   print(sample[1])複製代碼

0101101010如今能夠看到已是0、1交替了,咱們能夠開始咱們的模型了:

X = []
y = []
for features,label in training_data:
    X.append(features)
    y.append(label)
print(X[0].reshape(-1, IMG_SIZE, IMG_SIZE, 1))
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)複製代碼

讓咱們保存這些數據,這樣咱們就不須要每次想要使用神經網絡模型時繼續計算它:

import pickle
pickle_out = open("...\\X.pickle","wb")
pickle.dump(X, pickle_out)pickle_out.close()
pickle_out = open("...\\y.pickle","wb")
pickle.dump(y, pickle_out)pickle_out.close()
# We can always load it in to our current script, or a totally new one by doing:
pickle_in = open("...\\X.pickle","rb")
X = pickle.load(pickle_in)
pickle_in = open("...\\y.pickle","rb")
y = pickle.load(pickle_in)複製代碼

如今咱們已經拿出了數據集,咱們已經準備好覆蓋卷積神經網絡,並用咱們的數據進行分類。以上就是此次的關於數據集操做的所有任務。

二、訓練模型

基礎知識基本的CNN結構以下:Convolution(卷積) -> Pooling(池化) -> Convolution -> Pooling -> Fully Connected Layer(全鏈接層) -> Output

Convolution(卷積)是獲取原始數據並從中建立特徵映射的行爲。Pooling(池化)是下采樣,一般以「max-pooling」的形式,咱們選擇一個區域,而後在該區域中取最大值,這將成爲整個區域的新值。Fully Connected Layers(全鏈接層)是典型的神經網絡,其中全部節點都「徹底鏈接」。卷積層不像傳統的神經網絡那樣徹底鏈接。

卷積:咱們將採用某個窗口,並在該窗口中查找要素,該窗口的功能如今只是新功能圖中的一個像素大小的功能,但實際上咱們將有多層功能圖。接下來,咱們將該窗口滑過並繼續該過程,繼續此過程,直到覆蓋整個圖像。

池化:最多見的池化形式是「最大池化」,其中咱們簡單地獲取窗口中的最大值,而且該值成爲該區域的新值。

全鏈接層:每一個卷積和池化步驟都是隱藏層。在此以後,咱們有一個徹底鏈接的層,而後是輸出層。徹底鏈接的層是典型的神經網絡(多層感知器)類型的層,與輸出層相同。

注意本次代碼中所需的X.pickle和y.pickle爲上一篇的輸出,路徑請根據本身的狀況更改!

此篇中文爲譯者根據原文整理獲得,可能有不當之處,能夠點擊此處查看原文。

import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D

import pickle

pickle_in = open("../datasets/X.pickle","rb")
X = pickle.load(pickle_in)

pickle_in = open("../datasets/y.pickle","rb")
y = pickle.load(pickle_in)

X = X/255.0

model = Sequential()

model.add(Conv2D(256, (3, 3), input_shape=X.shape[1:]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(256, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors

model.add(Dense(64))

model.add(Dense(1))
model.add(Activation('sigmoid'))

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

model.fit(X, y, batch_size=32, epochs=3, validation_split=0.3)複製代碼

Train on 17462 samples, validate on 7484 samplesEpoch 1/3step - loss: 0.6728 - acc: 0.6019 - valloss: 0.6317 - valacc: 0.6463Epoch 2/3step - loss: 0.6164 - acc: 0.6673 - valloss: 0.6117 - valacc: 0.6776Epoch 3/3step - loss: 0.5690 - acc: 0.7129 - valloss: 0.5860 - valacc: 0.6963

在僅僅三個epoches以後,咱們的驗證準確率爲71%。若是咱們繼續進行更多的epoches,咱們可能會作得更好,但咱們應該討論咱們如何知道咱們如何作。爲了解決這個問題,咱們可使用TensorFlow附帶的TensorBoard,它能夠幫助在訓練模型時可視化模型。

三、模型調參

在這一部分,咱們將討論的是TensorBoard。TensorBoard是一個方便的應用程序,容許在瀏覽器中查看模型或模型的各個方面。咱們將TensorBoard與Keras一塊兒使用的方式是經過Keras回調。實際上有不少Keras回調,你能夠本身製做。

from tensorflow.keras.callbacks import TensorBoard
#建立TensorBoard回調對象
NAME = "Cats-vs-dogs-CNN"

tensorboard = TensorBoard(log_dir="logs/{}".format(NAME))複製代碼

最終,你會但願得到更多的自定義NAME,但如今這樣作。所以,這將保存模型的訓練數據logs/NAME,而後由TensorBoard讀取。

最後,咱們能夠經過將它添加到.fit方法中來將此回調添加到咱們的模型中,例如:

model.fit(X, y,
          batch_size=32,
          epochs=3,
          validation_split=0.3,
          callbacks=[tensorboard])複製代碼

請注意,這callbacks是一個列表。也能夠將其餘回調傳遞到此列表中。咱們的模型尚未定義,因此如今讓咱們把它們放在一塊兒:

import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import TensorBoard
# more info on callbakcs: https://keras.io/callbacks/ model saver is cool too.
import pickle
import time

NAME = "Cats-vs-dogs-CNN"

pickle_in = open("../datasets/X.pickle","rb")
X = pickle.load(pickle_in)

pickle_in = open("../datasets/y.pickle","rb")
y = pickle.load(pickle_in)

X = X/255.0

model = Sequential()

model.add(Conv2D(256, (3, 3), input_shape=X.shape[1:]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(256, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(64))

model.add(Dense(1))
model.add(Activation('sigmoid'))

tensorboard = TensorBoard(log_dir="logs/{}".format(NAME))

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

model.fit(X, y,
          batch_size=32,
          epochs=3,
          validation_split=0.3,
          callbacks=[tensorboard])複製代碼

Train on 17462 samples, validate on 7484 samplesEpoch 1/3step - loss: 0.6992 - acc: 0.5480 - valloss: 0.6900 - valacc: 0.5274Epoch 2/3step - loss: 0.6754 - acc: 0.5782 - valloss: 0.6685 - valacc: 0.5885Epoch 3/3step - loss: 0.6377 - acc: 0.6483 - valloss: 0.6217 - valacc: 0.6625運行此以後,應該有一個名爲的新目錄logs。咱們如今可使用tensorboard從這個目錄中可視化初始結果。打開控制檯,切換到工做目錄,而後鍵入:tensorboard --logdir=logs/。應該看到一個通知:TensorBoard 1.10.0 at http://H-PC:6006 (Press CTRL+C to quit)「h-pc」是機器的名稱。打開瀏覽器並前往此地址。你應該看到相似的東西:

image

如今咱們能夠看到咱們的模型隨着時間的推移。讓咱們改變模型中的一些東西。首先,咱們從未在密集層中添加激活。另外,讓咱們嘗試總體較小的模型:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import TensorBoard
# more info on callbakcs: https://keras.io/callbacks/ model saver is cool too.
import pickle
import time

NAME = "Cats-vs-dogs-64x2-CNN"

pickle_in = open("../datasets/X.pickle","rb")
X = pickle.load(pickle_in)

pickle_in = open("../datasets/y.pickle","rb")
y = pickle.load(pickle_in)

X = X/255.0

model = Sequential()

model.add(Conv2D(64, (3, 3), input_shape=X.shape[1:]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())  # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(64))
model.add(Activation('relu'))

model.add(Dense(1))
model.add(Activation('sigmoid'))

tensorboard = TensorBoard(log_dir="logs/{}".format(NAME))

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

model.fit(X, y,
          batch_size=32,
          epochs=10,
          validation_split=0.3,
          callbacks=[tensorboard])複製代碼

除此以外,我還更名爲NAME = "Cats-vs-dogs-64x2-CNN"。不要忘記這樣作,不然你會偶然附加到你之前的型號的日誌,它看起來不太好。咱們如今檢查TensorBoard:

image

看起來更好!可是,可能會當即注意到驗證丟失的形狀。損失是衡量錯誤的標準,看起來很明顯,在咱們的第四個時代以後,事情開始變得糟糕。

有趣的是,咱們的驗證準確性仍然持續,但我想它最終會開始降低。更可能的是,第一件遭受的事情確實是你的驗證損失。這應該提醒你,你幾乎確定會開始過分適應。這種狀況發生的緣由是該模型不斷嘗試減小樣本損失。

在某些時候,模型不是學習關於實際數據的通常事物,而是開始只記憶輸入數據。若是你繼續這樣作,是的,樣本中的「準確性」會上升,但你的樣本,以及你試圖爲模型提供的任何新數據可能會表現得不好。

參考

https://github.com/MLEveryday/100-Days-Of-ML-Code/blob/master/Code/Day%2040.ipynb

https://github.com/MLEveryday/100-Days-Of-ML-Code/blob/master/Code/Day%2041.ipynb

https://github.com/MLEveryday/100-Days-Of-ML-Code/blob/master/Code/Day%2042.ipynb

相關文章
相關標籤/搜索