開篇的這張圖代表ILSVRC歷年的Top-5錯誤率,我會按照以上經典網絡出現的時間順序對他們進行介紹,同時穿插一些其他的經典CNN網絡。
前言時間來到2016年,也就是ResNet被提出的下一年,清華的黃高(也是DenseNet的提出者)在EECV會議上提出了Stochastic Depth(隨機深度網絡)。這個網絡主要是針對ResNet訓練時做了一些優化,即隨機丟掉一些層,優化了速度和性能(有點類似於Dropout的效果?)。論文原文見附錄。
背景ResNet這個裡程碑式的創新對AI領域帶來了深遠的影響。然而,作者發現ResNet網絡中不是所有的層都是必要的,因此結合經典的Dropout思想提出在訓練過程中隨機丟棄丟掉一些層來優化ResNet的訓練過程。(PS:這不就是把Dropout用到網絡層這個單位嗎?)
結構首先來看一下原始的ResNet結構,其中
如下圖所示:
Stochastic Depth(隨機深度網絡)就是在訓練時加入了一個隨機變量
上面提到
論文選擇了第二種設置方式,即將線性衰減規律應用於每一層的生存概率的設置,這是因為較早的層會提取低級特徵,而這些低級特徵會被後面的特徵應用,因此前面的層不應該頻繁的被丟棄,最終
論文中提到,將原始的ResNet模型調整為隨機深度網絡之後,期望深度為原始ResNet的
在測試過程中,所有的殘差塊都保持被激活的狀態,以充分利用整個網絡的所有參數。但每個殘差塊的權重都要根據其在訓練中的生存概率
論文將ResNet的普通版和Stochastic_Depth版在CIFAR 10/100和SVHN做了實驗。首先作者和其他當時的SOTA網絡在CIFAR10和CIFAR100上的錯誤率做了一個對比,如Table1所示:
訓練過程中的測試錯誤率曲線隨著Epoch數的變化情況如下:
下面的Table2展示了在相同數據集上訓練ResNet的訓練時間,隨機深度網絡比原始的ResNet有25%左右的訓練速度提升。
在這裡插入圖片描述為什麼隨機深度網絡有效?從實驗結果可以看到,隨機深度網絡的精度比ResNet更高,證明了其具有更好的泛化能力,這是為什麼呢?論文中的解釋是,不激活一部分殘差模塊事實上提現了一種模型融合的思想(和dropout解釋一致),由於訓練時模型的深度隨機,預測時模型的深度確定,實際是在測試時把不同深度的模型融合了起來。不過在查閱資料時我發現了另外一種解釋,覺得也是有道理的,我貼一下截圖。原始文章來自:https://zhuanlan.zhihu.com/p/31200098。
在這裡插入圖片描述代碼實現隨機深度網絡中的將原始的殘差模塊替換為下面的帶丟棄的單元即可,原始的可訓練的代碼見附錄。
def residual_drop(x, input_shape, output_shape, strides=(1, 1)):
global add_tables
nb_filter = output_shape[0]
conv = Convolution2D(nb_filter, 3, 3, subsample=strides,
border_mode="same", W_regularizer=l2(weight_decay))(x)
conv = BatchNormalization(axis=1)(conv)
conv = Activation("relu")(conv)
conv = Convolution2D(nb_filter, 3, 3,
border_mode="same", W_regularizer=l2(weight_decay))(conv)
conv = BatchNormalization(axis=1)(conv)
if strides[0] >= 2:
x = AveragePooling2D(strides)(x)
if (output_shape[0] - input_shape[0]) > 0:
pad_shape = (1,
output_shape[0] - input_shape[0],
output_shape[1],
output_shape[2])
padding = K.zeros(pad_shape)
padding = K.repeat_elements(padding, K.shape(x)[0], axis=0)
x = Lambda(lambda y: K.concatenate([y, padding], axis=1),
output_shape=output_shape)(x)
_death_rate = K.variable(death_rate)
scale = K.ones_like(conv) - _death_rate
conv = Lambda(lambda c: K.in_test_phase(scale * c, c),
output_shape=output_shape)(conv)
out = merge([conv, x], mode="sum")
out = Activation("relu")(out)
gate = K.variable(1, dtype="uint8")
add_tables += [{"death_rate": _death_rate, "gate": gate}]
return Lambda(lambda tensors: K.switch(gate, tensors[0], tensors[1]),
output_shape=output_shape)([out, x])
後記隨機深度網絡就講到這裡了,我下線了。。
附錄論文原文:https://arxiv.org/abs/1603.09382v1?utm_content=bufferbf6d7&utm_medium=social&utm_source=twitter.com&utm_campaign=bufferKeras代碼實現:https://github.com/dblN/stochastic_depth_keras卷積神經網絡學習路線往期文章歡迎關注我的微信公眾號GiantPandaCV,期待和你一起交流機器學習,深度學習,圖像算法,優化技術,比賽及日常生活等。