关于余弦相似度,如何选择损失函数和网络我有两个计划 型号培训/评估

问题描述

对不起,我不知道,我不知道在哪里找到解决方案。 我正在使用两个网络来构造两个嵌入,我有一个二进制目标来指示embeddingA和embeddingB是否“匹配”(1或-1)。 像这样的数据集:

embA0 embB0 1.0
embA1 embB1 -1.0
embA2 embB2 1.0
...

我希望使用余弦相似度来获得分类结果。 但是在选择损失函数时,我感到困惑,生成嵌入的两个网络是分开训练的,现在我可以想到以下两种选择:

计划1:

构造第三个网络,使用embeddingA和embeddingB作为nn.cosinesimilarity()的输入来计算最终结果(在[-1,1]中应为概率),然后选择一个两类损失函数。 / p>

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

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.CosineEmbeddingLoss()作为损失函数,当我计算精度时,我使用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)

我真的需要帮助。我该如何选择?为什么?或者我只能通过实验结果为我做出选择。 非常感谢!

############################## addition


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,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')
            print(repr(e))

    return train_loss_list,train_loss/len(trainloader)

解决方法

响应评论主题。

目标或管道似乎是:

  1. 接收两个嵌入向量(例如A和B)。
  2. 检查这两个向量是否“相似”(使用余弦相似度)。
  3. 如果标签相似,则标签为1,否则为-1(我建议将其更改为0或1,而不是-1和1)。

我能想到的是以下内容。如果我误解了一些,请纠正我。免责声明是,我几乎是根据我的直觉来编写代码,却不知道任何细节,因此,如果您尝试运行它,可能会充满错误。让我们继续尝试以获得高层次的理解。

型号

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)

我省略了一些详细信息(例如,超参数值,损失函数和优化器等)。这个总体过程与您要寻找的OP相似吗?

,

您可以使用三元组损失函数进行训练。您的输入是一组嵌入(比如 1000 行)。假设每一个都以 200 维编码。你也有相似性标签。所以对于例如第 1 行可能与 1000 行中的 20 行相似,而与其余 980 行不同。然后,您可以通过每次进行 1 +ve 和 1 -ve 匹配来对第 1 行使用三元组损失函数。您可以对火车中的所有 1000 行执行此操作。通过这种方式,嵌入现在可以更好地进行微调。这是训练阶段。

现在进行推理,您只需找出余弦相似度即可确定哪些行彼此接近,哪些不接近(k 最接近,其中 k=1)。我认为这就是您模型的目标。

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