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)写法一致

官方文档还是要好好看啊。。。。

猜你喜欢

转载自blog.csdn.net/huowa9077/article/details/81082795