- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我目前正在尝试在 Keras 中实现 siamese-net,我必须在其中实现以下损失函数:
loss(p ∥ q) = Is · KL(p ∥ q) + Ids · HL(p ∥ q)
detailed description of loss function from paper
其中 KL 是 Kullback-Leibler 散度,HL 是 Hinge-loss。
在训练过程中,我将相同说话人对标记为 1,将不同说话人标记为 0。
目标是使用经过训练的网络从频谱图中提取嵌入。频谱图是一个二维 numpy 数组 40x128(时间 x 频率)
问题是我从来没有超过 0.5 的准确度,当对说话人嵌入进行聚类时,结果显示嵌入和说话人之间似乎没有相关性
我将 kb-divergence 实现为距离度量,并相应地调整 hinge-loss:
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], 1
def kb_hinge_loss(y_true, y_pred):
"""
y_true: binary label, 1 = same speaker
y_pred: output of siamese net i.e. kullback-leibler distribution
"""
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。 base-network的架构如下:
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 repo
我想弄清楚我是否做出了任何错误的假设以及如何提高我的准确性。
最佳答案
请注意,在您的模型中:
y_true
= 标签y_pred
= kullback-leibler 散度这两个不能比较,看这个例子:
For correct results, when
y_true == 1
(same speaker), Kullback-Leibler isy_pred == 0
(no divergence).
因此,完全可以预料到指标无法正常工作。
然后,您要么创建自定义指标,要么仅根据损失进行评估。
此自定义指标需要进行一些调整才能可行,如下所述。
This might be a problem
首先,请注意您在 Kullback-Leibler 的值中使用了 clip
。这可能很糟糕,因为剪辑丢失了剪辑区域中的渐变。由于您的激活是 PRelu
,因此您的值小于 0 且大于 1。然后肯定会有零梯度情况,存在卡住模型的风险。
因此,您可能不想裁剪这些值。为了避免 PRelu
出现负值,您可以尝试使用 'softplus'
激活,这是一种没有负值的软 relu。您也可以“求和”一个 epsilon 以避免麻烦,但保留大于 1 的值没有问题:
#considering you used 'softplus' instead of 'PRelu' in speakers
def kullback_leibler_divergence(speakers):
x, y = speakers
x = x + ks.backend.epsilon()
y = y + ks.backend.epsilon()
return ks.backend.sum(x * ks.backend.log(x / y), axis=-1)
This IS a problem
另请注意,Kullback-Leibler 不是对称函数,并且其最小值也不为零!!完美匹配为零,但糟糕的匹配可能具有更低的值,这对损失函数不利,因为它会驱使你发散。
See this picture showing KB's graph
您的论文指出您应该对两个损失求和:(p||q) 和 (q||p)。
这消除了 assimetry 和负值。
所以:
distance1 = ks.layers.Lambda(kullback_leibler_divergence,
name='distance1')([processed_a, processed_b])
distance2 = ks.layers.Lambda(kullback_leibler_divergence,
name='distance2')([processed_b, processed_a])
distance = ks.layers.Add(name='dist_add')([distance1,distance2])
This might be a problem
最后,看到铰链损失也将值限制在零以下!
由于 Kullback-Leibler 不限于 1,因此具有高发散性的样本可能不受此损失的控制。不确定这是否真的是一个问题,但您可能想要:
mean
而不是 sum
softplus
而不是 max
,以避免丢失梯度。 参见:
MARGIN = someValue
hinge = ks.backend.mean(ks.backend.softplus(MARGIN - y_pred), axis=-1)
这不是很容易,因为我们对告诉我们“正确/不正确”的知识库没有明确的限制
您可以随机尝试一个,但您需要调整此 threshold
参数,直到找到代表现实的好东西。例如,您可以使用您的验证数据来找到带来最佳准确性的阈值。
def customMetric(y_true_targets, y_pred_KBL):
isMatch = ks.backend.less(y_pred_KBL, threshold)
isMatch = ks.backend.cast(isMatch, ks.backend.floatx())
isMatch = ks.backend.equal(y_true_targets, isMatch)
isMatch = ks.backend.cast(isMatch, ks.backend.floatx())
return ks.backend.mean(isMatch)
关于python - siamese-net 中的自定义组合铰链/kb-divergence 损失函数无法生成有意义的说话人嵌入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53581298/
我试图理解 Haskell 2010 Report section 3.17.2 “模式匹配的非正式语义”。其中大部分与模式匹配成功或失败相关似乎很简单,但是我很难理解被描述为模式匹配“发散”的情况。
我最近开始使用一台新机器,在我早些时候在 Github 上在线解决了一些问题而忘记 pull 之后,试图推送到一个分支时注意到并注意到了这个错误提示。 所以我 pull 了,通常当我这样做时,我会得到
我想知道是否有任何涵盖 RSI-Divergence 的 Python 库(快速和慢速之间的差异 RSI )或有关如何在 Python 中实现其算法的任何指导。 已提问:Programmaticall
我创建了一个小示例程序来尝试找出为什么没有编译更大的程序。 val o1: Ordered[Int] = 1 val o2: Ordered[Int] = 2 println(o1 java.lan
其他答案建议使用"-Xlog-implicits"选项来调试“发散的隐式扩展”错误。但是,它还会在与这些错误无关的位置记录很多隐式内容。有什么方法可以限制它仅解释产生编译错误的地方吗? 最佳答案 如果
在从 mallet 中的各种文档中获得各种概率分布后,我应用以下代码来计算第一个和第二个文档之间的 KL 散度: Maths.klDivergence(double[] d1,doub
我有两个 GMM,用于在同一空间中拟合两组不同的数据,我想计算它们之间的 KL 散度。 目前我正在使用 sklearn ( http://scikit-learn.org/stable/modules
我有这个数据: df <- data.frame(x = 1:10, y = 1:10, value = c(seq(from =
我需要构建一个轴标题,其中字符串左对齐和字符串右对齐。 我尝试使用 css 样式作为标题文本属性,但它不起作用: Highcharts.chart('container', { xAxis:
介绍 我正在尝试构建一个 GLM,根据鱼群的大小和年龄来模拟鱼群所产卵的数量(质量)。 因此,变量是: eggW:产蛋总质量,连续正变量,范围在 300 到 30000 之间。 fishW:鱼的质量,
我在 github 上有一个开源的 ruby 项目,我的 master 分支代表已经发布的内容,我的 dev 分支代表接下来要发布的内容。 master 分支在 dev 分支后面有 80 多个提交
我目前正在尝试在 Keras 中实现 siamese-net,我必须在其中实现以下损失函数: loss(p ∥ q) = Is · KL(p ∥ q) + Ids · HL(p ∥ q) detail
假设我有以下情况: 有一个用户 Foo 的主要存储库。 User Bar fork 这个存储库,所以两个存储库是同步的。现在用户 Bar 实现了一个特性并创建了一个名为“barbranch”的本地分支
在下面的代码中,我尝试使用 shapeless 派生类型类实例。但是,在更复杂的 case 类(转换为更复杂的 HList)的情况下,编译器给了我一个“发散的隐式扩展”,即使它似乎没有两次解析同一种隐
我想知道List(3,2,1).toIndexedSeq.sortBy(x=>x)为什么不起作用: scala> List(3,2,1).toIndexedSeq.sortBy(x=>x) // Wr
def MyFun(result: ListBuffer[(String, DateTime, List[(String, Int)])]): String = { val json = (r
我正在努力学习 Scala for the Impatient 并努力为第 10 章第二个练习的解决方案编写测试:通过将 scala.math.Ordered[Point] 混合到 java.awt.
我的情况:warp 中的每个线程都在其自己完全独立且不同的数据数组上运行。所有线程循环遍历它们的数据数组。每个线程的循环迭代次数不同。 (这会产生成本,我知道)。 在for循环中,每个线程计算完三个
使用以下代码,我在 Scala 2.10 中遇到“发散隐式扩展”错误,即使有一种独特的方式来构造隐式: class Foo { trait Foo[A] abstract class Bar[
当我使用 克隆远程存储库时 git clone 'repo_url' git pull git status 我收到这条消息 - On branch master Your branch and 'o
我是一名优秀的程序员,十分优秀!