在網絡結構的設計上,經常說DenseNet和Inception中更多采用的是concatenate操作,而ResNet更多采用的add操作,那么這兩個操作有什么異同呢?
concatenate操作是網絡結構設計中很重要的一種操作,經常用於將特征聯合,多個卷積特征提取框架提取的特征融合或者是將輸出層的信息進行融合,而add層更像是信息之間的疊加。
This reveals that both DenseNets and ResNets densely aggregate features from prior layers and their essential difference is how features are aggregated: ResNets aggregate features by summation and DenseNets aggregate them by concatenation.
Resnet是做值的疊加,通道數是不變的,DenseNet是做通道的合並。你可以這么理解,add是描述圖像的特征下的信息量增多了,但是描述圖像的維度本身並沒有增加,只是每一維下的信息量在增加,這顯然是對最終的圖像的分類是有益的。而concatenate是通道數的合並,也就是說描述圖像本身的特征增加了,而每一特征下的信息是沒有增加。
在代碼層面就是ResNet使用的都是add操作,而DenseNet使用的是concatenate。
這些對我們設計網絡結構其實有很大的啟發。
通過看keras的源碼,發現add操作,
def _merge_function(self, inputs):
    output = inputs[0]
    for i in range(1, len(inputs)):
        output += inputs[i]
    return output 
        執行的就是加和操作,舉個例子
-  
          import keras
 -  
          
 -  
          input1 = keras.layers.Input(shape=( 16,))
 -  
          x1 = keras.layers.Dense( 8, activation='relu')(input1)
 -  
          input2 = keras.layers.Input(shape=( 32,))
 -  
          x2 = keras.layers.Dense( 8, activation='relu')(input2)
 -  
          added = keras.layers.add([x1, x2])
 -  
          
 -  
          out = keras.layers.Dense( 4)(added)
 -  
          model = keras.models.Model(inputs=[input1, input2], outputs=out)
 -  
          model.summary()
 
打印出來模型結構就是:
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_1 (InputLayer)            (None, 16)           0                                            
__________________________________________________________________________________________________
input_2 (InputLayer)            (None, 32)           0                                            
__________________________________________________________________________________________________
dense_1 (Dense)                 (None, 8)            136         input_1[0][0]                    
__________________________________________________________________________________________________
dense_2 (Dense)                 (None, 8)            264         input_2[0][0]                    
__________________________________________________________________________________________________
add_1 (Add)                     (None, 8)            0           dense_1[0][0]                    
                                                                                 dense_2[0][0]                    
__________________________________________________________________________________________________
dense_3 (Dense)                 (None, 4)            36          add_1[0][0]                      
==================================================================================================
Total params: 436
Trainable params: 436
Non-trainable params: 0
__________________________________________________________________________________________________
這個比較好理解,add層就是接在dense_1,dense_2后面的是一個連接操作,並沒有訓練參數。
相對來說,concatenate操作比較難理解一點。
if py_all([is_sparse(x) for x in tensors]):
    return tf.sparse_concat(axis, tensors)
else:
    return tf.concat([to_dense(x) for x in tensors], axis) 
        通過keras源碼發現,一個返回sparse_concate,一個返回concate,這個就比較明朗了,
concate操作,舉個例子
t1 = [[1, 2, 3], [4, 5, 6]] t2 = [[7, 8, 9], [10, 11, 12]] tf.concat([t1, t2], 0) ==> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] tf.concat([t1, t2], 1) ==> [[1, 2, 3, 7, 8, 9], [4, 5, 6, 10, 11, 12]] # tensor t3 with shape [2, 3] # tensor t4 with shape [2, 3] tf.shape(tf.concat([t3, t4], 0)) ==> [4, 3] tf.shape(tf.concat([t3, t4], 1)) ==> [2, 6]
事實上,是關於維度的一個聯合,axis=0表示列維,1表示行維,沿着通道維度連接兩個張量。另一個sparse_concate則是關於稀疏矩陣的級聯,也比較好理解。
