iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
AI & Data

AI Facial Expression Recognition: Data, Model, Application系列 第 11

[Day 11] 從零開始的 DenseNet 生活

0. 進度條

模型 進度
VGG Net (完成)
ResNet (完成)
DensNet (此篇)
MobileNet (未完成)
EfficientNet (未完成)

0.1 前言

大家都知道模型越深就越有潛力達到更高的準確率。
但是隨著深度增加,梯度消失的問題就更嚴重,
ResNet的設計就是用來減緩這個問題,
而DenseNet就是在ResNet的基礎上去做改良。


1. DenseNet 網路架構

01
DenseNet 全名為 Densely Connected Convolutional Network。
由許多個Dense Block組成,每個Block皆採用bottleneck結構。
而Dense Block用了許多「層與層的連結」來達到特徵重用性。

其論文開門見山地說:

Recent work has shown that convolutional networks can be
substantially deeper, more accurate, and efficient to train
if they contain shorter connections
between layers close to the input and those close to the output.

它有最多層與層的連結

這個shorter connections就是指ResNet中的直連通路,
ResNet只是在block的最頂端拉一條線出來,
做identity connection傳到block的最底端。
但是DenseNet更狠!直接讓每一層的輸出傳遞到之後的每一層,
相當於是做了超多次identity connection。
假如我們有L層卷積神經網路,那就有https://chart.googleapis.com/chart?cht=tx&chl=L個(層與層之間的)連結。
但是DenseNet設計成有https://chart.googleapis.com/chart?cht=tx&chl=L%2F(L2%2B1)個連結。
如下圖所示:
02
寫成數學式子就長這樣:
https://chart.googleapis.com/chart?cht=tx&chl=X_l%20%3D%20H(%5BX_0%2CX_1%2CX_2%2C...%2CX_(l-1)%5D)

要升維思考,不要同流合汙

這個所謂「拉一條線出來做連結」其實就是在避免模型太「寬」。
我們可以發現當年的模型基本上都在追求又寬又深(又大又圓),像是GoogLeNet。
但是DenseNet不屑透過加深和加寬網路來增強圖像表徵能力,
DenseNet利用"特徵重用性"來做到這件事。

Growth-rate

這個專有名詞是指卷積層中卷積核的數量(k),
在DenseNet的實驗中發現設k=12也能夠獲得和其他state-of-the-art一樣的效果。
所以DenseNet是可以很「窄」(narrow)的。

1.1 DenseNet優點

  1. 更加減緩梯度消失問題:
    由於Densely connected,反向梯度傳播十分容易,模型收斂效果佳。

  2. 特徵重用性:
    從低階特徵到高階特徵都會被直連到最後一層卷積層,
    這讓下一層接受到更全面的圖像資訊。

  3. 減少參數量:
    這很反直覺,這麼多連結卻減少參數量?
    那是因為對於舊的特徵圖(feature-map)是不需要再去重新學習的,
    而且因為growth-rate不用設很大,所以減少許多參數。

1.2 DenseNet缺點

  1. 對應優點1,反向傳播雖然容易,但是計算複雜。
  2. 對應優點2和3,特徵重用這件事的壞處就是訓練模型時RAM會爆炸。

2. 結語

看起來DenseNet稍微減緩了人們對於模型寬度的追求,
但不得不說,每個人在調整模型架構的時候都是先往加深加寬的方向。
而沒有去考慮用更有效的層與層之間的連接方式。

我想我們應該要去思考:
有沒有一種模型架構是可以容許我們用少少的深度和寬度,
就可以獲得跟DensNet一樣的效果呢?


3. 附錄

因為Dense Block的結構很簡單,
所以我練習用keras實現它,
如果我寫錯了...還請大家幫忙debug/images/emoticon/emoticon25.gif

import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense, BatchNormalization, ReLU
from tensorflow.keras.layers import Concatenate, Dropout
from tensorflow.keras.layers import Conv2D, AveragePooling2D, MaxPooling2D
from tensorflow.keras.layers import GlobalAveragePooling2D


def DenseLayer(x, growthRate, dropRate=0):

    # bottleneck
    x = BatchNormalization(axis=3)(x)
    x = ReLU(x)
    x = Conv2D(4*growthRate, kernel_size=(1, 1), padding='same')(x)

    # composition
    x = BatchNormalization(axis=3)(x)
    x = ReLU(x)
    x = Conv2D(growthRate, kernel_size=(3, 3), padding='same')(x)

    # dropout
    x = Dropout(dropRate)(x)

    return x


def DenseBlock(x, num_layers, growthRate, dropRate=0):

    for i in range(num_layers):
        featureMap = DenseLayer(x, growthRate, dropRate)
        x = Concatenate([x, featureMap], axis=3)

    return x


def TransitionLayer(x, ratio):

    growthRate = int(x.shape[-1]*ratio)
    x = BatchNormalization(axis=3)(x)
    x = ReLU(x)
    x = Conv2D(growthRate, kernel_size=(1, 1),
               strides=(2, 2), padding='same')(x)
    x = AveragePooling2D(pool_size=(2, 2), strides=(2, 2))(x)

    return x


def DenseNet121(numClass=1000, inputShape=(224, 224, 3), growthRate=12):
    x_in = Input(inputShape)
    x = Conv2D(growthRate*2, (3, 3), padding='same')(x_in)
    x = MaxPooling2D(pool_size=(2, 2), strides=(2, 2))(x)

    x = TransitionLayer(DenseBlock(
        x, num_layers=6, growthRate=12, dropRate=0.2))
    x = TransitionLayer(DenseBlock(
        x, num_layers=12, growthRate=12, dropRate=0.2))
    x = TransitionLayer(DenseBlock(
        x, num_layers=24, growthRate=12, dropRate=0.2))
        
    x = DenseBlock(x, num_layers=16, growthRate=12, dropRate=0.2)
    x = GlobalAveragePooling2D()(x)
    x_out = Dense(numClass=1000, activation='softmax')(x)

    model = Model(x_in, x_out)
    model.compile(optimizer=tf.keras.optimizers.Adam(),
                  loss=tf.keras.losses.CategoricalCrossentropy(), metrics=['accuracy'])
    model.summary()
    return model

參考資料

  1. https://arxiv.org/abs/1608.06993

上一篇
[Day 10] 從 tensorflow.keras 開始的 ResNet 生活
下一篇
[Day 12] 從 tensorflow.keras 開始的 MobileNet 生活
系列文
AI Facial Expression Recognition: Data, Model, Application30

尚未有邦友留言

立即登入留言