[DL]Calculate Parameter Numbers of MLP & CNN

Posted by John on 2018-09-30
Words 2.2k and Reading Time 9 Minutes
Viewed Times

往最近在上CNN的課程,對於如何計算Layers之間要訓練的參數數量有更加清楚的理解,於是想發一篇文章將這些數量到底如何推出的記錄下來,順便證明我還活著只是久久沒發文:-(

簡介

透過Keras來搭建簡易的NN模型,並透過code和執行結果解釋層和層之間的訓練參數數量如何得來。

程式碼分析 - Fully Connection Layer

首先會先利用幾個Case來分析全連接層的參數數量到底怎麼計算的,全連接層的意思就是每個neural彼此之間都有一條線(weight)相連,聽不懂的話下面case有簡潔的醜陋的圖形可以看看。

首先import待會需要的東西(可能不會全部用到)

1
2
from keras.models import Sequential
from keras.layers import Conv2D, MaxPool2D, Flatten, Dropout, Dense, Activation,GlobalMaxPooling2D

Case 1

1
2
3
model = Sequential()
model.add(Dense(units=10, input_shape = (1,)))
model.summary()

會得到:

_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_4 (Dense) (None, 10) 20
=================================================================
Total params: 20
Trainable params: 20
Non-trainable params: 0
_________________________________________________________________

這個架構簡單看就是長這樣(畫得很醜):

IMG_20180930_011605.jpg

輸入是一個數字,所以只有一個neural,輸出層有10個layer(第一層我們稱為input layer,最後一層被稱為output layer),而第二層neural的值來自於第一層,公式為

$y = wx + b$

x是輸入,w和b是我們要學習的參數,所以有10個neural就有10個w和b,10 + 10 = 20。


Case 2.

1
2
3
4
model = Sequential()
model.add(Dense(units=1024, input_shape = (10,)))
model.add(Dense(units=1))
model.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_5 (Dense) (None, 1024) 11264
_________________________________________________________________
dense_6 (Dense) (None, 1) 1025
=================================================================
Total params: 12,289
Trainable params: 12,289
Non-trainable params: 0
_________________________________________________________________

圖形架構是:

IMG_20180930_013224

input layer有10個neurals,中間有一層1024個neurals,由於是全連接層,所以輸入層和中間層之間總共會有10 * 1024 + 1024(bias) = 11264個參數要學。

同樣地,中間層和輸出層的數量計算為 1024 * 1 + 1(bias) = 1025個參數。

而Total params就是11264 + 1025 = 12289


到這邊相信聰明的大家已經發現計算的方式,對於Layer A 和 Layer B之間的參數數量計算公式為:

(# of unitA) * (# of unit B) + (# of unit B)

所以對於Full Connection Layer,不管多深的網路,我們都可以簡單算出要訓練的參數了,參數的數量大大的影響著訓練一個模型的時間。

程式碼分析 - Convolution Layer

了解原理後其實FC Layer的計算就很簡單了,再來看比較複雜一點的,在做CNN時用到的Convoluation Layer參數又是怎麼計算的呢?

Case 3

1
2
3
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(3, 3), input_shape=(32, 32, 1), activation='relu', padding='same'))
model.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_2 (Conv2D) (None, 32, 32, 32) 320
=================================================================
Total params: 320
Trainable params: 320
Non-trainable params: 0
_________________________________________________________________

解釋一下Conv2D的參數,我有一張32*32的黑白圖(因為只有一個channel,也就是32*32*1的1)

filters=32和kernel_size=(3, 3)代表我使用32組3*3的filter來做convolution,至於convolution怎麼做不是這裡的重點,請自行Google。

怎麼理解Param #的320?

想一下做CNN的時候我們要訓練的是什麼,我們沒有FC的neurals,我們要訓練的是filter的值。在影像處理中,已經有許多知名的filter可以達到不同的效果,例如找出圖片邊緣,模糊圖片,去除雜訊……,但在神經網路裡我們希望讓機器自動學習我們應該使用什麼樣的filter,也就是說,每個filter的值就是要被訓練的參數。

這個case有32組filter,每張大小為3*3,所以32 * (3*3) = 288…好像不太對???

別忘了還有bias,每個filter我們都給予一個bias,所以32 (33) + 32 = 320。


Case 4

最後來個大魔王,結合更多不同的Layer:

1
2
3
4
5
6
7
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(3, 3), input_shape=(32, 32, 3), activation='relu', padding='same'))
model.add(MaxPool2D())
model.add(Dropout(0.2))
model.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='same'))
model.add(Flatten())
model.summary()

_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_15 (Conv2D) (None, 32, 32, 32) 896
_________________________________________________________________
max_pooling2d_7 (MaxPooling2 (None, 16, 16, 32) 0
_________________________________________________________________
dropout_6 (Dropout) (None, 16, 16, 32) 0
_________________________________________________________________
conv2d_16 (Conv2D) (None, 16, 16, 32) 9248
_________________________________________________________________
flatten_1 (Flatten) (None, 8192) 0
=================================================================
Total params: 10,144
Trainable params: 10,144
Non-trainable params: 0
_________________________________________________________________

這次的輸入是彩色32*32的圖,為甚麼呢?因為在實際上,彩色的圖會被分層紅色(R)的一張,綠色的(G)一張,藍色的(B)一張,所以輸入才會是(32, 32, 3)。

既然圖片被分層RGB每個顏色各有一張32*32的圖,那我們又要怎麼做convolution呢?如果敵人開影分身,我們也使用影分身就好了,所以我們一組filter數量實際上是3*3大小的filter有3張,分別對R、G、B去做convolution,當初我一直卡在這裡是因為被kernel_size=(3, 3)的意思給誤解了。

好所以現在一組filter有三層(RGB),每層的大小是3*3,也就是說一組filter的參數有3*3*3=27個,而我們有32組(filters=32),加上每組有一個bias,所以總共是(3*3*3) * 32 + 32 = 896。

並且因為我有32組,做完之後我會得到32個32*32的data(因為有做padding,這裡不多贅述),所以可以看到第一個convolution layer的output shape是(32, 32, 32)。

再來看下一個Convolution Layer,其他的先跳過,注意在第二個Convolution Layer前一層的output shape為(None, 16, 16, 32),也就是說我們有16*16的圖片,有32層(這邊已經有點難理解實際上圖片呈現會長怎樣了)。

按照剛剛說過的,我們有3*3的filter,但是對方影分身變成32層了,所以我們就跟著影分身吧!!所以現在3*3的filter有的32個(層),(3*3) * 32這樣稱為一組filter,我們有32組,所以總共有(3*3) * 32 * 32 + 32 = 9248個要訓練的參數。

我們可以發現Maxpooling()和Flatten()並不會有要訓練的參數,因為pooling就只是從data中取區域最大值,不需要訓練;flatten則是將weights鋪平(reshape),也不會更動到參數的數量。


結論

Full Connection Layer 和 Convolution Layer的參數計算就到這邊,總結一下結論:

  • Full Connection Layer的參數數量與兩層之間的neural個數有關,neural數量越多,要訓練的參數數量越多。
  • Convolution Layer的參數數量與filter大小、數量,以及data的channel(有幾張)有關,與data的大小(shape)無關。由於Convolution Layer參數相較FC少很多,所以不太需要加Dropout(在進入下一層Layer之前隨機捨棄一定比例的weights,常用在FC,用來防止overfitting),也有人提出使用全部都是Convolution Layer的神經網路模型架構來減少訓練的負擔。

>