Advertisement

A-Softmax的keras实现-《SphereFace: Deep Hypersphere Embedding for Face Recognition》

阅读量:

A-Softmax的keras实现

参考文档:https://www.cnblogs.com/heguanyou/p/7503025.html

注:我的写作水平还有待提升,在模型构建过程中采用了批处理机制(batch_size),因此导致编译效率低下;同时普遍认为该方法难以达到良好的收敛效果,在实际应用中表现欠佳;在此基础上建议进一步优化算法设计以改善训练效果

《AM : 基于具有加性边距的Softmax分类器用于面部验证系统》

《AAM : 基于集中坐标学习策略实现的面部识别技术》

《ArcFace: 基于具有加性角边际损失的深度面部识别模型》

具体的理论基础及物理解释参见:
人脸识别中的LOSS(上)
人脸识别中的LOSS(下)
其中我对keras版本的《Additive Margin Softmax for Face Verification》进行了实现工作,请参考<>资源;与A-Softmax算法的主要区别在于输入x也进行了归一化处理,并采用加性margins作为区分依据。

替代了乘性margin:

复制代码
    # -*- coding: utf-8 -*-
    from keras import backend as K
    from keras.engine.topology import Layer
    from keras.layers import Dense, Activation,BatchNormalization
    from keras.layers import activations, initializers, regularizers, constraints, Lambda
    from keras.engine import InputSpec
    import tensorflow as tf
    import numpy as np
    
    
    class ASoftmax(Dense):
    def __init__(self, units, m, batch_size,
                 kernel_initializer='glorot_uniform',
                 kernel_regularizer=None,
                 kernel_constraint=None,
                 **kwargs):
        if 'input_shape' not in kwargs and 'input_dim' in kwargs:
            kwargs['input_shape'] = (kwargs.pop('input_dim'),)
        super(Dense, self).__init__(**kwargs)
        self.units = units
        self.m = m
        self.batch_size = batch_size
        self.kernel_initializer = initializers.get(kernel_initializer)
        self.kernel_regularizer = regularizers.get(kernel_regularizer)
        self.kernel_constraint = constraints.get(kernel_constraint)
        self.input_spec = InputSpec(min_ndim=2)
        self.supports_masking = True
    
    def build(self, input_shape):
        assert len(input_shape) >= 2
        input_dim = input_shape[-1]
    
        self.kernel = self.add_weight(shape=(input_dim, self.units),
                                      initializer=self.kernel_initializer,
                                      name='kernel',
                                      regularizer=self.kernel_regularizer,
                                      constraint=self.kernel_constraint)
        self.bias = None
        self.input_spec = InputSpec(min_ndim=2, axes={-1: input_dim})
        self.built = True
    
    
    def call(self, inputs):
        inputs.set_shape([self.batch_size, inputs.shape[-1]])
        inputs_norm = K.sqrt(K.sum(K.square(inputs), axis=-1, keepdims=True))
        kernel_norm = tf.nn.l2_normalize(self.kernel, dim=(0, 1))                          # W归一化
        inner_product = K.dot(inputs, kernel_norm)
        dis_cosin = inner_product / inputs_norm
    
        m_cosin = multipul_cos(dis_cosin, self.m)
        sum_y = K.sum(K.exp(inputs_norm * dis_cosin), axis=-1, keepdims=True)
        k = get_k(dis_cosin, self.units, self.batch_size)
        psi = np.power(-1, k) * m_cosin - 2 * k
        e_x = K.exp(inputs_norm * dis_cosin)
        e_y = K.exp(inputs_norm * psi)
        sum_x = K.sum(e_x, axis=-1, keepdims=True)
        temp = e_y - e_x
        temp = temp + sum_x
    
        output = e_y / temp
        return output
    
    
    def multipul_cos(x, m):
    if m == 2:
        x = 2 * K.pow(x, 2) - 1
    elif m == 3:
        x = 4 * K.pow(x, 3) - 3 * x
    elif m == 4:
        x = 8 * K.pow(x, 4) - 8 * K.pow(x, 2) + 1
    else:
        raise ValueError("To high m")
    return x
    
    
    def get_k(m_cosin, out_num, batch_num):
    theta_yi = tf.acos(m_cosin)  #[0,pi]
    theta_yi = tf.reshape(theta_yi, [-1])
    pi = K.constant(3.1415926)
    
    def cond(p1, p2, k_temp, theta):
        return K.greater_equal(theta, p2)
    
    def body(p1, p2, k_temp, theta):
        k_temp += 1
        p1 = k_temp * pi / out_num
        p2 = (k_temp + 1) * pi / out_num
        return p1, p2, k_temp, theta
    
    k_list = []
    for i in range(batch_num * out_num):
        k_temp = K.constant(0)
        p1 = k_temp * pi / out_num
        p2 = (k_temp + 1) * pi / out_num
        _, _, k_temp, _ = tf.while_loop(cond, body, [p1, p2, k_temp, theta_yi[i]])
        k_list.append(k_temp)
    k = K.stack(k_list)
    k = tf.squeeze(K.reshape(k, [batch_num, out_num]))
    return k
    
    
    def asoftmax_loss(y_true, y_pred):
    d1 = K.sum(tf.multiply(y_true, y_pred), axis=-1)
    p = -K.log(d1)
    loss = K.mean(p)
    K.print_tensor(loss)
    return p

主文件:

复制代码
    from keras import backend as K
    from keras.layers import Dense,Input,Conv2D,MaxPooling2D,Activation
    from keras.layers.core import Flatten
    from keras.models import Model
    from keras.utils.generic_utils import CustomObjectScope
    from Modify_Softmax import ModifySoftmax
    from A_Softmax import ASoftmax
    
    
    
    with CustomObjectScope({'a_softmax': ASoftmax}):
    x_input = Input(shape=(10, 10, 3))
    y = Conv2D(10,2,activation='relu')(x_input)
    y= MaxPooling2D()(y)
    y = Flatten()(y)
    y = Dense(5)(y)
    #y= Dense(2, activation='relu')(y)
    y = ASoftmax(3, 3, activation='a_softmax')(y)
    
    model = Model(inputs=x_input, outputs=y)
    model.compile(optimizer='sgd',
          loss='categorical_crossentropy',
          metrics=['accuracy'])
    
    model.summary()

全部评论 (0)

还没有任何评论哟~