基於卷積神經網路的影像分類技術

WBOY
發布: 2023-05-06 19:13:06
轉載
1443 人瀏覽過

譯者 | 朱先忠

審校 | 孫淑娟

1.什麼是卷積神經網路(CNN)?

概括來講,卷積神經網路是一類特殊的神經網絡,具有從影像資料中提取獨特的影像特徵的能力。例如,目前卷積神經網路已被廣泛應用於人臉偵測和識別,因為它們非常有助於識別影像資料中的複雜特徵。

2.卷積神經網路是如何運作的?

與其他類型的神經網路一樣,CNN也使用數位資料。因此,饋送到這些網路的圖像必須先轉換為數位表示。因為影像是由像素組成的,所以它們被轉換成數位形式後再傳遞給CNN。

正如我們將在下一節中討論的,整個數位表示層並沒有傳遞到網路中。為了理解這是如何運作的,讓我們看看訓練CNN的一些步驟。

卷積

透過卷積運算減少發送給CNN的數字表示的大小。這個過程至關重要,因此只有對影像分類重要的特徵才會被傳送到神經網路。除了提高網路的準確性外,這還可以確保在訓練網路時使用最少的計算資源。

卷積運算的結果稱為特徵映射、卷積特徵或活化映射。應用特徵檢測器可以產生特徵映射。特徵檢測器也被稱為內核或過濾器等其他名稱。

核心通常是一個3X3的矩陣。將內核與輸入影像依元素相乘並求和,輸出特徵映射。這是透過在輸入影像上滑動核心來實現的。這種滑動以步長的形式發生。當然,創建CNN時,可以手動設定內核的步長和大小。

基於卷積神經網路的影像分類技術

一個典型的3X3的捲積運算

例如,給定一個5X5的輸入,一個3X3的核心將輸出一個3X3的輸出特徵映射。

填充(Padding)

在上述操作中,我們看到,作為應用卷積操作的一部分,特徵映射的大小減小了。那麼,如果希望特徵映射的大小與輸入影像的大小相同,該怎麼辦?這是透過填充實現的。

填滿操作是指透過零「填滿」影像來增加輸入影像的大小。因此,對影像套用這種濾鏡會產生與輸入影像大小相同的特徵映射。

基於卷積神經網路的影像分類技術

未著色的區域代表填充區域

填充操作不僅減少了卷積運算中遺失的資訊量,而且還能夠確保在卷積運算中更頻繁地劃分影像的邊緣。

在建置CNN時,您可以選擇定義所需的填滿類型或完全不填入。這裡的常見選項包括:有效(valid)或相同(same)。其中,valid表示不應用填充處理;而same表示套用填充處理,以便特徵映射的大小與輸入影像的大小相同。

基於卷積神經網路的影像分類技術

3×3內核將5×5的輸入減少為3×3的輸出

下圖給出的是上面描述的特徵映射和過濾器的元素相乘的樣子。

基於卷積神經網路的影像分類技術

激活函數

在每次卷積運算後應用線性整流函數(ReLU)變換以確保非線性。 ReLU是目前最受歡迎的激活函數,但也有其他一些激活函數可供選擇。

轉換後,所有低於零的值都會傳回為零,而其他值則保持不變。

基於卷積神經網路的影像分類技術

ReLu函數圖

池化

在池化運算中,特徵映射的大小會進一步減小。目前,可以使用各種池化方法。

常見的方法是最大池化法。池過濾器的大小通常是一個2×2矩陣。在最大池化法中,2×2濾波器在功能映射上滑動,並在給定範圍的矩形框中選取最大值。此操作將產生池化的特徵映射。

基於卷積神經網路的影像分類技術

把2×2池過濾器套用到4×4特徵映射

#

池化迫使神經網路辨識影像中的關鍵特徵,而不必考慮這些關鍵特徵資料的位置。此外,縮小的圖像大小也有助於網路訓練速度更快一些。

Dropout正規化

應用Dropout正規化是CNN的常見做法。這涉及在一些特定網路層中隨機刪除一些節點,以便在反向傳播期間不會更新它們。這樣可以防止過度擬合。

扁平化

扁平化的主要任務是將池化後的特徵映射轉換為單一列,並傳遞給完全連接層。這是從卷積層過渡到完全連接層期間的常見做法。

完全連接層

接下來,扁平化後的特徵映射被傳遞到完全連接層。根據特定的問題和網路類型,可能存在好幾個完全連接層。其中,最後一個完全連接層負責輸出預測結果。

根據問題的類型,在最後一層中使用激活函數。其中,sigmoid激活函數主要用於二值分類的情形,而softmax激活函數通常用於多類別圖像分類。

基於卷積神經網路的影像分類技術

全連結卷積神經網路

3.為什麼卷積神經網路優於常規型前饋神經網路?

了解了CNN之後,你可能想知道為什麼我們不能用普通的神經網路來解決圖像問題,主要原因在於,常規的神經網路無法像CNN那樣從圖像中提取複雜的特徵。

CNN透過應用濾鏡從影像中提取額外特徵的能力使其更適合處理影像問題。此外,將影像直接輸入前饋神經網路的運算成本也會很高。

4.卷積神經網路架構

你可以選擇從頭開始設計你的CNN,也可以利用公開開發發布的眾多CNN體系結構。值得注意的是,其中一些CNN網路還附帶預先訓練的模型,你可以輕鬆地根據自己的使用需求進行調整。以下是一些可供你選擇的流行的CNN架構:

  • ResNet50
  • #VGG19
  • Xception
  • Inception

您可以透過Keras應用程式開始使用這些架構。例如,下面的程式碼展示如何使用VGG19框架進行開發的框架範例:

from tensorflow.keras.applications.vgg19 import VGG19
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.vgg16 import preprocess_input
import numpy as np

model = VGG19(weights='imagenet', include_top=False)

img_path = 'elephant.jpg'
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)

features = model.predict(x)
登入後複製

5.卷積神經網路(CNN)在TensorFlow中的應用

現在,讓我們使用食物資料集建構一個食物分類CNN。此資料集包含101個類別的10萬多張影像。

載入圖片

第一步是下載並擷取資料。

!wget --no-check-certificate 
http://data.vision.ee.ethz.ch/cvl/food-101.tar.gz
-O food.tar.gz
!tar xzvf food.tar.gz
登入後複製

讓我們看一下資料集中的一個圖像。

plt.imshow(Image.open("food-101/images/beignets/2802124.jpg"))
plt.axis('off')
plt.show()
登入後複製

基於卷積神經網路的影像分類技術

產生一個tf.data.Dataset

接下來,將影像載入到TensorFlow資料集中。我們將使用20%的資料進行測試,其餘資料用於訓練。因此,我們必須為訓練和測試集建立一個圖像資料集合(透過呼叫訓練集產生器函數ImageDataGenerator來實現)。

在訓練集產生器函數中還需要指定幾種影像增強技術,例如縮放和翻轉影像等。需要說明一點,增強功能有助於防止網路中出現過度擬合。

base_dir = 'food-101/images'
train_datagen = ImageDataGenerator(rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
width_shift_range=0.1,
height_shift_range=0.1,
validation_split=0.2
)
validation_gen = ImageDataGenerator(rescale=1./255,validation_split=0.2)
登入後複製

建立圖像集產生器後,下一步的任務就是使用它們從基底目錄位置載入食物圖像。載入圖像時,我們需要指定圖像的目標大小。所有影像都將調整為可指定大小。

image_size = (200, 200)
training_set = train_datagen.flow_from_directory(base_dir,
seed=101,
target_size=image_size,
batch_size=32,
subset = "training",
class_mode='categorical')
登入後複製

注意到,在載入圖片時我們還需要指定:

  • 載入圖片的目錄位置。
  • 批次大小,在本例中為32,這表示映像將以32個批次載入。
  • 子集;無論是訓練或驗證時都需要指定。
  • 由於我們有多個類型的圖像,因此類型模式為多分類模式。對於兩個類別的情形,這個參數可以使用二進位數來指定。
validation_set = validation_gen.flow_from_directory(base_dir, 
target_size=image_size,
batch_size=32,
subset = "validation",
class_mode='categorical')
登入後複製

模型定義

下一步是定義CNN模型。神經網路的架構方案將與我們前面在「卷積神經網路是如何運作的?」一節中討論的步驟類似。我們將使用Keras網路框架中的Sequential API來定義網路。其中,CNN部分是使用Conv2D層定義的。

model = Sequential([
Conv2D(filters=32,kernel_size=(3,3),input_shape = (200, 200, 3),activation='relu'),
MaxPooling2D(pool_size=(2,2)),

Conv2D(filters=32,kernel_size=(3,3), activation='relu'),
MaxPooling2D(pool_size=(2,2)),
Dropout(0.25),

Conv2D(filters=64,kernel_size=(3,3), activation='relu'),
MaxPooling2D(pool_size=(2,2)),
Dropout(0.25),

Flatten(),
Dense(128, activation='relu'),
Dropout(0.25),
Dense(101, activation='softmax')
])
登入後複製

該Conv2D層有以下期望:

  • 在本例中,使用的过滤器数量为32。
  • 在本例中,使用的内核的大小数量为3X3。
  • 输入图像的大小。200X200是图像的大小,3指定这是一种彩色图像。
  • 激活函数,通常使用的就是ReLu函数。

在上述网络中,我们使用2X2的过滤器进行池化,并应用一个Dropout层以防止过度拟合。最后一层有101个单元,因为有101个食物类别。激活函数使用的是softmax函数,因为我们解决的是一个多类别图像分类问题。

编译CNN模型

接下来,我们使用分类损失算法和精确算法对网络进行编译,因为它涉及多个类。

model.compile(optimizer='adam',
loss=keras.losses.CategoricalCrossentropy(),
metrics=[keras.metrics.CategoricalAccuracy()])
登入後複製

训练CNN模型

接下来,我们开始训练CNN模型。

现在让我们开始训练CNN模型。在训练过程中,我们要应用EarlyStopping回调函数;这样做的目的是,如果模型在多次迭代后没有得到改善,训练就会停止。在本例情况下,共使用了三个训练周期(epochs)。

callback = EarlyStopping(monitor='loss', patience=3)
history = model.fit(training_set,validation_data=validation_set, epochs=100,callbacks=[callback])
登入後複製

本例中,由于我们正在处理的图像数据集相当大,所以我们需要使用GPU来训练这个模型。让我们利用Layer网站(【译者注】遗憾的是无法打开此网站,读者知道这种思路即可,其实当前市面上已经有多种免费在线GPU服务可供AI学习之用)提供的免费GPU来训练模型。为此,我们需要将上面开发的所有代码“捆绑”到一个函数中。此函数应返回一个模型。在本例情况下,返回的是一个TensorFlow模型。

要使用GPU训练模型,只需使用GPU环境参数装饰一下函数,这是使用fabric装饰器(https://docs.app.layer.ai/docs/reference/fabrics)指定的。

#pip install layer-sdk -qqq
import layer
from layer.decorators import model, fabric,pip_requirements
#验证层帐户
#经过训练的模型将保存在此。
layer.login()
#初始化一个项目,经过训练的模型将保存在此项目下。
layer.init("image-classification")
@pip_requirements(packages=["wget","tensorflow","keras"])
@fabric("f-gpu-small")
@model(name="food-vision")
def train():
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense,Conv2D,MaxPooling2D,Flatten,Dropout
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import EarlyStopping
import os
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
import pandas as pd
import tarfile
import wget
wget.download("http://data.vision.ee.ethz.ch/cvl/food-101.tar.gz")
food_tar = tarfile.open('food-101.tar.gz')
food_tar.extractall('.')
food_tar.close()
plt.imshow(Image.open("food-101/images/beignets/2802124.jpg"))
plt.axis('off')
layer.log({"Sample image":plt.gcf()})
base_dir = 'food-101/images'
class_names = os.listdir(base_dir)
train_datagen = ImageDataGenerator(rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
width_shift_range=0.1,
height_shift_range=0.1,
validation_split=0.2
)
validation_gen = ImageDataGenerator(rescale=1./255,validation_split=0.2)
image_size = (200, 200)
training_set = train_datagen.flow_from_directory(base_dir,
seed=101,
target_size=image_size,
batch_size=32,
subset = "training",
class_mode='categorical')
validation_set = validation_gen.flow_from_directory(base_dir,
target_size=image_size,
batch_size=32,
subset = "validation",
class_mode='categorical')
model = Sequential([
Conv2D(filters=32,kernel_size=(3,3),input_shape = (200, 200, 3),activation='relu'),
MaxPooling2D(pool_size=(2,2)),

Conv2D(filters=32,kernel_size=(3,3), activation='relu'),
MaxPooling2D(pool_size=(2,2)),
Dropout(0.25),

Conv2D(filters=64,kernel_size=(3,3), activation='relu'),
MaxPooling2D(pool_size=(2,2)),
Dropout(0.25),

Flatten(),
Dense(128, activation='relu'),
Dropout(0.25),
Dense(101, activation='softmax')])
model.compile(optimizer='adam',
loss=keras.losses.CategoricalCrossentropy(),
metrics=[keras.metrics.CategoricalAccuracy()])
callback = EarlyStopping(monitor='loss', patience=3)
epochs=20
history = model.fit(training_set,validation_data=validation_set, epochs=epochs,callbacks=[callback])
metrics_df = pd.DataFrame(history.history)
layer.log({"Metrics":metrics_df})
loss, accuracy = model.evaluate(validation_set)
layer.log({"Accuracy on test dataset":accuracy})
metrics_df[["loss","val_loss"]].plot()
layer.log({"Loss plot":plt.gcf()})
metrics_df[["categorical_accuracy","val_categorical_accuracy"]].plot()
layer.log({"Accuracy plot":plt.gcf()})
return model
登入後複製

训练模型的任务是通过将训练函数传递给“layer.run”函数来完成的。如果希望在本地基础设施上训练模型,则可以通过调用“train()”函数来实现。

layer.run([train])
登入後複製

基於卷積神經網路的影像分類技術

预测

模型准备好后,我们可以对新图像进行预测,这可以通过以下步骤完成:

  • 从前面提及的在线GPU服务网站获取经过训练的模型。
  • 加载与训练图像中使用的图像大小相同的图像。
  • 将图像转换为数组。
  • 将数组中的数字除以255,使其介于0和1之间。切记:所有参与训练图像的形式都必须是相同的。
  • 扩展图像的尺寸——增加1个batch_size大小,因为我们正在对单个图像进行预测。
from keras.preprocessing import image
import numpy as np
image_model = layer.get_model('layer/image-classification/models/food-vision').get_train()
!wget --no-check-certificate
https://upload.wikimedia.org/wikipedia/commons/b/b1/Buttermilk_Beignets_%284515741642%29.jpg
-O /tmp/Buttermilk_Beignets_.jpg
test_image = image.load_img('/tmp/Buttermilk_Beignets_.jpg', target_size=(200, 200))
test_image = image.img_to_array(test_image)

test_image = test_image / 255.0
test_image = np.expand_dims(test_image, axis=0)

prediction = image_model.predict(test_image)

prediction[0][0]
登入後複製

由于这是一个多类别网络,我们将使用softmax函数来解释结果。该函数将logit转换为每个类别的概率。

class_names = os.listdir(base_dir)
scores = tf.nn.softmax(prediction[0])
scores = scores.numpy()
f"{class_names[np.argmax(scores)]} with a { (100 * np.max(scores)).round(2) } percent confidence."
登入後複製

6.小结    

在本文中,我们详细介绍了卷积神经网络有关知识。具体来说,文章中涵盖了如下内容:

  • 什么是CNN?
  • CNN如何工作
  • CNN架构
  • 如何为图像分类问题构建CNN

原文链接:

https://www.kdnuggets.com/2022/05/image-classification-convolutional-neural-networks-cnns.html

译者介绍

朱先忠,51CTO社区编辑,51CTO专家博客、讲师,潍坊一所高校计算机教师,自由编程界老兵一枚。早期专注各种微软技术(编著成ASP.NET AJX、Cocos 2d-X相关三本技术图书),近十多年投身于开源世界(熟悉流行全栈Web开发技术),了解基于OneNet/AliOS+Arduino/ESP32/树莓派等物联网开发技术与Scala+Hadoop+Spark+Flink等大数据开发技术。

基於卷積神經網路的影像分類技術

以上是基於卷積神經網路的影像分類技術的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:51cto.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!