訂閱
糾錯(cuò)
加入自媒體

人工神經(jīng)網(wǎng)絡(luò)訓(xùn)練圖像分類器

我們將僅使用全連接層在20000張圖像上訓(xùn)練圖像分類模型。所以沒有卷積和其他花哨的東西,我們將把它們留到下一篇文章中。

不用說,但你真的不應(yīng)該使用普通的人工神經(jīng)網(wǎng)絡(luò)來分類圖像。圖像是二維的,通過展平圖像,你將失去使圖像可識別的模式。盡管如此,它還是很有趣且可行的,并且會(huì)讓你洞察這種方法的所有錯(cuò)誤。

使用的數(shù)據(jù)集和數(shù)據(jù)準(zhǔn)備

我們將使用Kaggle的狗與貓數(shù)據(jù)集。它是根據(jù)知識共享許可證授權(quán)的,這意味著你可以免費(fèi)使用它:

圖1:狗與貓數(shù)據(jù)集:

該數(shù)據(jù)集相當(dāng)大——25000張圖像均勻分布在不同的類中(12500張狗圖像和12500張貓圖像)。它應(yīng)該足夠大,可以訓(xùn)練一個(gè)像樣的圖像分類器,但不能使用人工神經(jīng)網(wǎng)絡(luò)。

唯一的問題是——它的結(jié)構(gòu)不適合直接使用。你可以按照之前的文章創(chuàng)建一個(gè)適當(dāng)?shù)哪夸浗Y(jié)構(gòu),并將其拆分為訓(xùn)練集、測試集和驗(yàn)證集:

縮小、灰度化和展平圖像

讓我們導(dǎo)入相關(guān)庫。我們需要很多,需要安裝Numpy、Pandas、TensorFlow、PIL和Scikit Learn:

image.png

我們不能將圖像直接傳遞到Dense層。單個(gè)圖像是三維的——高度、寬度、顏色通道——而Dense層需要一維輸入。

讓我們看一個(gè)例子。以下代碼加載并顯示訓(xùn)練集中的cat圖像:

src_img = Image.open('data/train/cat/1.jpg')

display(src_img)

圖2——貓的圖片示例

圖像寬281像素,高300像素,有三個(gè)顏色通道(np.a(chǎn)rray(src_img).shape)。

總的來說,它有252900個(gè)像素,在展平時(shí)轉(zhuǎn)化為252900個(gè)特征。讓我們盡可能節(jié)省一些資源。

如果有意義的話,你應(yīng)該對你的圖像數(shù)據(jù)集進(jìn)行灰度化。如果你能對不以顏色顯示的圖像進(jìn)行分類,那么神經(jīng)網(wǎng)絡(luò)也應(yīng)該如此。可以使用以下代碼段將圖像轉(zhuǎn)換為灰色:

gray_img = ImageOps.grayscale(src_img)

display(gray_img)

圖3:灰色貓圖像

顯然,它仍然是一只貓,所以顏色在這個(gè)數(shù)據(jù)集中并沒有起到很大作用。

灰度圖像寬281像素,高300像素,但只有一個(gè)顏色通道。這意味著我們從252,900 像素減少到84,300 像素。仍然很多,但肯定是朝著正確的方向邁出了一步。

數(shù)據(jù)集中的圖像大小不同。這對于神經(jīng)網(wǎng)絡(luò)模型來說是個(gè)問題,因?yàn)樗看味夹枰嗤瑪?shù)量的輸入特征。

我們可以將每個(gè)圖像調(diào)整為相同的寬度和高度,以進(jìn)一步減少輸入特征的數(shù)量。

下面的代碼片段調(diào)整了圖像的大小,使其既寬又高96像素:

gray_resized_img = gray_img.resize(size=(96, 96))

display(gray_resized_img)

圖4:調(diào)整大小的貓圖片

當(dāng)然,圖像有點(diǎn)小而且模糊,但它仍然是一只貓。但是我們的特征減少到9216個(gè),相當(dāng)于將特征的數(shù)量減少了27倍。

作為最后一步,我們需要將圖像展平。你可以使用Numpy中的ravel函數(shù)來執(zhí)行此操作:

np.ravel(gray_resized_img)

圖5:扁平貓圖片

計(jì)算機(jī)就是這樣看待貓的——它只是一個(gè)9216像素的數(shù)組,范圍從0到255。問題是——神經(jīng)網(wǎng)絡(luò)更喜歡0到1之間的范圍。我們將整個(gè)數(shù)組除以255.0即可:

img_final = np.ravel(gray_resized_img) / 255.0

img_final

圖6-扁平和縮放的貓圖像

作為最后一步,我們將編寫一個(gè)process_image函數(shù),將上述所有轉(zhuǎn)換應(yīng)用于單個(gè)圖像:

image.png

讓我們在隨機(jī)的狗圖像上進(jìn)行測試,然后反轉(zhuǎn)最后一步,以直觀地表示圖像:

tst_img = process_image(img_path='data/validation/dog/10012.jpg')

Image.fromarray(np.uint8(tst_img * 255).reshape((96, 96)))

圖7:經(jīng)過變換的狗形象

就這樣,這個(gè)函數(shù)就像字面意思。接下來,我們將其應(yīng)用于整個(gè)數(shù)據(jù)集。

將圖像轉(zhuǎn)換為表格數(shù)據(jù)進(jìn)行深度學(xué)習(xí)

我們將編寫另一個(gè)函數(shù)——process_folder——它迭代給定的文件夾,并在任何JPG文件上使用process_image函數(shù)。然后,它將所有圖像合并到一個(gè)數(shù)據(jù)幀中,并添加一個(gè)類作為附加列(貓或狗):

讓我們將其應(yīng)用于訓(xùn)練、測試和驗(yàn)證文件夾。每個(gè)文件夾需要調(diào)用兩次,一次用于貓,一次用于狗,然后連接集合。我們還將把數(shù)據(jù)集轉(zhuǎn)儲(chǔ)到pickle文件中:

image.png

下面是訓(xùn)練集的樣子:

# Training set

train_cat = process_folder(folder=pathlib.Path.cwd().joinpath('data/train/cat'))

train_dog = process_folder(folder=pathlib.Path.cwd().joinpath('data/train/dog'))

train_set = pd.concat([train_cat, train_dog], axis=0)

with open('train_set.pkl', 'wb') as f:

   pickle.dump(train_set, f)


# Test set

test_cat = process_folder(folder=pathlib.Path.cwd().joinpath('data/test/cat'))

test_dog = process_folder(folder=pathlib.Path.cwd().joinpath('data/test/dog'))

test_set = pd.concat([test_cat, test_dog], axis=0)

with open('test_set.pkl', 'wb') as f:

   pickle.dump(test_set, f)

# Validation set 

valid_cat = process_folder(folder=pathlib.Path.cwd().joinpath('data/validation/cat'))

valid_dog = process_folder(folder=pathlib.Path.cwd().joinpath('data/validation/dog'))

valid_set = pd.concat([valid_cat, valid_dog], axis=0)

with open('valid_set.pkl', 'wb') as f:

   pickle.dump(valid_set, f)

圖8——訓(xùn)練集

數(shù)據(jù)集包含所有貓的圖像,然后是所有狗的圖像。這對于訓(xùn)練集和驗(yàn)證集來說并不理想,因?yàn)樯窠?jīng)網(wǎng)絡(luò)會(huì)按照這個(gè)順序看到它們。

你可以使用Scikit Learn中的隨機(jī)函數(shù)來隨機(jī)排序:

train_set = shuffle(train_set).reset_index(drop=True)

valid_set = shuffle(valid_set).reset_index(drop=True)

下面是它現(xiàn)在的樣子:

圖9——隨機(jī)后的訓(xùn)練集

下一步是將特征與目標(biāo)分離。我們將對所有三個(gè)子集進(jìn)行拆分:

X_train = train_set.drop('class', axis=1)

y_train = train_set['class']


X_valid = valid_set.drop('class', axis=1)

y_valid = valid_set['class']


X_test = test_set.drop('class', axis=1)

y_test = test_set['class']

最后,使用數(shù)字編碼目標(biāo)變量。有兩個(gè)不同的類(cat和dog),因此每個(gè)實(shí)例的目標(biāo)變量應(yīng)該包含兩個(gè)元素。

例如,使用factorize函數(shù)進(jìn)行編碼:

y_train.factorize()

圖10-factorize函數(shù)

標(biāo)簽被轉(zhuǎn)換成整數(shù)——貓為0,狗為1。

你可以使用TensorFlow中的to_category函數(shù),并傳入factorize后的數(shù)組,以及不同類的數(shù)量(2):

y_train = tf.keras.utils.to_categorical(y_train.factorize()[0], num_classes=2)

y_valid = tf.keras.utils.to_categorical(y_valid.factorize()[0], num_classes=2)

y_test = tf.keras.utils.to_categorical(y_test.factorize()[0], num_classes=2)

因此,y_train現(xiàn)在看起來是這樣的:

圖11——目標(biāo)變量

從概率的角度考慮——第一張圖片有100%的幾率是貓,0%的幾率是狗。這些都是真實(shí)的標(biāo)簽,所以概率可以是0或1。

我們現(xiàn)在終于有了訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型所需的一切。

用人工神經(jīng)網(wǎng)絡(luò)(ANN)訓(xùn)練圖像分類模型

我隨機(jī)選擇了層的數(shù)量和每層的節(jié)點(diǎn)數(shù)量,以下2部分不能更改:

· 輸出層——它需要兩個(gè)節(jié)點(diǎn),因?yàn)槲覀冇袃蓚(gè)不同的類。我們不能再使用sigmoid激活函數(shù)了,所以選擇softmax。

· 損失函數(shù)——我們使用分類交叉熵。

其他部分可以隨意更改:

image.png

以下是我在100個(gè)epoch后得到的結(jié)果:

圖12:100個(gè)epoch后的ANN結(jié)果

60%的準(zhǔn)確率比猜測稍微好一點(diǎn),但性能一般。盡管如此,我們還是來檢查一下訓(xùn)練期間指標(biāo)發(fā)生了什么變化。

以下代碼片段繪制了100個(gè)epoch中每個(gè)epoch的訓(xùn)練損失與驗(yàn)證損失:

plt.plot(np.a(chǎn)range(1, 101), history.history['loss'], label='Training Loss')

plt.plot(np.a(chǎn)range(1, 101), history.history['val_loss'], label='Validation Loss')

plt.title('Training vs. Validation Loss', size=20)

plt.xlabel('Epoch', size=14)

plt.legend();

圖13:訓(xùn)練損失與驗(yàn)證損失

該模型能很好地學(xué)習(xí)訓(xùn)練數(shù)據(jù),但不能推廣。隨著我們對模型進(jìn)行更多epoch的訓(xùn)練,驗(yàn)證損失繼續(xù)增加,這表明模型不穩(wěn)定且不可用。

讓我們看看準(zhǔn)確度:

plt.plot(np.a(chǎn)range(1, 101), history.history['accuracy'], label='Training Accuracy')

plt.plot(np.a(chǎn)range(1, 101), history.history['val_accuracy'], label='Validation Accuracy')

plt.title('Training vs. Validation Accuracy', size=20)

plt.xlabel('Epoch', size=14)

plt.legend();

圖14:訓(xùn)練準(zhǔn)確度與驗(yàn)證準(zhǔn)確度

類似的圖片。驗(yàn)證精度穩(wěn)定在60%左右,而模型對訓(xùn)練數(shù)據(jù)的擬合度過高。

對于一個(gè)包含20K訓(xùn)練圖像的兩類數(shù)據(jù)集,60%的準(zhǔn)確率幾乎是它所能達(dá)到的最差水平。原因很簡單——Dense層的設(shè)計(jì)并不是為了捕捉二維圖像數(shù)據(jù)的復(fù)雜性。

結(jié)論

現(xiàn)在你知道了——如何用人工神經(jīng)網(wǎng)絡(luò)訓(xùn)練一個(gè)圖像分類模型,以及為什么你不應(yīng)該這么做。這就像穿著人字拖爬山——也許你能做到,但最好不要。

       原文標(biāo)題 : 人工神經(jīng)網(wǎng)絡(luò)訓(xùn)練圖像分類器

聲明: 本文由入駐維科號的作者撰寫,觀點(diǎn)僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報(bào)。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個(gè)字

您提交的評論過于頻繁,請輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無評論

暫無評論

    掃碼關(guān)注公眾號
    OFweek人工智能網(wǎng)
    獲取更多精彩內(nèi)容
    文章糾錯(cuò)
    x
    *文字標(biāo)題:
    *糾錯(cuò)內(nèi)容:
    聯(lián)系郵箱:
    *驗(yàn) 證 碼:

    粵公網(wǎng)安備 44030502002758號