如何让BiLSTM孪生网络的相似度值(成对距离/余弦)落在0-1区间?
解决孪生网络相似度映射至0-1区间并满足极值要求的方案
问题根源
sigmoid函数的数学特性是输出无限趋近于0/1但永远无法达到,这是导致相同字符串对相似度无法为1的核心原因。针对欧氏距离和余弦相似度的不同取值范围,需要设计不同的映射方式,才能严格满足"相同对为1、不同对为0"的要求。
针对欧氏距离的处理方案
欧氏距离取值范围是[0, +∞),相同样本的距离为0,距离越大样本差异越大。我们可以用指数衰减函数替代sigmoid:
- 当距离为0(相同样本)时,
exp(0)=1,正好满足要求 - 距离增大时,
exp(-x)会平滑趋近于0,符合相似度逻辑 - 可引入可学习的缩放因子
α,让模型自动适配数据的距离分布
针对余弦相似度的处理方案
余弦相似度取值范围是[-1, 1],相同样本相似度为1,完全相反样本为-1。直接通过线性变换映射到[0,1]即可:
- 变换公式:
(x + 1) / 2 - 当x=1时,结果为1;x=-1时,结果为0,严格满足极值要求
修改后的完整代码
class SiameseNetwork(nn.Module): def __init__(self, num_layers, dropout, weight_matrix, vocabs, similarity_measure, alpha=None): super(SiameseNetwork, self).__init__() self.lstm_network = BiLSTM(num_layers, weight_matrix, vocabs) self.fc_drop = nn.Dropout(p=dropout) self.similarity_measure = similarity_measure # 初始化相似度度量模块 if self.similarity_measure == 'euclidean_distance': self.sm = nn.PairwiseDistance(p=2) # 可学习的缩放因子,默认初始为1.0 self.alpha = nn.Parameter(torch.tensor(1.0)) if alpha is None else alpha else: self.sm = nn.functional.cosine_similarity def forward(self, input1, input2): output1 = self.lstm_network(input1) output2 = self.lstm_network(input2) out1 = self.fc_drop(output1) out2 = self.fc_drop(output2) x = self.sm(out1, out2) if self.similarity_measure == 'euclidean_distance': # 指数衰减映射至[0,1]区间 x = torch.exp(-self.alpha * x) else: # 线性变换将余弦相似度映射至[0,1]区间 x = (x + 1) / 2 return x
额外注意事项
- Dropout的影响:训练阶段的dropout随机性会导致相同输入的输出有微小差异,若要在推理时让相同字符串严格输出1,需调用
model.eval()关闭dropout - 损失函数适配:输出已经是
[0,1]区间的数值,二分类任务可直接使用BCELoss作为损失函数 - 可学习α的优势:针对不同数据集的距离分布,模型会自动调整衰减速率,提升适配性
内容的提问来源于stack exchange,提问作者fairy
相关产品推荐
相关产品推荐

