### 自定义组合铰链/KB-散度损失函数在孪生网络中无法生成有意义的说话人嵌入

我目前正在尝试在Keras中实现一个孪生网络,需要实现以下损失函数:

loss(p ∥ q) = Is · KL(p ∥ q) + Ids · HL(p ∥ q)

论文中损失函数的详细描述

其中KL是Kullback-Leibler散度,HL是铰链损失(Hinge-loss)。

在训练过程中,我将同一个说话人的配对标记为1,不同说话人的配对标记为0。

目标是使用训练好的网络从频谱图中提取嵌入。频谱图是一个40×128(时间 x 频率)的二维numpy数组。

问题是我从未超过0.5的准确率,并且在聚类说话人嵌入时,结果显示嵌入和说话人之间似乎没有相关性。

我实现了KB-散度作为距离度量,并相应地调整了铰链损失:

def kullback_leibler_divergence(vects):    x, y = vects    x = ks.backend.clip(x, ks.backend.epsilon(), 1)    y = ks.backend.clip(y, ks.backend.epsilon(), 1)    return ks.backend.sum(x * ks.backend.log(x / y), axis=-1)def kullback_leibler_shape(shapes):    shape1, shape2 = shapes    return shape1[0], 1def kb_hinge_loss(y_true, y_pred):    """    y_true: 二进制标签,1 = 相同说话人    y_pred: 孪生网络的输出,即Kullback-Leibler分布    """    MARGIN = 1.    hinge = ks.backend.mean(ks.backend.maximum(MARGIN - y_pred, 0.), axis=-1)    return y_true * y_pred + (1 - y_true) * hinge

一个频谱图将被输入到基础网络的一个分支中,孪生网络由两个这样的分支组成,因此同时输入两个频谱图,并在距离层中连接。基础网络的输出为1 x 128。距离层计算Kullback-Leibler散度,其输出被输入到kb_hinge_loss中。基础网络的架构如下:

    def create_lstm(units: int, gpu: bool, name: str, is_sequence: bool = True):        if gpu:            return ks.layers.CuDNNLSTM(units, return_sequences=is_sequence, input_shape=INPUT_DIMS, name=name)        else:            return ks.layers.LSTM(units, return_sequences=is_sequence, input_shape=INPUT_DIMS, name=name)def build_model(mode: str = 'train') -> ks.Model:    topology = TRAIN_CONF['topology']    is_gpu = tf.test.is_gpu_available(cuda_only=True)    model = ks.Sequential(name='base_network')    model.add(        ks.layers.Bidirectional(create_lstm(topology['blstm1_units'], is_gpu, name='blstm_1'), input_shape=INPUT_DIMS))    model.add(ks.layers.Dropout(topology['dropout1']))    model.add(ks.layers.Bidirectional(create_lstm(topology['blstm2_units'], is_gpu, is_sequence=False, name='blstm_2')))    if mode == 'extraction':        return model    num_units = topology['dense1_units']    model.add(ks.layers.Dense(num_units, name='dense_1'))    model.add(ks.layers.advanced_activations.PReLU(init='zero', weights=None))    model.add(ks.layers.Dropout(topology['dropout2']))    num_units = topology['dense2_units']    model.add(ks.layers.Dense(num_units, name='dense_2'))    model.add(ks.layers.advanced_activations.PReLU(init='zero', weights=None))    num_units = topology['dense3_units']    model.add(ks.layers.Dense(num_units, name='dense_3'))    model.add(ks.layers.advanced_activations.PReLU(init='zero', weights=None))    num_units = topology['dense4_units']    model.add(ks.layers.Dense(num_units, name='dense_4'))    model.add(ks.layers.advanced_activations.PReLU(init='zero', weights=None))    return model

然后我按照以下方式构建孪生网络:

    base_network = build_model()    input_a = ks.Input(shape=INPUT_DIMS, name='input_a')    input_b = ks.Input(shape=INPUT_DIMS, name='input_b')    processed_a = base_network(input_a)    processed_b = base_network(input_b)    distance = ks.layers.Lambda(kullback_leibler_divergence,                                output_shape=kullback_leibler_shape,                                name='distance')([processed_a, processed_b])    model = ks.Model(inputs=[input_a, input_b], outputs=distance)    adam = build_optimizer()    model.compile(loss=kb_hinge_loss, optimizer=adam, metrics=['accuracy'])

最后,我构建了一个具有相同架构的网络,但只有一个输入,并尝试提取嵌入,然后对它们进行平均处理,其中一个嵌入应作为说话人的代表,用于聚类期间使用:

utterance_embedding = np.mean(embedding_extractor.predict_on_batch(spectrogram), axis=0)

我们使用voxceleb说话人数据集训练网络。

完整代码可在此查看:GitHub仓库

我正在尝试找出是否有任何错误的假设以及如何提高我的准确性。


回答:

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注