不懂圖像分類?這四種卷積神經網絡模型瞭解一下!

摘要: 不懂圖像分類?這四種卷積神經網絡模型瞭解一下!

服裝購買是一種繁重的體驗,眼睛被太多的信息佔據了。視覺系統吸取了大量信息,我應該去賣哪件H&M卡其褲嗎?那是Nike背心嗎?git

機器能自動檢測襯衫、褲子、連衣裙和運動鞋的圖片嗎?事實證實,用高質量的訓練數據對機器進行訓練,準確地對時尚物品的圖像進行分類是可行的。在本教程中,咱們將從頭開始構建一個機器學習模型,使用Fashion-MNIST數據集訓練它們。咱們將介紹如何訓練模型、設計類別分類的輸入和輸出,最後顯示每一個模型的準確度結果。github

圖像分類

圖像分類是這樣的:給定一組所有用單一類別標記的圖像,咱們要求爲一組新的測試圖像預測它們究竟是什麼類別?並測量預測的準確性。這項任務涉及各類挑戰,包括視點變化、尺度變化、類內變化、圖像變形、圖像遮擋、光照條件、背景雜波等。正則表達式

咱們如何編寫能夠將圖像分類爲不一樣類別的算法?計算機視覺研究人員已經提出了一種數據驅動方法來解決這個問題。它們不是試圖直接在代碼中指定每一個感興趣的圖像類別,而是爲計算機提供每一個圖像類的許多示例,而後開發學習算法,查看這些示例並瞭解每一個類的視覺外觀。換句話說,他們首先累積標記圖像的訓練數據集,而後將其提供給計算機,以使其熟悉數據。算法

鑑於這一事實,完整的圖像分類管道能夠形式化以下:數據庫

  •  輸入是一個訓練數據集,由N個圖像組成,每一個圖像都標有K不一樣類別中的一個。
  •  而後,咱們使用此訓練集來訓練分類器,以瞭解每一個類的外觀。
  •  最後,咱們經過要求分類器預測從未見過的一組新圖像的標籤來評估分類器的質量。而後,咱們將比較這些圖像的真實標籤與分類器預測的標籤。

卷積神經網絡

卷積神經網絡(CNN)是用於圖像分類問題的最流行的神經網絡模型。CNN背後的一個重要思想是,對圖像的局部理解是好的。實際的好處是,參數少將大大縮短了學習所需的時間,並減小了訓練模型所需的數據量。CNN具備足夠的權重來查看圖像的小塊,而不是來自每一個像素的徹底鏈接的權重網絡。數組

好比一個256 x 256的圖像。CNN能夠經過局部有效地掃描它,例如,用一個5×5的窗口,一般從左到右,從上到下,以下圖所示。它如何「快速」滑動稱爲其步幅。例如,步幅長度2表示5×5滑動窗口一次移動2個像素,直到它跨越整個圖像。網絡

卷積是圖像的像素值的加權和,事實證實,整個帶有權重矩陣的圖像的卷積過程會產生另外一個圖像。架構

滑動窗口發生在神經網絡的卷積層中,典型的CNN具備多個卷積層。每一個卷積層一般產生許多交替卷積,所以權重矩陣是5×5×n的張量,其中n是卷積數。app

例如,假設圖像經過5×5×64的權重矩陣上的卷積層。它經過滑動5×5窗口生成64個卷積。所以,該模型具備5×5×64=1,600個參數,其參數明顯少於徹底鏈接的網絡,256×256= 65,536個。框架

CNN的優勢在於參數的數量與原始圖像的大小無關。你能夠在300×300圖像上運行相同的CNN,但卷積層中的參數數量不會改變。

數據加強(data augmentation)

圖像分類研究數據集一般是很是大的。然而,常用數據加強來改善泛化屬性。一般,使用從新縮放圖像的隨機裁剪以及隨機水平閃爍和隨機RGB顏色和亮度偏移。這其中存在用於從新縮放和裁剪圖像的不一樣方案(即,單一規模與多規模訓練)。請注意,隨機從新縮放和裁剪的目標是學習不一樣尺度和位置的每一個對象的重要特徵,不幸的是Keras沒有實現全部這些開箱即用的數據加強技術,

Fashion MNIST數據集

最近,Zalando發佈了一個新的數據集,它與衆所周知的MNIST手寫數字數據庫很是類似。該數據集專爲機器學習分類任務而設計,包含總共60000個訓練和10000個測試圖像(灰度),每一個28x28像素。每一個訓練和測試用例與十個標籤之一(0-9)相關聯。直到這裏,Zalando的數據集基本上與原始手寫數字數據相同。然而,Zalando的數據不包含數字0-9的圖像,而是包含10種不一樣時尚產品的圖像。所以,數據集稱爲Fashion-MNIST數據集,能夠從GitHub下載。這些數據也能夠在Kaggle上下載。下圖中顯示了一些示例,其中每行包含一個時尚項。

10個不一樣的類別標籤是:

一、T恤/上衣;二、褲子;三、套頭衫;四、連衣裙;五、外套;

六、涼鞋;七、襯衫;八、運動鞋;九、袋;十、靴子;

據做者稱,Fashion-MNIST數據旨在成爲舊MNIST手寫數字數據的直接替代品,由於手寫數字存在若干問題。例如,經過簡單地查看幾個像素,能夠正確地區分幾個數字。即便使用線性分類器,也能夠實現高分類精度。Fashion-MNIST數據有望更加多樣化,所以機器學習(ML)算法必須學習更多高級特徵,以便可以可靠地分離各個類。

時尚MNIST的嵌入可視化(Embedding Visualization)

嵌入是一種將離散對象(圖像,單詞等)映射到高維向量的方法。這些載體中的各個維度一般沒有固有的含義。相反,它是機器學習利用向量之間的位置和距離的總體模式。所以,嵌入對於機器學習的輸入很重要;由於分類器和神經網絡更廣泛地用於實數矢量。它們在密集向量上訓練最好,其中全部值都有助於定義對象。

TensorBoard有一個內置的可視化器,稱爲嵌入式可視化工具(Embedding Projector),用於交互式可視化和分析嵌入等高維數據。嵌入式可視化工具將從個人模型檢查點文件中讀取嵌入,雖然它對嵌入最有用,但它會加載任何2D張量,包括訓練權重。

在這裏,我將嘗試使用TensorBoard表示高維時尚MNIST數據。在讀取數據並建立測試標籤後,我使用此代碼構建TensorBoard的嵌入投影儀:

from tensorflow.contrib.tensorboard.plugins import projector
logdir = 'fashionMNIST-logs'
# Creating the embedding variable with all the images defined above under X_test
embedding_var = tf.Variable(X_test, name='fmnist_embedding')
# Format: tensorflow/contrib/tensorboard/plugins/projector/projector_config.proto
config = projector.ProjectorConfig()
# You can add multiple embeddings. Here I add only one.
embedding = config.embeddings.add()
embedding.tensor_name = embedding_var.name
# Link this tensor to its metadata file (e.g. labels).
embedding.metadata_path = os.path.join(logdir, 'metadata.tsv')
# Use this logdir to create a summary writer
summary_writer = tf.summary.FileWriter(logdir)
# The next line writes a projector_config.pbtxt in the logdir. TensorBoard will read this file during startup.
projector.visualize_embeddings(summary_writer,config)
# Periodically save the model variables in a checkpoint in logdir.
with tf.Session() as sesh:
    sesh.run(tf.global_variables_initializer())
    saver = tf.train.Saver()
    saver.save(sesh, os.path.join(logdir, 'model.ckpt'))  
# Create the sprite image
rows = 28 
cols = 28
label = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

sprite_dim = int(np.sqrt(X_test.shape[0]))
sprite_image = np.ones((cols * sprite_dim, rows * sprite_dim))

index = 0 
labels = [] 
for i in range(sprite_dim): 
    for j in range(sprite_dim):
        labels.append(label[int(Y_test[index])])

        sprite_image[
            i * cols: (i + 1) * cols,
            j * rows: (j + 1) * rows
        ] = X_test[index].reshape(28, 28) * -1 + 1

        index += 1      
# After constructing the sprite, I need to tell the Embedding Projector where to find it
embedding.sprite.image_path = os.path.join(logdir, 'sprite.png')
embedding.sprite.single_image_dim.extend([28, 28])

# Create the metadata (labels) file
with open(embedding.metadata_path, 'w') as meta:
    meta.write('Index\tLabel\n')
    for index, label in enumerate(labels):
        meta.write('{}\t{}\n'.format(index, label))

嵌入可視化工具備三種減小數據集維數的方法:兩個線性和一個非線性。每種方法均可用於建立二維或三維視圖。

主成分分析:主成分分析(PCA)是一種簡單的減少尺寸的技術。嵌入可視化工具備10個主要組件。PCA是一種線性可視化效果,一般可用於檢查全局幾何。

t-SNE:這是一種流行的非線性降維技術是t-SNE。嵌入可視化工具提供二維和三維t-SNE視圖。在客戶端執行局部動畫算法的每一個步驟,由於t-SNE一般保留一些局部結構,因此它對於探索局部鄰域和尋找聚類是有用的。

自定義(custom):咱們還能夠根據文本搜索構建專門的線性可視化,以便在空間中找到有意義的方向。首先定義可視軸,接着輸入兩個搜索字符串或正則表達式。程序計算其標籤與這些搜索匹配的點集的質心,並使用質心之間的差矢量做爲可視軸。

你能夠在此筆記本中查看可視化步驟的完整代碼:TensorBoard-Visualization.ipynb

在時尚MNIST上訓練CNN模型

如今讓咱們轉到有趣的部分:我將建立各類不一樣的基於CNN的分類模型來評估Fashion MNIST的表現。我將使用Keras框架構建咱們的模型,關於它的更多信息,請參閱此處的文檔。如下是我將嘗試的模型列表,並比較它們的結果:

1.具備1個卷積層的CNN;

2.具備3個卷積層的CNN;

3.有4個卷積層的CNN;

4.VGG-19預訓練模型;

對於全部模型(預訓練模型除外),這是我經常使用的方式:

  • 將原始訓練數據(60,000張圖像)分紅80%訓練集(48,000張圖像)和20%驗證集(12000張圖像)優化分類器,同時保留測試數據(10,000張圖像)以最終評估模型對數據的準確性從未見過。這有助於瞭解我是否過分擬合訓練數據,以及若是驗證準確度高於訓練準確度。
  • 訓練模型10個epoch,批量大小爲256,使用categorical_crossentropy損失函數和Adam優化器。
  • 而後,添加數據加強,經過旋轉、移動和縮放訓練樣本生成新的訓練樣本,並在更新的數據上訓練模型另外50個epoch。

這是加載和加強數據的代碼:

# Import libraries
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split
# Load training and test data into dataframes
data_train = pd.read_csv('data/fashion-mnist_train.csv')
data_test = pd.read_csv('data/fashion-mnist_test.csv')
# X forms the training images, and y forms the training labels
X = np.array(data_train.iloc[:, 1:])
y = to_categorical(np.array(data_train.iloc[:, 0]))
# Here I split original training data to sub-training (80%) and validation data (20%)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=13)
# X_test forms the test images, and y_test forms the test labels
X_test = np.array(data_test.iloc[:, 1:])
y_test = to_categorical(np.array(data_test.iloc[:, 0]))

在加載和加強數據以後,我經過將它們從新重構爲網絡所需的形狀並對其進行縮放以使全部值都在[0,1]間隔中來對它們進行預處理。例如,之前,訓練數據存儲在uint8類型的形狀(60000,28,28)的數組中,其值在[0,255]間隔中。我將它轉換爲float32數組形狀(60000,28 * 28),其值介於0和1之間。

# Each image's dimension is 28 x 28
img_rows, img_cols = 28, 28
input_shape = (img_rows, img_cols, 1)
# Prepare the training images
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)
X_train = X_train.astype('float32')
X_train /= 255
# Prepare the test images
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)
X_test = X_test.astype('float32')
X_test /= 255
# Prepare the validation images
X_val = X_val.reshape(X_val.shape[0], img_rows, img_cols, 1)
X_val = X_val.astype('float32')
X_val /= 255

1-1-Conv CNN

如下是具備1個卷積層的CNN的代碼:

from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
cnn1 = Sequential()
cnn1.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
cnn1.add(MaxPooling2D(pool_size=(2, 2)))
cnn1.add(Dropout(0.2))
cnn1.add(Flatten())
cnn1.add(Dense(128, activation='relu'))
cnn1.add(Dense(10, activation='softmax'))
cnn1.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy'])

訓練模型後,這裏是test loss和測試精度:

應用數據加強後,這裏是測試損失和測試準確度:

出於視覺目的,我繪製了訓練和驗證的準確性和損失:

你能夠在此筆記本上查看此型號的完整代碼:CNN-1Conv.ipynb

2-3-Conv CNN

如下是CNN與3卷積層的代碼:

from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
cnn3 = Sequential()
cnn3.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
cnn3.add(MaxPooling2D((2, 2)))
cnn3.add(Dropout(0.25))
cnn3.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
cnn3.add(MaxPooling2D(pool_size=(2, 2)))
cnn3.add(Dropout(0.25))
cnn3.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))
cnn3.add(Dropout(0.4))
cnn3.add(Flatten())
cnn3.add(Dense(128, activation='relu'))
cnn3.add(Dropout(0.3))
cnn3.add(Dense(10, activation='softmax'))
cnn3.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy'])

訓練模型後,這裏是test loss和測試精度:

應用數據加強後,這裏是測試損失和測試準確度:

出於視覺目的,我繪製了訓練和驗證的準確性和損失:

你能夠在此筆記本上查看此型號的完整代碼:CNN-3Conv.ipynb

3-4-Conv CNN

如下是具備4個卷積層的CNN的代碼:

from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, BatchNormalization
cnn4 = Sequential()
cnn4.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
cnn4.add(BatchNormalization())
cnn4.add(Conv2D(32, kernel_size=(3, 3), activation='relu'))
cnn4.add(BatchNormalization())
cnn4.add(MaxPooling2D(pool_size=(2, 2)))
cnn4.add(Dropout(0.25))
cnn4.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
cnn4.add(BatchNormalization())
cnn4.add(Dropout(0.25))
cnn4.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))
cnn4.add(BatchNormalization())
cnn4.add(MaxPooling2D(pool_size=(2, 2)))
cnn4.add(Dropout(0.25))
cnn4.add(Flatten())
cnn4.add(Dense(512, activation='relu'))
cnn4.add(BatchNormalization())
cnn4.add(Dropout(0.5))
cnn4.add(Dense(128, activation='relu'))
cnn4.add(BatchNormalization())
cnn4.add(Dropout(0.5))
cnn4.add(Dense(10, activation='softmax'))
cnn4.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy'])

訓練模型後,這裏是test loss和測試精度:

應用數據加強後,這裏是測試損失和測試準確度:

出於視覺目的,我繪製了訓練和驗證的準確性和損失:

你能夠在此筆記本上查看此型號的完整代碼:CNN-4Conv.ipynb

4–遷移學習

對小圖像數據集進行深度學習的經常使用且高效的方法是使用預先訓練的網絡。一個預先訓練網絡是之前訓練的大型數據集,一般在大型圖像分類任務保存的網絡。若是這個原始數據集足夠大且足夠通用,則預訓練網絡所學習的特徵的空間層次結構能夠有效地充當視覺世界的通用模型,所以其特徵能夠證實對於許多不一樣的計算機視覺問題是有用的。即便這些新問題可能涉及與原始任務徹底不一樣的類。

我試圖實現VGG19預訓練模型,這是ImageNet普遍使用的ConvNets架構。這是你能夠遵循的代碼:

import keras
from keras.applications import VGG19
from keras.applications.vgg19 import preprocess_input
from keras.layers import Dense, Dropout
from keras.models import Model
from keras import models
from keras import layers
from keras import optimizers
# Create the base model of VGG19
vgg19 = VGG19(weights='imagenet', include_top=False, input_shape = (150, 150, 3), classes = 10)
# Preprocessing the input 
X_train = preprocess_input(X_train)
X_val = preprocess_input(X_val)
X_test = preprocess_input(X_test)
# Extracting features
train_features = vgg19.predict(np.array(X_train), batch_size=256, verbose=1)
test_features = vgg19.predict(np.array(X_test), batch_size=256, verbose=1)
val_features = vgg19.predict(np.array(X_val), batch_size=256, verbose=1)
# Flatten extracted features
train_features = np.reshape(train_features, (48000, 4*4*512))
test_features = np.reshape(test_features, (10000, 4*4*512))
val_features = np.reshape(val_features, (12000, 4*4*512))
# Add Dense and Dropout layers on top of VGG19 pre-trained
model = models.Sequential()
model.add(layers.Dense(512, activation='relu', input_dim=4 * 4 * 512))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(10, activation="softmax"))
# Compile the model
model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy'])

訓練模型後,這裏是test loss和測試精度:

出於視覺目的,我繪製了培訓和驗證的準確性和損失:

你能夠在此筆記本上查看此型號的完整代碼:VGG19-GPU.ipynb

總結

時尚領域是一個很是受歡迎的機器學習和計算機視覺應用的戰場。因爲高度的主觀性和所涉及的特徵的語義複雜性,該領域中的問題具備挑戰性。我但願這篇文章有助於你瞭解構建本身的卷積神經網絡以對時尚圖像進行分類的4種不一樣方法。

本文做者:【方向】

閱讀原文
)

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索