keras中siamese的實現

近期由於項目需要學習了一下Siamese網絡,並用keras簡單實現,現總結兩種寫法如下:

1.keras 序貫模型

input_shape = (105, 105, 1)
left_input = Input(input_shape)
right_input = Input(input_shape)
#build convnet to use in each siamese 'leg'
convnet = Sequential()
convnet.add(Conv2D(64,(10,10),activation='relu',input_shape=input_shape,
                   kernel_initializer=W_init,kernel_regularizer=l2(2e-4)))
convnet.add(MaxPooling2D())
convnet.add(Conv2D(128,(7,7),activation='relu',
                   kernel_regularizer=l2(2e-4),kernel_initializer=W_init,bias_initializer=b_init))
convnet.add(MaxPooling2D())
convnet.add(Conv2D(128,(4,4),activation='relu',kernel_initializer=W_init,kernel_regularizer=l2(2e-4),bias_initializer=b_init))
convnet.add(MaxPooling2D())
convnet.add(Conv2D(256,(4,4),activation='relu',kernel_initializer=W_init,kernel_regularizer=l2(2e-4),bias_initializer=b_init))
convnet.add(Flatten())
convnet.add(Dense(4096,activation="sigmoid",kernel_regularizer=l2(1e-3),kernel_initializer=W_init,bias_initializer=b_init))

#call the convnet Sequential model on each of the input tensors so params will be shared
encoded_l = convnet(left_input)
encoded_r = convnet(right_input)
#layer to merge two encoded inputs with the l1 distance between them
L1_layer = Lambda(lambda tensors:K.abs(tensors[0] - tensors[1]))
#call this layer on list of two input tensors.
L1_distance = L1_layer([encoded_l, encoded_r])
prediction = Dense(1,activation='sigmoid',bias_initializer=b_init)(L1_distance)
siamese_net = Model(inputs=[left_input,right_input],outputs=prediction)

該siamese網絡參考 https://sorenbouma.github.io/blog/oneshot/

2.函數式模型

由於項目需要應將siamese的每個支路設置爲densenet

而densenet不是多個網絡層的簡單線性堆疊,無法寫成序貫模型的形式,因此使用函數式模型

input_shape = (4096,1)
left_input = Input(input_shape)
right_input = Input(input_shape)
dense_net = DenseNet121(k=32,conv_kernel_width=3,bottleneck_size=4,transition_pool_size=2,transition_pool_stride=2,theta=0.5,
    initial_conv_width=7,initial_stride=2,initial_filters=64,initial_pool_width=3,initial_pool_stride=2,use_global_pooling=True)
encoded_l = dense_net(left_input)
encoded_r = dense_net(right_input)
# layer to merge two encoded inputs with the l1 distance between them

L1_layer = Lambda(lambda tensors:K.abs(tensors[0] - tensors[1]))
# call this layer on list of two input tensors.
L1_distance = L1_layer([encoded_l, encoded_r])
prediction = Dense(1,activation='sigmoid',bias_initializer=b_init)(L1_distance)
siamese_net = Model(inputs=[left_input,right_input],outputs=prediction)

因爲不能確定這樣寫,siamese的每個支路是否完全共享權重(在github上找到的基於keras的siamese均是採用序貫模型)

設計了一個小實驗,假設siamese的每個支路爲一層全連接層,利用model.summary()打印了模型參數

input_shape = (200,)
left_input = Input(input_shape)
right_input = Input(input_shape)

model = Dense(50,input_shape = input_shape,activation='sigmoid',kernel_regularizer=l2(1e-3),kernel_initializer=W_init,bias_initializer=b_init)
encoded_l = model(left_input)
encoded_r = model(right_input)
# layer to merge two encoded inputs with the l1 distance between them

L1_layer = Lambda(lambda tensors:K.abs(tensors[0] - tensors[1]))
# call this layer on list of two input tensors.
L1_distance = L1_layer([encoded_l, encoded_r])
prediction = Dense(1,activation='sigmoid',bias_initializer=b_init)(L1_distance)
siamese_net = Model(inputs=[left_input,right_input],outputs=prediction)

可以看出訓練的參數個數10101,只是一個支路的參數量,網絡是共享權重的。

ps:keras官方文檔中有關於共享層的實現
http://keras-cn.readthedocs.io/en/latest/getting_started/functional_API/

與本文(2)寫法一致

官方文檔還是要好好看啊。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章