Python 关于余弦相似性,如何选择损失函数和网络(我有两个方案)

Python 关于余弦相似性,如何选择损失函数和网络(我有两个方案),python,neural-network,pytorch,embedding,cosine-similarity,Python,Neural Network,Pytorch,Embedding,Cosine Similarity,对不起,我不知道该怎么解决。 我使用两个网络来构造两个嵌入,我有一个二进制目标来指示embeddingA和embeddingB是否匹配1或-1。 数据集如下所示: embA0 embB0 1.0 embA1 embB1 -1.0 embA2 embB2 1.0 ... 我希望使用余弦相似性来得到分类结果。 但我在选择损失函数时感到困惑,生成嵌入的两个网络是分开训练的,现在我可以想到以下两个选项: 计划1: 构造第三个网络,使用embeddingA和embeddingB作为nn的输入。余弦相似性

对不起,我不知道该怎么解决。 我使用两个网络来构造两个嵌入,我有一个二进制目标来指示embeddingA和embeddingB是否匹配1或-1。 数据集如下所示:

embA0 embB0 1.0
embA1 embB1 -1.0
embA2 embB2 1.0
...
我希望使用余弦相似性来得到分类结果。 但我在选择损失函数时感到困惑,生成嵌入的两个网络是分开训练的,现在我可以想到以下两个选项:

计划1:

构造第三个网络,使用embeddingA和embeddingB作为nn的输入。余弦相似性计算最终结果应为[-1,1]中的概率,然后选择两类损失函数

对不起,我不知道该选择哪个损失函数

class cos_Similarity(nn.Module):
    def __init__(self):
        super(cos_Similarity,self).__init__()
        cos=nn.CosineSimilarity(dim=2)
        embA=generator_A()
        embB=generator_B()

    def forward(self,a,b):
        output_a=embA(a)
        output_b=embB(b)
        return cos(output_a,output_b)
loss_func=nn.CrossEntropyLoss()

y=cos_Similarity(a,b)
loss=loss_func(y,target)
acc=np.int64(y>0)

计划2: 将两个嵌入作为输出,然后使用nn.CosineMbeddingLoss作为损失函数,当我计算精度时,我使用nn.Cosinesimilarity将结果概率输出为[-1,1]

output_a=embA(a)
output_b=embB(b)

cos=nn.CosineSimilarity(dim=2)
loss_function = torch.nn.CosineEmbeddingLoss()

loss=loss_function(output_a,output_b,target)
acc=cos(output_a,output_b)

我真的需要帮助。我如何做出选择?为什么?或者我只能通过实验结果为自己做出选择。 多谢各位

加成


def train_func(train_loss_list):

    train_data=load_data('train')
    trainloader = DataLoader(train_data, batch_size=BATCH_SIZE)
    
    cos_smi=nn.CosineSimilarity(dim=2)
    train_loss = 0
    
    for step,(a,b,target) in enumerate(trainloader):

        try:
            optimizer.zero_grad()

            output_a = model_A(a) #generate embA
            output_b = model_B(b) #generate embB
            
            acc=cos_smi(output_a,output_b)

            loss = loss_fn(output_a,output_b, target.unsqueeze(dim=1))
            
            train_loss += loss.item()
            
            loss.backward()
            
            optimizer.step()
            
            train_loss_list.append(loss)
            

            if step%10==0:
                print('train:',step,'step','loss:',loss,'acc',acc)
                
                
        except Exception as e:
            print('train:',step,'step')
            print(repr(e))

    return train_loss_list,train_loss/len(trainloader)

作为对注释线程的响应

目标或管道似乎是:

接收两个嵌入向量,比如A和B。 使用余弦相似性检查这两个向量是否相似。 如果它们相似,则标签为1,否则建议将其更改为0或1,而不是-1和1。 我能想到的是以下几点。如果我误解了什么,请纠正我。免责声明是,我几乎是根据我的直觉编写的,不知道任何细节,所以如果你尝试运行,它可能会充满错误。让我们仍然尝试获得高层次的理解

模型 培训/评价
我省略了一些细节,例如超参数值、损失函数和优化器等。。整个过程是否与您正在寻找的OP类似?

您可以使用triplet loss函数进行训练。您的输入是一组嵌入,比如1000行。假设每一个都以200维编码。还有相似性标签。例如,第1行可能与1000行中的20行相似,而dis与其余980行相似。然后,您可以通过每次进行1+ve和1-ve匹配,对第1行使用三重态丢失函数。你可以对火车上的所有1000行这样做。这样,嵌入现在可以更好地进行微调。这是训练阶段

现在,为了进行推断,您可以找出余弦相似性来确定哪些行彼此接近,哪些行不是k最近,其中k=1。我想这就是你的模型的目标


我们在这里假设嵌入是“可转移的”,因为它来自诸如BERT文本或imagenet图像之类的东西,这些嵌入可以通过在顶部添加一层进行微调

您是从其他地方获得代码的吗?如果是这样的话,你能把它链接起来让我看得更清楚吗。一般来说,如果您处理的是二进制分类,那么使用nn.BCELoss可能比使用nn.CrossEntropyLoss更容易。@Seankala我自己编写了代码。。。因为我高估了自己:损失函数非常有用!因为我试图运行plan1,所以模型没有收敛。您使用的是什么数据?我可以尝试并复制您正在尝试做的事情。@Seankala我的项目中有太多的前进步骤,无法生成嵌入。然而,你的想法启发了我。我可以通过模拟一些数据和进行实验来验证哪一个更好?或者我应该使用真实数据。它不一定要与真实数据一起使用,但我建议使用与您使用的数据分布相同的数据。我个人会做的就是取出一小块正在使用的数据并调试模型。您只需确保模型在开始阶段收敛。另外,我不确定您是否有意在示例中省略它,但您应该添加loss.backward和optimizer.step来实际训练模型。非常感谢,我在我的项目中尝试了您的代码并进行了适当的修改,但模型仍然没有收敛。所以我重新筛选了嵌入生成部分,这需要一些时间。期待未来的好消息,再次感谢您的帮助!
import torch
import torch.nn as nn


class Model(nn.Module):
    def __init__(self, num_emb, emb_dim): # I'm assuming the embedding matrices are same sizes.
        self.embedding1 = nn.Embedding(num_embeddings=num_emb, embedding_dim=emb_dim)
        self.embedding2 = nn.Embedding(num_embeddings=num_emb, embedding_dim=emb_dim)
        self.cosine = nn.CosineSimilarity()
        self.sigmoid = nn.Sigmoid()

    def forward(self, a, b):
        output1 = self.embedding1(a)
        output2 = self.embedding2(b)
        similarity = self.cosine(output1, output2)
        output = self.sigmoid(similarity)

        return output
model = Model(num_emb, emb_dim)

if torch.cuda.is_available():
    model = model.to('cuda')

model.train()

criterion = loss_function()
optimizer = some_optimizer()

for epoch in range(num_epochs):
    epoch_loss = 0
    for batch in train_loader:
        optimizer.zero_grad()

        a, b, label = batch

        if torch.cuda.is_available():
            a = a.to('cuda')
            b = b.to('cuda')
            label = label.to('cuda')

        output = model(a, b)

        loss = criterion(output, label)
        loss.backward()
        optimizer.step()

        epoch_loss += loss.cpu().item()

        print("Epoch %d \t Loss %.6f" % epoch, epoch_loss)