在實(shí)體店買衣服的過程中,我們會(huì)被眼花繚亂的信息轟炸。要兼顧某件衣服的款式、價(jià)格、商場(chǎng)優(yōu)惠還不夠,商場(chǎng)的燈光、擁擠的過道,無時(shí)無刻不在考驗(yàn)著人們分辨信息的能力。
那么,電腦能自動(dòng)檢測(cè)襯衫、褲子、連衣裙或運(yùn)動(dòng)鞋的照片嗎?事實(shí)證明,如果有高質(zhì)量的訓(xùn)練數(shù)據(jù),準(zhǔn)確地對(duì)時(shí)尚單品圖片進(jìn)行分類是很很容易做到的。在本文中,我們將講解如何用Fashion-MNIST數(shù)據(jù)集搭建一個(gè)用于辨認(rèn)時(shí)尚單品的機(jī)器學(xué)習(xí)模型。我們會(huì)提到如何訓(xùn)練模型、針對(duì)類別分類設(shè)計(jì)輸入和輸出以及每個(gè)模型的最終結(jié)果。
圖像分類
這一任務(wù)中涉及到的問題包括視角的變化、尺度變化、同類的多種變化、照片形變、照片遮擋、光線條件、背景等問題。如何寫出一套可以區(qū)分圖片類型的算法呢?計(jì)算機(jī)視覺研究人員提出了一種數(shù)據(jù)驅(qū)動(dòng)的方法來解決。過去,人們會(huì)了解每一圖片類別的代碼,從而進(jìn)行分類?,F(xiàn)在,研究人員從每類圖像中都選出一些樣本,訓(xùn)練深度學(xué)習(xí)算法學(xué)習(xí)每種類別的特點(diǎn)。換句話說,他們首先收集帶標(biāo)簽的訓(xùn)練數(shù)據(jù)集,然后輸入到計(jì)算機(jī)中,讓計(jì)算機(jī)熟悉這些數(shù)據(jù)。
主要步驟如下:
輸入的是一個(gè)含有N張圖片的數(shù)據(jù)集,每張圖片都帶有類別標(biāo)簽,數(shù)據(jù)集中共有K個(gè)不同的類別。
之后,我們用訓(xùn)練集去訓(xùn)練一個(gè)分類器,學(xué)習(xí)每種類別的樣式。
最后,讓分類器對(duì)陌生圖片進(jìn)行標(biāo)簽預(yù)測(cè),從而對(duì)分類器質(zhì)量進(jìn)行評(píng)估。之后我們會(huì)比較真實(shí)標(biāo)簽和分類器的預(yù)測(cè)標(biāo)簽。
Fashion MNIST數(shù)據(jù)集
去年八月份,德國(guó)研究機(jī)構(gòu)Zalando Research在GitHub上推出了一個(gè)全新的數(shù)據(jù)集,其中訓(xùn)練集包含60000個(gè)樣例,測(cè)試集包含10000個(gè)樣例,分為10類,其中的樣本都來自日常穿著的衣褲鞋包,每個(gè)都是28×28的灰度圖像,其中總共有10類標(biāo)簽,每張圖像都有各自的標(biāo)簽。
10種標(biāo)簽包括:
0:T-shirt/上衣
1:褲子
2:套頭衫
3:連衣裙
4:大衣
5:涼鞋
6:襯衣
7:運(yùn)動(dòng)鞋
8:包
9:高幫鞋
Fashion MNIST的可視化嵌入
嵌入是一種將分散目標(biāo)(圖像、文字等等)映射到高維向量中的方法。這些向量中的每個(gè)維度通常都沒有內(nèi)在意義,機(jī)器學(xué)習(xí)運(yùn)用的是想兩件的距離和總體的模式。在這里,我打算用TensorBoard表示高維的Fashion MNIST數(shù)據(jù)。閱讀了數(shù)據(jù)并創(chuàng)建測(cè)試標(biāo)簽后,我用以下代碼創(chuàng)建了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 Label ')
for index, label in enumerate(labels):
meta.write('{} {} '.format(index, label))
該投射器有三種對(duì)數(shù)據(jù)集降維的方法,兩種線性方法,一種非線性方法。每種方法都能用于創(chuàng)建二維或三維場(chǎng)景。
PCA:PCA是一種用于直接降維的技術(shù),嵌入投射器計(jì)算前十位的主要成分,通過菜單,我們可以將那些成分投射成任意兩種或三種的結(jié)合上。PCA是一個(gè)線性工具,通常在檢查全局幾何結(jié)構(gòu)上非常高效。
t-SNE:這是一種流行的非線性降維方法,嵌入投射器會(huì)同時(shí)提供二維和三維的t-SNE視圖。在客戶端可以看到平面圖,能展示出每一步算法。由于t-SNE通常會(huì)保留一些局部結(jié)構(gòu),這在探索局部近鄰、找尋聚類中是很有用的。
Custom:我還可以基于文本搜索創(chuàng)建特殊的線性投射器,用于在空間中尋找有意義的方向。程序可以計(jì)算這些點(diǎn)集的中心點(diǎn),他們的標(biāo)簽可以與搜索匹配,利用向量之間的不同作為投射器的軸。
查看完成的可視化步驟代碼,可點(diǎn)擊此網(wǎng)址:github.com/khanhnamle1994/fashion-mnist/blob/master/TensorBoard-Visualization.ipynb
在Fashion MNIST上訓(xùn)練CNN模型
接下來,我會(huì)創(chuàng)建多個(gè)基于CNN的分類模型,在Fashion MNIST上評(píng)估模型性能。我會(huì)用Keras框架搭建模型,想了解框架的更多信息,可以點(diǎn)擊此網(wǎng)址:keras.io/。下面是我想要比較的四種模型:
有一層卷積層的CNN
有三層卷積層的CNN
有四層卷積層的CNN
經(jīng)過與訓(xùn)練的VGG-19模型
除了預(yù)訓(xùn)練模型,我的實(shí)驗(yàn)方法如下:
將原始訓(xùn)練數(shù)據(jù)(共60000張圖片)分成訓(xùn)練集和驗(yàn)證集兩部分,80%是訓(xùn)練集,20%是驗(yàn)證集,另外還有10000張測(cè)試圖片,用于最終測(cè)試模型在陌生圖像上的表現(xiàn)。這可以研究模型是否在訓(xùn)練數(shù)據(jù)上過度擬合,以及是否應(yīng)該降低學(xué)習(xí)速率。
用256的batch size訓(xùn)練模型10個(gè)epoch,同時(shí)用categorical_crossentropy損失函數(shù)和Adam優(yōu)化器共同編譯。
之后進(jìn)行數(shù)據(jù)增強(qiáng),可以通過旋轉(zhuǎn)、變化、縮放生成新的訓(xùn)練樣本,再通過50個(gè)epoch對(duì)模型進(jìn)行訓(xùn)練。
以下是下載數(shù)據(jù)并分離數(shù)據(jù)的代碼:
# 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]))
下載數(shù)據(jù)后,我會(huì)重新處理它們,讓它們的值處于0到1之間。此前,訓(xùn)練數(shù)據(jù)都被存儲(chǔ)在一個(gè)(60000,28,28)的數(shù)組中,其中的值在0到255之間。
# 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
一層卷積層CNN
下面是只有一層卷積層的CNN代碼:
from keras.models importSequential
from keras.layers importDense, Dropout, Flatten
from keras.layers importConv2D, 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'])
訓(xùn)練完模型后,下面是測(cè)試損失和測(cè)試精確度:
進(jìn)行數(shù)據(jù)增強(qiáng)后的測(cè)試損失和測(cè)試精確度:
訓(xùn)練和驗(yàn)證精確度和損失的可視化:
完整代碼請(qǐng)點(diǎn)擊:github.com/khanhnamle1994/fashion-mnist/blob/master/CNN-1Conv.ipynb
三層卷積層CNN
有三層卷積層的CNN代碼:
from keras.models importSequential
from keras.layers importDense, Dropout, Flatten
from keras.layers importConv2D, 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'])
訓(xùn)練模型后,測(cè)試損失和測(cè)試精確度:
數(shù)據(jù)增強(qiáng)后的測(cè)試損失和精確度:
訓(xùn)練和驗(yàn)證的精確度和損失:
完整代碼請(qǐng)點(diǎn)擊:github.com/khanhnamle1994/fashion-mnist/blob/master/CNN-3Conv.ipynb
四層卷積層的CNN
下面是四層卷積層的CNN代碼:
from keras.models importSequential
from keras.layers importDense, Dropout, Flatten
from keras.layers importConv2D, 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'])
訓(xùn)練模型后的測(cè)試損失和精確度:
數(shù)據(jù)增強(qiáng)后的測(cè)試損失和精確度:
訓(xùn)練和驗(yàn)證的精確度和損失:
完整代碼請(qǐng)點(diǎn)擊:github.com/khanhnamle1994/fashion-mnist/blob/master/CNN-4Conv.ipynb
遷移學(xué)習(xí)
在小數(shù)據(jù)集上常用的一種高效深度學(xué)習(xí)方法就是使用預(yù)訓(xùn)練網(wǎng)絡(luò)。一種預(yù)訓(xùn)練網(wǎng)絡(luò)是此前在大型數(shù)據(jù)集上訓(xùn)練過的網(wǎng)絡(luò),通常處理過大型圖像分類任務(wù)。如果這樣的原始數(shù)據(jù)集足夠大并且足夠通用,那么預(yù)訓(xùn)練網(wǎng)絡(luò)學(xué)習(xí)到的特征空間分層可以用于視覺世界的普通模型,它的特征可以解決很多不同的計(jì)算機(jī)視覺問題。
我嘗試使用VGG19預(yù)訓(xùn)練模型,這在ImageNet中廣泛使用的ConvNets架構(gòu)。以下是所用的代碼:
import keras
from keras.applications import VGG19
from keras.applications.vgg19 import preprocess_input
from keras.layers importDense, Dropout
from keras.models importModel
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'])
模型訓(xùn)練后,測(cè)試損失和精確度如下:
可視化:
結(jié)語(yǔ)
時(shí)尚領(lǐng)域是計(jì)算機(jī)視覺和機(jī)器學(xué)習(xí)應(yīng)用的熱門,由于其中的予以復(fù)雜性,導(dǎo)致問題難度增加。希望這篇文章能對(duì)你在圖像分類任務(wù)上有所啟發(fā)。
-
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4819瀏覽量
106080 -
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8528瀏覽量
135880 -
數(shù)據(jù)集
+關(guān)注
關(guān)注
4文章
1229瀏覽量
25920
原文標(biāo)題:用卷積神經(jīng)網(wǎng)絡(luò)模型辨認(rèn)不同時(shí)尚服裝,四種方法對(duì)比
文章出處:【微信號(hào):jqr_AI,微信公眾號(hào):論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
評(píng)論