Posted on

Tensorflow裡ResNet(殘差網路)的介紹

殘差網路ResNet

殘差網路(Residual Network,簡稱 ResNet)是一種深度卷積神經網路,它被設計用來解決深度神經網路中的梯度消失問題。

在深度神經網路中,隨著層數的增加,梯度有可能會越來越小,導致模型無法有效地學習。殘差網路通過在每一層中引入一個「殘差块」來解決這個問題。殘差块包含兩個卷積層和一個殘差路徑,殘差路徑將輸入數據直接加到輸出數據上。這樣,當殘差块的輸出數據與輸入數據相加時,梯度就不會被消失。

這邊是別人的文章介紹: https://ithelp.ithome.com.tw/articles/10264843?sc=hot

與Conv2D關鍵的不同

Conv2D就是一個提取圖片裡的特徵的方式,他是可以讓圖片也可以丟進Dense去找到共通特徵的一個關鍵,但是,Conv2D一定會需要與其他像是池化層、全連接層、輸出層等一起使用。
而殘差網路就是某個對ML非常熟的神人,所使用像是卷積層、池化層、連接層等,可有效降低梯度消失的問題的一個【已經建立好的模型】
例如: 以下為一個原始的TF模型的建立方式

model = tf.keras.Sequential([
    tf.keras.layers.Rescaling(1./255),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(num_classes)
])

ResNet使用範例

而使用ResNet非常的簡單,就使用別人已建立好的ResNet就可以了,以下範例中的 ResNet 使用了 20 個 ResidualBlock,每個 ResidualBlock 中使用了 64 個濾波器,卷積核大小為 3×3,步長為 2。

import tensorflow as tf
from tensorflow.keras import layers

class ResidualBlock(layers.Layer):
    def __init__(self, filters, kernel_size, strides, use_projection=False):
        super(ResidualBlock, self).__init__()
        self.use_projection = use_projection
        self.conv1 = layers.Conv2D(filters, kernel_size, strides=strides, padding='same')
        self.bn1 = layers.BatchNormalization()
        self.relu = layers.ReLU()
        self.conv2 = layers.Conv2D(filters, kernel_size, strides=1, padding='same')
        self.bn2 = layers.BatchNormalization()
        if use_projection:
            self.projection = layers.Conv2D(filters, 1, strides=strides, padding='same')

    def call(self, inputs, training=False):
        x = self.conv1(inputs)
        x = self.bn1(x, training=training)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.bn2(x, training=training)
        if self.use_projection:
            shortcut = self.projection(inputs)
        else:
            shortcut = inputs
        x += shortcut
        x = self.relu(x)
        return x

class ResNet(layers.Layer):
    def __init__(self, blocks, filters, kernel_size, strides):
        super(ResNet, self).__init__()
        self.conv = layers.Conv2D(filters, kernel_size, strides=strides, padding='same')
        self.bn = layers.BatchNormalization()
        self.relu = layers.ReLU()
        self.blocks = blocks
        self.res_blocks = [ResidualBlock(filters, kernel_size, strides) for _ in range(blocks)]

    def call(self, inputs, training=False):
        x = self.conv(inputs)
        x = self.bn(x, training=training)
        x = self.relu(x)
        for res_block in self.res_blocks:
            x = res_block(x, training=training)
        return x

inputs = tf.keras.Input(shape=(224, 224, 3))
resnet = ResNet(20, 64, 3, 2)(inputs)
outputs = layers.Dense(10, activation='softmax')(resnet)
model = tf.keras.Model(inputs, outputs)

官方介紹文件

V1版本: https://www.tensorflow.org/api_docs/python/tf/keras/applications/resnet
V2版本: https://www.tensorflow.org/api_docs/python/tf/keras/applications/resnet_v2

好多種ResNet,有甚麼差?

ResNet50, ResNet101, ResNet152 是 TensorFlow 中原始版本的 ResNet 模型,而 ResNet50V2, ResNet101V2, ResNet152V2 是 V2 版本的 ResNet 模型。以下是這些模型之間的主要區別:

  • 深度: ResNet50 的深度為 50 層,ResNet101 的深度為 101 層,ResNet152 的深度為 152 層,V2 版本的深度分別為 50 層,101 層和 152 層。
  • 架構: V2 版本的 ResNet 模型在原始版本的基礎上增加了許多改進,包括使用非常深的層 (bottleneck layer) 來減少參數數量,並在輸入層和輸出層之間使用高密度連接 (dense connection)。
  • 參數數量: V2版本的 ResNet 模型通常具有較少的參數數量,因為它們使用了更高效的架構。
  • 效能: V2版本的 ResNet 模型通常具有更好的效能,因為它們使用了更高效的架構和更少的參數。

總之, 如果要在效能和參數數量之間取得平衡, 使用 V2 版本的 ResNet 模型是個好選擇。
如果效能是優先考量,則可以使用原始版本的 ResNet 模型。

設定ResNet模型超參數

在建立殘差網路 ResNet 的模型時,有一些重要的超參數可以考慮調整,例如:

  • 卷積層數量 (num_blocks):通常來說,越多的卷積層能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定卷積層的數量。
  • 初始濾波器數量 (initial_filters):通常來說,使用較大的濾波器能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定初始濾波器的數量。
  • 激活函數 (activation):激活函數可以對輸入的數據施加非線性轉換,以便讓模型能夠學習更複雜的模式。常見的激活函數包括 ReLU、Sigmoid 和 tanh 等。
  • 優化器 (optimizer):優化器是用來更新模型參數的算法,通常會使用常見的優化器如 SGD、Adam 和 RMSprop 等。
  • 學習率 (learning rate):學習率決定了優化器更新參數的速度。如果學習率過大,則優化器可能會震蕩,無法有效地學習;如果學習率過小,則優化器可能會過慢,學習效率較低。因此可以根據實際的情況選擇合適的學習率。
  • 批次大小 (batch size):批次大小決定了每次更新參數時使用的數據數量。如果批次大小過大,則更新參數的速度會較快,但也有可能導致模型的表現變差;如果批次大小過小,則更新參數的速度會較慢,但也有可能會使模型的表現更好。因此可以根據實際的情況選擇合適的批次大小。
  • 訓練輪數 (epochs):訓練輪數決定了模型在訓練集上訓練的次數。如果訓練輪數過多,則模型有可能會對訓練集過擬合,導致在驗證集上的表現變差;如果訓練輪數過少,則模型可能無法充分學習到訓練集中的模式,導致整體的表現較差。因此可以根據實際的情況選擇合適的訓練輪數。
  • 正規化 (regularization):正規化是指在訓練過程中加入額外的限制,以防止模型過度擬合。常見的正規化方法包括 L1 正規化和 L2 正規化。
  • 丟棄率 (dropout rate):丟棄率是指在訓練過程中隨機丟棄一定比例的神經元,以防止模型過度擬合。
  • 濾波器數量 (filters):濾波器數量決定了每個卷積層使用的濾波器數量。通常來說,使用較多的濾波器能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定濾波器的數量。
  • 卷積層的濾波器大小 (filter size):卷積層的濾波器大小決定了每個卷積層使用的濾波器的大小。通常來說,使用較大的濾波器能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定濾波器的大小。

使用TunableResNet

GitHub位置: https://github.com/keras-team/keras-tuner
官方網站: https://keras.io/keras_tuner/