介紹
卷積神經(jīng)網(wǎng)絡 (CNN) 徹底改變了計算機視覺領域,成為圖像和視頻分析應用的基石。在本文中,我們將深入研究使 CNN 強大的關鍵組件和操作,探索卷積、最大池化、步長、填充、上采樣、下采樣等概念。此外,我們將使用 Python 和流行的深度學習框架討論數(shù)據(jù)集上的簡單 CNN 模型。
卷積神經(jīng)網(wǎng)絡 (CNN) 由各種類型的層組成,這些層協(xié)同工作以從輸入數(shù)據(jù)中學習分層表示。每個層在整體架構中都發(fā)揮著獨特的作用。讓我們探索典型 CNN 中的主要層類型:
1. 輸入層 輸入層是網(wǎng)絡的初始數(shù)據(jù)輸入點。在基于圖像的任務中,輸入層表示圖像的像素值。在下面的示例中,我們假設我們正在處理大小為 28x28 像素的灰度圖像。
從tensorflow.keras.layersimport Input input_layer=Input(shape=(28, 28, 1))2.卷積層 卷積層是 CNN 的核心構建塊。這些層使用可學習的濾波器對輸入數(shù)據(jù)應用卷積運算。這些濾波器掃描輸入,提取邊緣、紋理和圖案等特征在卷積神經(jīng)網(wǎng)絡 (CNN) 中,“核”和“濾波器”這兩個術語經(jīng)?;Q使用,指的是同一個概念。讓我們來分析一下這些術語的含義:
from tensorflow.keras.layers import Conv2D conv_layer=Conv2D(filters=32, kernel_size=(3, 3), activation='relu')(input_layer)2.1核 核是卷積運算中使用的小矩陣。它是一組可學習的權重,應用于輸入數(shù)據(jù)以生成輸出特征圖。核是讓 CNN 自動學習輸入數(shù)據(jù)中特征的空間層次結構的關鍵元素。在圖像處理中,核可能是 3x3 或 5x5 這樣的小矩陣。
2.2濾波器 另一方面,濾波器是一組多個內(nèi)核。在大多數(shù)情況下,卷積層使用多個濾波器來捕獲輸入數(shù)據(jù)中的不同特征。每個濾波器與輸入進行卷積以產(chǎn)生特征圖,并且網(wǎng)絡通過在訓練期間調(diào)整這些濾波器的權重(參數(shù))來學習提取各種模式。
在這個例子中,我們定義了一個有 32 個濾波器的卷積層,每個濾波器的內(nèi)核大小為 3x3。在訓練期間,神經(jīng)網(wǎng)絡會調(diào)整這 32 個濾波器的權重(參數(shù)),以從輸入數(shù)據(jù)中學習不同的特征。讓我們通過一個圖像示例來看一下:
核形狀(3X3)
總之,核是在輸入數(shù)據(jù)上滑動或卷積的小矩陣,而濾波器是一組用于從輸入中提取各種特征的核,從而允許神經(jīng)網(wǎng)絡學習分層表示。
3.激活層 (ReLU) 在卷積操作之后,逐元素應用激活函數(shù)(通常是整流線性單元 (ReLU)),以將非線性引入模型。ReLU 可幫助網(wǎng)絡學習復雜的關系并使模型更具表現(xiàn)力。使用哪種激活完全取決于您的用例,在大多數(shù)情況下,研究人員使用 ReLU,但也可以使用一些激活,例如:Leaky ReLU、ELU。
ReLU 激活 在 Python 中實現(xiàn)整流線性單元 (ReLU) 函數(shù)非常簡單。ReLU 是神經(jīng)網(wǎng)絡中常用的引入非線性的激活函數(shù)。這是一個簡單的 Python 實現(xiàn):
def relu(x): return max(0,x)4.池化層 池化層(例如MaxPooling或AveragePooling)可減少卷積層生成的特征圖的空間維度。例如,MaxPooling 從一組值中選擇最大值,重點關注最顯著的特征。
最大池化——平均池化 池化層減少了空間維度。MaxPooling 通常用于:
從tensorflow.keras.layers import MaxPooling2D pooling_layer = MaxPooling2D(pool_size=( 2 , 2 ))(conv_layer)5.全連接(密集)層 全連接層將一層中的每個神經(jīng)元連接到下一層中的每個神經(jīng)元。這些層通常位于網(wǎng)絡的末端,將學習到的特征轉(zhuǎn)換為預測或類概率。全連接層通常用于網(wǎng)絡的末端。對于分類任務:
從tensorflow.keras.layers import Dense、Flatten
flatten_layer = Flatten()(pooling_layer) density_layer = Dense(units= 128 ,activation= 'relu' )(flatten_layer)6.Dropout 層 Dropout 層用于正則化以防止過擬合。在訓練期間,隨機神經(jīng)元被“丟棄”,這意味著它們被忽略,從而迫使網(wǎng)絡學習更穩(wěn)健和更通用的特征。它通過在訓練期間隨機忽略一小部分輸入單元來幫助防止過擬合:
Dropout 機制
從tensorflow.keras.layers import Dropout
dropout_layer = Dropout(rate= 0.5)(dense_layer)7.批量標準化層 批量標準化 (BN) 是神經(jīng)網(wǎng)絡中用于穩(wěn)定和加速訓練過程的一種技術。它通過在訓練期間調(diào)整和縮放層輸入來標準化層輸入。批量標準化背后的數(shù)學細節(jié)涉及標準化、縮放和移位操作。讓我們深入研究批量標準化的數(shù)學原理。假設我們有一個大小為m且包含n 個特征的小批量。批量標準化的輸入可以總結如下:
7.1均值計算 計算每個特征的小批量的均值μ :
數(shù)組 X 的平均值
這里,xi 表示小批量中第 i個特征的值。
7.2方差計算 計算每個特征的小批量方差σ2 :
方差計算
7.3標準化 通過減去平均值并除以標準差(σ)來標準化輸入:
在范圍內(nèi)標準化
這里,?是為了避免被零除而添加的一個小常數(shù)。
7.4縮放和平移 引入可學習參數(shù)(γ和β)來縮放和平移標準化值:
這里,γ是尺度參數(shù),β是平移參數(shù)。
批量標準化操作通常插入神經(jīng)網(wǎng)絡層中的激活函數(shù)之前。它已被證明具有正則化效果,可以緩解內(nèi)部協(xié)變量偏移等問題,使訓練更穩(wěn)定、更快速。這是一個簡單的代碼,用于 CNN 或任何深度神經(jīng)網(wǎng)絡中的批量標準化。
從tensorflow.keras.layers import BatchNormalization
batch_norm_layer = BatchNormalization()(dropout_layer)總之,批量標準化對輸入進行標準化,縮放和移動標準化值,并引入可學習的參數(shù),使網(wǎng)絡在訓練期間能夠適應。批量標準化的使用已成為深度學習架構中的標準做法。 8.Flatten Layer Flatten Layer 將多維特征圖轉(zhuǎn)換為一維向量,為輸入到全連接層準備數(shù)據(jù)。
flatten_layer=Flatten()(batch_norm_layer)9.上采樣層 上采樣是深度學習中用來增加特征圖空間分辨率的技術。它通常用于圖像分割和生成等任務。以下是常見上采樣方法類型的簡要說明:
9.1最近鄰 (NN) 上采樣 最近鄰 (NN) 上采樣,也稱為通過復制或復制進行上采樣,是一種簡單而直觀的方法。在這種方法中,輸入中的每個像素都被復制或復制以生成更大的輸出。雖然簡單明了,但 NN 上采樣可能會導致塊狀偽影和精細細節(jié)的丟失,因為它不會在相鄰像素之間進行插值。
最近鄰上采樣
9.2轉(zhuǎn)置卷積(反卷積)上采樣 轉(zhuǎn)置卷積,通常稱為反卷積,是一種可學習的上采樣方法。它涉及使用具有可學習參數(shù)的卷積運算來增加輸入的空間維度。轉(zhuǎn)置卷積層中的權重在優(yōu)化過程中進行訓練,使網(wǎng)絡能夠?qū)W習特定于任務的上采樣模式。
importtensorflowas tf from tensorflow.keras.layers import Conv2DTranspose #轉(zhuǎn)置卷積上采樣 transposed_conv_upsampling=Conv2DTranspose(filters=32, kernel_size=(3, 3), strides=(2, 2), padding='same')
每種上采樣方法都有其優(yōu)點和權衡,選擇取決于任務的具體要求和數(shù)據(jù)的特點。
填充和步幅
這些是卷積神經(jīng)網(wǎng)絡 (CNN) 中的關鍵概念,它們會影響卷積運算后輸出特征圖的大小。讓我們討論三種類型的填充,并解釋一下步幅的概念。
有效填充(無填充):在有效填充(也稱為無填充)中,在應用卷積運算之前不會向輸入添加任何額外填充。因此,卷積運算僅在濾波器和輸入完全重疊的地方執(zhí)行。這通常會導致輸出特征圖的空間維度減少。
from tensorflow.keras.layersimportConv2D # 有效填充 valid_padding_conv=Conv2D(filters=32,kernel_size=(3,3), strides=(1,1),padding='valid')
相同填充:相同填充確保輸出特征圖具有與輸入相同的空間維度。它通過向輸入添加零填充來實現(xiàn)這一點,這樣濾波器就可以在輸入上滑動而不會超出其邊界。填充量經(jīng)過計算以保持維度相同。
from tensorflow.keras.layers import Conv2D #Keras中的填充 same_padding_conv=Conv2D(filters=32,kernel_size=(3,3), strides=(1,1),padding='same')
步幅:步幅定義卷積過程中濾波器在輸入上移動的步長。步幅越大,輸出特征圖的空間維度就越小??梢哉{(diào)整步幅來控制網(wǎng)絡中的下采樣級別。
從tensorflow.keras.layers導入Conv2D
# Keras 中帶步幅的卷積示例 conv_with_stride = Conv2D(filters= 32 , kernel_size=( 3 , 3 ), strides=( 2 , 2 ), padding= 'same' )在此示例中,步幅設置為 (2, 2),表示濾波器在水平和垂直方向上每次移動兩個像素。步幅是控制特征圖的空間分辨率和影響網(wǎng)絡感受野的關鍵參數(shù)。
在本文中,我想探索如何從頭開始構建一個簡單的卷積神經(jīng)網(wǎng)絡。讓我們做早期計算機視覺學習任務中最流行的分類任務:貓與狗分類。此任務包括以下幾個步驟:
導入庫:
import tensorflow_datasets as tfds import tensorflow as tf from tensorflow.keras import layers import keras from keras.models import Sequential,Model from keras.layers import Dense,Conv2D,Flatten,MaxPooling2D,GlobalAveragePooling2D from keras.utils import plot_model import numpy as np import matplotlib.pyplot as plt import scipy as sp import cv2
加載數(shù)據(jù):Cats vs Dogs 數(shù)據(jù)集
!curl -O https://download.microsoft.com/download/ 3 /E/ 1 /3E1C3F21-ECDB- 4869 - 8368 -6DEBA77B919F/kagglecatsanddogs_5340.zip !unzip -qkagglecatsanddogs_5340.zip ! ls
下面的單元將對圖像進行預處理并創(chuàng)建批次,然后將其輸入到我們的模型中。
def augment_images ( image, label ): # 轉(zhuǎn)換為浮點數(shù) image = tf.cast(image, tf.float32) # 標準化像素值 image = (image/ 255 ) # 調(diào)整大小為 300 x 300 image = tf.image.resize(image,( 300 , 300 )) return image, label # 使用上面的實用函數(shù)預處理圖像 augmented_training_data = train_data.map ( augment_images) # 在訓練前打亂并創(chuàng)建批次 train_batches = augmented_training_data.shuffle( 1024 ).batch( 32 )
過濾掉損壞的圖像
在處理大量現(xiàn)實世界的圖像數(shù)據(jù)時,損壞的圖像是常有的事。讓我們過濾掉標題中不包含字符串“JFIF”的編碼不良的圖像。
import os num_skipped = 0 for folder_name in ("Cat", "Dog"): folder_path = os.path.join("PetImages", folder_name) for fname in os.listdir(folder_path): fpath = os.path.join(folder_path, fname) try: fobj = open(fpath, "rb") is_jfif = tf.compat.as_bytes("JFIF") in fobj.peek(10) finally: fobj.close() if not is_jfif: num_skipped += 1 # Delete corrupted image os.remove(fpath) print("Deleted %d images" % num_skipped)生成Dataset
image_size = (300, 300) batch_size = 128 train_ds, val_ds = tf.keras.utils.image_dataset_from_directory( "PetImages", validation_split=0.2, subset="both", seed=1337, image_size=image_size, batch_size=batch_size, )
可視化數(shù)據(jù)
這是訓練數(shù)據(jù)集中的前 9 張圖片。如你所見,標簽 1 是“狗”,標簽 0 是“貓”。
import matplotlib.pyplot as plt plt.figure(figsize=(6, 6)) for images, labels in train_ds.take(1): for i in range(9): ax = plt.subplot(3, 3, i + 1) plt.imshow(images[i].numpy().astype("uint8")) plt.title(int(labels[i])) plt.axis("off")
使用圖像數(shù)據(jù)增強
如果您沒有大型圖像數(shù)據(jù)集,最好通過對訓練圖像應用隨機但現(xiàn)實的變換(例如隨機水平翻轉(zhuǎn)或小幅隨機旋轉(zhuǎn))來人為地引入樣本多樣性。這有助于讓模型接觸訓練數(shù)據(jù)的不同方面,同時減緩過擬合。
data_augmentation = keras.Sequential( [ layers.RandomFlip("horizontal"), layers.RandomRotation(0.1), ] )data_augmentation讓我們通過反復應用數(shù)據(jù)集中的第一個圖像來直觀地看到增強樣本的樣子:
plt.figure(figsize=(6, 6)) for images, _ in train_ds.take(1): for i in range(9): augmented_images = data_augmentation(images) ax = plt.subplot(3, 3, i + 1) plt.imshow(augmented_images[0].numpy().astype("uint8")) plt.axis("off")
配置數(shù)據(jù)集以提高性能
我們將數(shù)據(jù)增強應用到我們的訓練數(shù)據(jù)集,并確保使用緩沖預取,這樣我們就可以從磁盤中獲取數(shù)據(jù)而不會導致 I/O 阻塞:
# 將 `data_augmentation` 應用于訓練圖像。 train_ds = train_ds.map( lambda img, label: (data_augmentation(img), label), num_parallel_calls=tf.data.AUTOTUNE, ) # 在 GPU 內(nèi)存中預取樣本有助于最大限度地提高 GPU 利用率。 train_ds = train_ds.prefetch(tf.data.AUTOTUNE) val_ds = val_ds.prefetch(tf.data.AUTOTUNE)構建分類器
這看起來會很熟悉,因為它與我們之前構建的模型幾乎相同。關鍵區(qū)別在于輸出只是一個 S 激活單元。這是因為我們只處理兩個類。
classCustomModel(Sequential): def __init__(self): super(CustomModel, self).__init__() self.add(Conv2D(16, input_shape=(300, 300, 3), kernel_size=(3, 3), activation='relu', padding='same')) self.add(MaxPooling2D(pool_size=(2, 2))) self.add(Conv2D(32, kernel_size=(3, 3), activation='relu', padding='same')) self.add(MaxPooling2D(pool_size=(2, 2))) self.add(Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same')) self.add(MaxPooling2D(pool_size=(2, 2))) self.add(Conv2D(128, kernel_size=(3, 3), activation='relu', padding='same')) self.add(GlobalAveragePooling2D()) self.add(Dense(1, activation='sigmoid')) # Instantiate the custom model model = CustomModel() # Display the model summarymodel.summary()損失可以根據(jù)上次進行調(diào)整,以僅處理兩個類別。為此,我們選擇binary_crossentropy。
# 使用 GPU 進行訓練大約需要 30 分鐘。 #如果您的本地機器上沒有GPU,請隨意使用 model.compile(loss='binary_crossentropy', metrics=['accuracy'], optimizer=tf.keras.optimizers.RMSprop(lr=0.001)) model.fit(train_ds, epochs=25, validation_data=val_ds,)
測試模型
讓我們下載一些圖像并看看類別激活圖是什么樣子的。
!wget -O cat1.jpg https://storage.googleapis.com/laurencemoroney-blog.appspot.com/MLColabImages/cat1.jpg !wget -O cat2.jpg https://storage.googleapis.com/laurencemoroney-blog.appspot.com/MLColabImages/cat2.jpg !wget -O catanddog.jpg https://storage.googleapis.com/laurencemoroney-blog.appspot.com/MLColabImages/catanddog.jpg !wget -O dog1.jpg https://storage.googleapis.com/laurencemoroney-blog.appspot.com/MLColabImages/dog1.jpg !wget -O dog2.jpg https://storage.googleapis.com/laurencemoroney-blog.appspot.com/MLColabImages/dog2.jpg
# utility function to preprocess an image and show the CAM def convert_and_classify(image): # load the image img = cv2.imread(image) # preprocess the image before feeding it to the model img = cv2.resize(img, (300,300)) / 255.0 # add a batch dimension because the model expects it tensor_image = np.expand_dims(img, axis=0) # get the features and prediction features,results = cam_model.predict(tensor_image) # generate the CAM show_cam(tensor_image, features, results) convert_and_classify('cat1.jpg') convert_and_classify('cat2.jpg') convert_and_classify('catanddog.jpg') convert_and_classify('dog1.jpg') convert_and_classify('dog2.jpg')審核編輯:黃飛
-
濾波器
+關注
關注
162文章
8138瀏覽量
182086 -
計算機視覺
+關注
關注
9文章
1709瀏覽量
46781 -
python
+關注
關注
56文章
4827瀏覽量
86762 -
cnn
+關注
關注
3文章
354瀏覽量
22743 -
卷積神經(jīng)網(wǎng)絡
關注
4文章
369瀏覽量
12305
原文標題:CNN的原理詳解及代碼實戰(zhàn)(人手都會)
文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
評論