Keras-Tutorial(六)Keras实现Siamese Network

Keras实现Siamese Network

Siamese Architecture是由LeCun在1993年发表的,在2005年LeCun用这种结构来训练人脸比对模型,获得不错结果。

网络介绍

如下图,Siamese的网络结构
Keras-Tutorial(六)Keras实现Siamese Network_第1张图片
* 简单地来说,该网络将来处理一对样本,该对样本经过网络G,如果是同一类的样本,则距离会更近,而不同类别的之间的样本的距离会越来月远。
* 训练阶段,每次都输入两个样本,用两个参数完全一样的的网络对这两个样本进行变换,最后设计一个loss来实现第一点提到的功能。
* Contrastive Loss(对比损失函数):
L(F1,F2,Y)=12Ni=1yiD(F1,F2)2+(1yi)max(0,mD(F1,F2))2 L ( F 1 , F 2 , Y ) = 1 2 ∑ i = 1 N y i D ( F 1 , F 2 ) 2 + ( 1 − y i ) m a x ( 0 , m − D ( F 1 , F 2 ) ) 2
* N是batch的大小,D为每对样本的欧氏距离,y是标签,1为同一类,0为不同类。当为同一类时,则优化D的距离尽量减小。当为不同类别时,则是让 max(0,D(F1,F2))2 m a x ( 0 , D ( F 1 , F 2 ) ) 2 的尽量小。

下面与MLP为基础模型来介绍创建Siamese Network

import numpy as np
import random

import keras.backend as K
from keras.datasets import mnist
from keras.models import Sequential, Model
from keras.layers import Input, Dense, Dropout, Lambda, Conv2D, MaxPooling2D
from keras.optimizers import RMSprop
from keras.callbacks import TensorBoard

# 基础模型
def create_base_network(input_shape):
    model = Sequential()
    model.add(Dense(units=128, input_shape=(input_shape, ), activation='relu'))
    model.add(Dropout(rate=0.5))
    model.add(Dense(units=128, activation='relu'))
    model.add(Dropout(rate=0.5))
    model.add(Dense(units=128, activation='relu'))

    return model

# 计算欧式距离
def euclidean_distance(vects):
    v1, v2 = vects
    return K.sqrt(K.sum(K.square(v1 -v2), axis=1, keepdims=True))

def eucl_dist_output_shape(shapes):
    # 在这里我们需要求修改output_shape, 为(batch, 1)
    shape1, shape2 = shapes
    return (shape1[0], 1)

# 创建contrastive_loss
def contrastive_loss(y_true, y_pred):
    margin = 1
    square_pred = K.square(y_pred)
    margin_square = K.square(K.maximum(margin - y_pred, 0))
    return K.mean(y_true * square_pred + (1 - y_true) * margin_square)

# 创建训练时计算acc的方法
def accuracy(y_true, y_pred):
    return K.mean(K.equal(y_true, K.cast(y_pred < 0.5, y_true.dtype)))

base_network = create_base_network(input_shape)

# 因为模型是以两个张量作为输入,然后将它们连接在以上的base_network,再输出一个结果
input_a = Input(shape=(input_shape, ))
input_b = Input(shape=(input_shape, ))

# 获取经过模型后的输出
processed_a = base_network(input_a)  
processed_b = base_network(input_b)

# 这里在创建一个Lambda层,用于计算base_network输出的两个特征的欧氏距离,并且不含有可训练参数的计算要求
distance = Lambda(function=euclidean_distance, output_shape=eucl_dist_output_shape)([processed_a, processed_b])

model = Model(inputs=[input_a, input_b], outputs=distance)

msprop = RMSprop()
model.compile(optimizer=rmsprop, loss=contrastive_loss, metrics=[accuracy])

# 这里省略部分代码
model.fit(....)

[详细参考代码: https://github.com/Gary-Deeplearning/Keras-Tutorial]

你可能感兴趣的:(Keras)