訂閱
糾錯
加入自媒體

人工神經網(wǎng)絡訓練圖像分類器

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

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

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

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

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

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

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

縮小、灰度化和展平圖像

讓我們導入相關庫。我們需要很多,需要安裝Numpy、Pandas、TensorFlow、PIL和Scikit Learn:

image.png

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

讓我們看一個例子。以下代碼加載并顯示訓練集中的cat圖像:

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

display(src_img)

圖2——貓的圖片示例

圖像寬281像素,高300像素,有三個顏色通道(np.array(src_img).shape)。

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

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

gray_img = ImageOps.grayscale(src_img)

display(gray_img)

圖3:灰色貓圖像

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

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

數(shù)據(jù)集中的圖像大小不同。這對于神經網(wǎng)絡模型來說是個問題,因為它每次都需要相同數(shù)量的輸入特征。

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

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

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

display(gray_resized_img)

圖4:調整大小的貓圖片

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

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

np.ravel(gray_resized_img)

圖5:扁平貓圖片

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

img_final = np.ravel(gray_resized_img) / 255.0

img_final

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

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

image.png

讓我們在隨機的狗圖像上進行測試,然后反轉最后一步,以直觀地表示圖像:

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

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

圖7:經過變換的狗形象

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

將圖像轉換為表格數(shù)據(jù)進行深度學習

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

讓我們將其應用于訓練、測試和驗證文件夾。每個文件夾需要調用兩次,一次用于貓,一次用于狗,然后連接集合。我們還將把數(shù)據(jù)集轉儲到pickle文件中:

image.png

下面是訓練集的樣子:

# 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——訓練集

數(shù)據(jù)集包含所有貓的圖像,然后是所有狗的圖像。這對于訓練集和驗證集來說并不理想,因為神經網(wǎng)絡會按照這個順序看到它們。

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

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

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

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

圖9——隨機后的訓練集

下一步是將特征與目標分離。我們將對所有三個子集進行拆分:

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ù)字編碼目標變量。有兩個不同的類(cat和dog),因此每個實例的目標變量應該包含兩個元素。

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

y_train.factorize()

圖10-factorize函數(shù)

標簽被轉換成整數(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——目標變量

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

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

用人工神經網(wǎng)絡(ANN)訓練圖像分類模型

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

· 輸出層——它需要兩個節(jié)點,因為我們有兩個不同的類。我們不能再使用sigmoid激活函數(shù)了,所以選擇softmax。

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

其他部分可以隨意更改:

image.png

以下是我在100個epoch后得到的結果:

圖12:100個epoch后的ANN結果

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

以下代碼片段繪制了100個epoch中每個epoch的訓練損失與驗證損失:

plt.plot(np.arange(1, 101), history.history['loss'], label='Training Loss')

plt.plot(np.arange(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:訓練損失與驗證損失

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

讓我們看看準確度:

plt.plot(np.arange(1, 101), history.history['accuracy'], label='Training Accuracy')

plt.plot(np.arange(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:訓練準確度與驗證準確度

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

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

結論

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

       原文標題 : 人工神經網(wǎng)絡訓練圖像分類器

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

發(fā)表評論

0條評論,0人參與

請輸入評論內容...

請輸入評論/評論長度6~500個字

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

暫無評論

暫無評論

人工智能 獵頭職位 更多
掃碼關注公眾號
OFweek人工智能網(wǎng)
獲取更多精彩內容
文章糾錯
x
*文字標題:
*糾錯內容:
聯(lián)系郵箱:
*驗 證 碼:

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