介紹
卷積神經網絡 (CNN) 徹底改變了計算機視覺領域,成為圖像和視頻分析應用的基石。在本文中,我們將深入研究使 CNN 強大的關鍵組件和操作,探索卷積、最大池化、步長、填充、上采樣、下采樣等概念。此外,我們將使用 Python 和流行的深度學習框架討論數據集上的簡單 CNN 模型。
卷積神經網絡 (CNN) 由各種類型的層組成,這些層協同工作以從輸入數據中學習分層表示。每個層在整體架構中都發揮著獨特的作用。讓我們探索典型 CNN 中的主要層類型:
1. 輸入層 輸入層是網絡的初始數據輸入點。在基于圖像的任務中,輸入層表示圖像的像素值。在下面的示例中,我們假設我們正在處理大小為 28x28 像素的灰度圖像。
從tensorflow.keras.layersimport Input input_layer=Input(shape=(28, 28, 1))2.卷積層 卷積層是 CNN 的核心構建塊。這些層使用可學習的濾波器對輸入數據應用卷積運算。這些濾波器掃描輸入,提取邊緣、紋理和圖案等特征在卷積神經網絡 (CNN) 中,“核”和“濾波器”這兩個術語經常互換使用,指的是同一個概念。讓我們來分析一下這些術語的含義:
from tensorflow.keras.layers import Conv2D conv_layer=Conv2D(filters=32, kernel_size=(3, 3), activation='relu')(input_layer)2.1核 核是卷積運算中使用的小矩陣。它是一組可學習的權重,應用于輸入數據以生成輸出特征圖。核是讓 CNN 自動學習輸入數據中特征的空間層次結構的關鍵元素。在圖像處理中,核可能是 3x3 或 5x5 這樣的小矩陣。
2.2濾波器 另一方面,濾波器是一組多個內核。在大多數情況下,卷積層使用多個濾波器來捕獲輸入數據中的不同特征。每個濾波器與輸入進行卷積以產生特征圖,并且網絡通過在訓練期間調整這些濾波器的權重(參數)來學習提取各種模式。
在這個例子中,我們定義了一個有 32 個濾波器的卷積層,每個濾波器的內核大小為 3x3。在訓練期間,神經網絡會調整這 32 個濾波器的權重(參數),以從輸入數據中學習不同的特征。讓我們通過一個圖像示例來看一下:
核形狀(3X3)
總之,核是在輸入數據上滑動或卷積的小矩陣,而濾波器是一組用于從輸入中提取各種特征的核,從而允許神經網絡學習分層表示。
3.激活層 (ReLU) 在卷積操作之后,逐元素應用激活函數(通常是整流線性單元 (ReLU)),以將非線性引入模型。ReLU 可幫助網絡學習復雜的關系并使模型更具表現力。使用哪種激活完全取決于您的用例,在大多數情況下,研究人員使用 ReLU,但也可以使用一些激活,例如:Leaky ReLU、ELU。
ReLU 激活 在 Python 中實現整流線性單元 (ReLU) 函數非常簡單。ReLU 是神經網絡中常用的引入非線性的激活函數。這是一個簡單的 Python 實現:
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.全連接(密集)層 全連接層將一層中的每個神經元連接到下一層中的每個神經元。這些層通常位于網絡的末端,將學習到的特征轉換為預測或類概率。全連接層通常用于網絡的末端。對于分類任務:
從tensorflow.keras.layers import Dense、Flatten
flatten_layer = Flatten()(pooling_layer) density_layer = Dense(units= 128 ,activation= 'relu' )(flatten_layer)6.Dropout 層 Dropout 層用于正則化以防止過擬合。在訓練期間,隨機神經元被“丟棄”,這意味著它們被忽略,從而迫使網絡學習更穩健和更通用的特征。它通過在訓練期間隨機忽略一小部分輸入單元來幫助防止過擬合:
Dropout 機制
從tensorflow.keras.layers import Dropout
dropout_layer = Dropout(rate= 0.5)(dense_layer)7.批量標準化層 批量標準化 (BN) 是神經網絡中用于穩定和加速訓練過程的一種技術。它通過在訓練期間調整和縮放層輸入來標準化層輸入。批量標準化背后的數學細節涉及標準化、縮放和移位操作。讓我們深入研究批量標準化的數學原理。假設我們有一個大小為m且包含n 個特征的小批量。批量標準化的輸入可以總結如下:
7.1均值計算 計算每個特征的小批量的均值μ :
數組 X 的平均值
這里,xi 表示小批量中第 i個特征的值。
7.2方差計算 計算每個特征的小批量方差σ2 :
方差計算
7.3標準化 通過減去平均值并除以標準差(σ)來標準化輸入:
在范圍內標準化
這里,?是為了避免被零除而添加的一個小常數。
7.4縮放和平移 引入可學習參數(γ和β)來縮放和平移標準化值:
這里,γ是尺度參數,β是平移參數。
批量標準化操作通常插入神經網絡層中的激活函數之前。它已被證明具有正則化效果,可以緩解內部協變量偏移等問題,使訓練更穩定、更快速。這是一個簡單的代碼,用于 CNN 或任何深度神經網絡中的批量標準化。
從tensorflow.keras.layers import BatchNormalization
batch_norm_layer = BatchNormalization()(dropout_layer)總之,批量標準化對輸入進行標準化,縮放和移動標準化值,并引入可學習的參數,使網絡在訓練期間能夠適應。批量標準化的使用已成為深度學習架構中的標準做法。 8.Flatten Layer Flatten Layer 將多維特征圖轉換為一維向量,為輸入到全連接層準備數據。
flatten_layer=Flatten()(batch_norm_layer)9.上采樣層 上采樣是深度學習中用來增加特征圖空間分辨率的技術。它通常用于圖像分割和生成等任務。以下是常見上采樣方法類型的簡要說明:
9.1最近鄰 (NN) 上采樣 最近鄰 (NN) 上采樣,也稱為通過復制或復制進行上采樣,是一種簡單而直觀的方法。在這種方法中,輸入中的每個像素都被復制或復制以生成更大的輸出。雖然簡單明了,但 NN 上采樣可能會導致塊狀偽影和精細細節的丟失,因為它不會在相鄰像素之間進行插值。
最近鄰上采樣
9.2轉置卷積(反卷積)上采樣 轉置卷積,通常稱為反卷積,是一種可學習的上采樣方法。它涉及使用具有可學習參數的卷積運算來增加輸入的空間維度。轉置卷積層中的權重在優化過程中進行訓練,使網絡能夠學習特定于任務的上采樣模式。
importtensorflowas tf from tensorflow.keras.layers import Conv2DTranspose #轉置卷積上采樣 transposed_conv_upsampling=Conv2DTranspose(filters=32, kernel_size=(3, 3), strides=(2, 2), padding='same')
每種上采樣方法都有其優點和權衡,選擇取決于任務的具體要求和數據的特點。
填充和步幅
這些是卷積神經網絡 (CNN) 中的關鍵概念,它們會影響卷積運算后輸出特征圖的大小。讓我們討論三種類型的填充,并解釋一下步幅的概念。
有效填充(無填充):在有效填充(也稱為無填充)中,在應用卷積運算之前不會向輸入添加任何額外填充。因此,卷積運算僅在濾波器和輸入完全重疊的地方執行。這通常會導致輸出特征圖的空間維度減少。
from tensorflow.keras.layersimportConv2D # 有效填充 valid_padding_conv=Conv2D(filters=32,kernel_size=(3,3), strides=(1,1),padding='valid')
相同填充:相同填充確保輸出特征圖具有與輸入相同的空間維度。它通過向輸入添加零填充來實現這一點,這樣濾波器就可以在輸入上滑動而不會超出其邊界。填充量經過計算以保持維度相同。
from tensorflow.keras.layers import Conv2D #Keras中的填充 same_padding_conv=Conv2D(filters=32,kernel_size=(3,3), strides=(1,1),padding='same')
步幅:步幅定義卷積過程中濾波器在輸入上移動的步長。步幅越大,輸出特征圖的空間維度就越小。可以調整步幅來控制網絡中的下采樣級別。
從tensorflow.keras.layers導入Conv2D
# Keras 中帶步幅的卷積示例 conv_with_stride = Conv2D(filters= 32 , kernel_size=( 3 , 3 ), strides=( 2 , 2 ), padding= 'same' )在此示例中,步幅設置為 (2, 2),表示濾波器在水平和垂直方向上每次移動兩個像素。步幅是控制特征圖的空間分辨率和影響網絡感受野的關鍵參數。
在本文中,我想探索如何從頭開始構建一個簡單的卷積神經網絡。讓我們做早期計算機視覺學習任務中最流行的分類任務:貓與狗分類。此任務包括以下幾個步驟:
導入庫:
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
加載數據:Cats vs Dogs 數據集
!curl -O https://download.microsoft.com/download/ 3 /E/ 1 /3E1C3F21-ECDB- 4869 - 8368 -6DEBA77B919F/kagglecatsanddogs_5340.zip !unzip -qkagglecatsanddogs_5340.zip ! ls
下面的單元將對圖像進行預處理并創建批次,然后將其輸入到我們的模型中。
def augment_images ( image, label ): # 轉換為浮點數 image = tf.cast(image, tf.float32) # 標準化像素值 image = (image/ 255 ) # 調整大小為 300 x 300 image = tf.image.resize(image,( 300 , 300 )) return image, label # 使用上面的實用函數預處理圖像 augmented_training_data = train_data.map ( augment_images) # 在訓練前打亂并創建批次 train_batches = augmented_training_data.shuffle( 1024 ).batch( 32 )
過濾掉損壞的圖像
在處理大量現實世界的圖像數據時,損壞的圖像是常有的事。讓我們過濾掉標題中不包含字符串“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, )
可視化數據
這是訓練數據集中的前 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")
使用圖像數據增強
如果您沒有大型圖像數據集,最好通過對訓練圖像應用隨機但現實的變換(例如隨機水平翻轉或小幅隨機旋轉)來人為地引入樣本多樣性。這有助于讓模型接觸訓練數據的不同方面,同時減緩過擬合。
data_augmentation = keras.Sequential( [ layers.RandomFlip("horizontal"), layers.RandomRotation(0.1), ] )data_augmentation讓我們通過反復應用數據集中的第一個圖像來直觀地看到增強樣本的樣子:
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")
配置數據集以提高性能
我們將數據增強應用到我們的訓練數據集,并確保使用緩沖預取,這樣我們就可以從磁盤中獲取數據而不會導致 I/O 阻塞:
# 將 `data_augmentation` 應用于訓練圖像。 train_ds = train_ds.map( lambda img, label: (data_augmentation(img), label), num_parallel_calls=tf.data.AUTOTUNE, ) # 在 GPU 內存中預取樣本有助于最大限度地提高 GPU 利用率。 train_ds = train_ds.prefetch(tf.data.AUTOTUNE) val_ds = val_ds.prefetch(tf.data.AUTOTUNE)構建分類器
這看起來會很熟悉,因為它與我們之前構建的模型幾乎相同。關鍵區別在于輸出只是一個 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()損失可以根據上次進行調整,以僅處理兩個類別。為此,我們選擇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')審核編輯:黃飛
-
濾波器
+關注
關注
161文章
7817瀏覽量
178139 -
計算機視覺
+關注
關注
8文章
1698瀏覽量
45994 -
python
+關注
關注
56文章
4797瀏覽量
84692 -
cnn
+關注
關注
3文章
352瀏覽量
22215 -
卷積神經網絡
+關注
關注
4文章
367瀏覽量
11865
原文標題:CNN的原理詳解及代碼實戰(人手都會)
文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論