首页 > 其他分享 >借助chatgpt学习对比学习中的疑惑

借助chatgpt学习对比学习中的疑惑

时间:2023-02-27 11:55:33浏览次数:42  
标签:疑惑 样本 self torch 学习 z2 chatgpt 向量 size

  • 使用pytorch得到对比学习的正负样本,要求是NLP方向,正样本通过dropout(0.1)得到,负样本使用batch内其他样本。同时,帮我用pytorch实现他们的对比学习损失,用simcse的损失

以下是使用 PyTorch 得到对比学习的正负样本,并使用 SIMCSE 损失进行训练的示例代码,假设我们的任务是将一批文本表示为向量,同时使得同一类别的文本向量更加接近,不同类别的文本向量更加分散。

import torch
import torch.nn.functional as F
from torch.utils.data import DataLoader

class ContrastiveDataset(torch.utils.data.Dataset):
    def __init__(self, data, tokenizer, max_length=128):
        self.data = data
        self.tokenizer = tokenizer
        self.max_length = max_length

    def __getitem__(self, index):
        text1 = self.data[index]
        # 50% 的概率将 text1 和 text2 设为同一个文本
        text2 = text1 if torch.rand(1) < 0.5 else self.data[torch.randint(len(self.data), (1,))]
        # 将 text1 和 text2 都转换为输入张量
        input1 = self.tokenizer(text1, padding='max_length', truncation=True, max_length=self.max_length, return_tensors='pt')
        input2 = self.tokenizer(text2, padding='max_length', truncation=True, max_length=self.max_length, return_tensors='pt')

        # 使用 dropout 获取正样本对
        mask = torch.zeros_like(input1['input_ids'])
        mask[:, 1:-1] = torch.rand(input1['input_ids'][:, 1:-1].shape) < 0.1  # dropout 随机将词汇替换为 [MASK]
        input1_masked = input1['input_ids'].clone()
        input1_masked[mask] = self.tokenizer.mask_token_id
        input2_masked = input2['input_ids'].clone()
        input2_masked[mask] = self.tokenizer.mask_token_id
        return input1_masked, input2_masked, torch.tensor(1.0)

    def __len__(self):
        return len(self.data)

class ContrastiveModel(torch.nn.Module):
    def __init__(self, base_model):
        super().__init__()
        self.base_model = base_model

    def forward(self, input_ids):
        outputs = self.base_model(input_ids)
        return outputs.last_hidden_state[:, 0, :]  # 使用 CLS token 作为句子表示

class SimCSELoss(torch.nn.Module):
    def __init__(self, temperature=0.05):
        super().__init__()
        self.temperature = temperature

    def forward(self, z1, z2):
        # 将 z1 和 z2 单位化
        z1 = F.normalize(z1, dim=1)
        z2 = F.normalize(z2, dim=1)
        # 计算 z1 和 z2 的余弦相似度矩阵
        sim_matrix = torch.matmul(z1, z2.t()) / self.temperature
        # 构造同分布的标签,即每个样本的标签为它本身
        batch_size = sim_matrix.size(0)
        labels = torch.arange(batch_size, dtype=torch.long, device=sim_matrix.device)
        # 使用交叉熵损失
        loss = F.cross_entropy(sim_matrix, labels)
        return loss
  • 如何调用SimCSELoss

要在 PyTorch 中使用 SimCSELoss 损失函数,需要先将正样本和负样本分别通过模型前向传播得到它们的向量表示,然后将这些向量表示传递给 SimCSELoss 模块即可。以下是一个示例代码:

import torch
import torch.nn.functional as F

class SimCSELoss(torch.nn.Module):
    def __init__(self, temperature=0.05):
        super().__init__()
        self.temperature = temperature

    def forward(self, z1, z2):
        # 将 z1 和 z2 单位化
        z1 = F.normalize(z1, dim=1)
        z2 = F.normalize(z2, dim=1)
        # 计算 z1 和 z2 的余弦相似度矩阵
        sim_matrix = torch.matmul(z1, z2.t()) / self.temperature
        # 构造同分布的标签,即每个样本的标签为它本身
        batch_size = sim_matrix.size(0)
        labels = torch.arange(batch_size, dtype=torch.long, device=sim_matrix.device)
        # 使用交叉熵损失
        loss = F.cross_entropy(sim_matrix, labels)
        return loss

假设我们已经有了正样本 z1 和负样本 z2 的向量表示,那么我们可以通过以下方式调用 SimCSELoss:

loss_fn = SimCSELoss()
loss = loss_fn(z1, z2)

其中,z1 和 z2 的形状都应该是 (batch_size, embedding_size),分别表示正样本和负样本的向量表示。在这里,embedding_size 表示向量的维度,它应该与模型的最后一层的输出维度相同。在计算损失时,我们只需要将这些向量表示传递给 SimCSELoss 的 forward 方法即可,PyTorch 会自动执行反向传播并更新模型参数。

  • z1和z2是如何得到的

在对比学习中,我们需要构造正负样本对来训练模型,其中正样本对应的是同一条数据的两个不同视角的嵌入向量(例如句子的不同表述或同义词的不同表示),而负样本对应的是来自不同数据的嵌入向量(例如在同一批次中,对于给定的正样本,其它所有样本作为负样本)。

具体地,在 NLP 领域,我们可以使用预训练模型(如 BERT、RoBERTa 等)对每条文本数据进行编码,得到其对应的嵌入向量。对于同一条文本数据,我们可以通过对原始文本进行随机扰动(例如在词级别进行替换或删除),从而得到不同的视角或表述,并使用模型分别编码这些扰动后的文本,即可得到正样本对应的两个嵌入向量。而负样本则可以从同一批次的其它样本中随机选择,使用同样的编码器得到嵌入向量。

在 PyTorch 中,我们可以使用预训练模型(如 transformers 库中的 BERT、RoBERTa 等)对文本数据进行编码,并得到其对应的嵌入向量。例如,对于一批次大小为 batch_size 的文本数据 texts,我们可以使用以下代码获取其嵌入向量:

import torch
import transformers

model_name = "bert-base-uncased"
tokenizer = transformers.BertTokenizer.from_pretrained(model_name)
model = transformers.BertModel.from_pretrained(model_name)

# 将文本转换为模型输入
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
# 对文本进行编码并得到嵌入向量
outputs = model(**inputs)
embeddings = outputs.last_hidden_state

其中,texts 是一个列表,包含了批次中的所有文本数据。通过 tokenizer 将文本转换为模型输入,然后使用 model 对文本进行编码并得到嵌入向量。注意,embeddings 的形状应该是 (batch_size, sequence_length, hidden_size),其中 hidden_size 表示模型最后一层的输出维度,即嵌入向量的维度。我们可以使用 torch.mean 函数对 sequence_length 维度进行平均池化,得到每条文本数据对应的嵌入向量:

# 对每条文本数据进行平均池化,得到其对应的嵌入向量
z = torch.mean(embeddings, dim=1)

最后,我们可以通过对正样本的嵌入向量应用 dropout(在 PyTorch 中可以使用 torch.nn.Dropout 模块)和对批次中其它样本的嵌入向量应用负采样,得到对比学习的正负样本。具体地,在 PyTorch 中,可以使用以下代码实现:

import torch

# 对正样本的嵌入向量应用 dropout
z1 = torch.nn.Dropout(p=0.1)(z)
# 使用负采样得到负样本的嵌入向量
z2_indices = torch.randint(0, batch_size, size=(batch_size,))
z2 = z[z2_indices]

向量应用负采样,得到对比学习的正负样本。具体地,在 PyTorch 中,可以使用以下代码实现:

import torch

# 对正样本的嵌入向量应用 dropout
z1 = torch.nn.Dropout(p=0.1)(z)
# 使用负采样得到负样本的嵌入向量
z2_indices = torch.randint(0, batch_size, size=(batch_size,))
z2 = z[z2_indices]

其中,z 是形状为 (batch_size, hidden_size) 的嵌入向量矩阵,batch_size 表示批次大小,hidden_size 表示嵌入向量的维度。通过对 z 应用 dropout,可以得到正样本的嵌入向量 z1。同时,我们可以使用 torch.randint 函数在 [0, batch_size) 范围内随机采样 batch_size 个整数作为负样本的索引,然后从 z 中获取这些索引对应的嵌入向量,即可得到负样本的嵌入向量 z2。

注意,在上述代码中,由于每个样本可以作为负样本和正样本的对比样本,因此在采样负样本时,我们需要使用 torch.randint 函数而不是 torch.randperm 函数,以保证每个样本都有机会作为负样本出现。此外,在实现中,还需要确保负样本与正样本来自不同的数据,因此在实际使用中,可能需要对代码进行一些修改。

  • 上面那个Dataset的类好像没有必要实现

你说得没错。在我的代码示例中,我演示了如何使用 PyTorch 得到对比学习的正负样本。因此,在实际使用中,可以根据需要进行选择,如果数据已经提前处理好了,那么就不需要再使用 ContrastiveDataset 类了。另外,ContrastiveDataset 类的作用主要是为了方便使用 PyTorch 提供的数据加载和处理函数,可以实现更高效的批次化训练,因此如果不需要这些功能,也可以不使用该类。

标签:疑惑,样本,self,torch,学习,z2,chatgpt,向量,size
From: https://www.cnblogs.com/douzujun/p/17159176.html

相关文章

  • python+playwright 学习-14.导航page.goto(url) 详解
    前言Playwright可以导航到URL并处理由页面交互引起的导航。本篇涵盖了等待页面导航和加载完成的常见场景。导航生命周期导航从更改页面URL或通过与页面交互(例如,单......
  • python基本绘图函数学习
    1.plot绘制线型图plot是python中最基本的绘制二维线性折线图的函数基本使用方式:plt.plot(x,y,s)代码实现:importmatplotlib.pyplotaspltimportnumpyasnpimport......
  • ts 学习笔记
    varmessage:string="HelloWorld"console.log(message)//ts1基础类型任意类型 any 声明为any的变量可以赋予任意类型的值。数字类型 number 双精度64位浮点......
  • 大数据挖掘-python基本绘图函数学习
    1-plot绘制线型图plot是python中最基本的绘制二维线性折线图的函数基本使用方式:plt.plot(x,y,s)代码实现:importmatplotlib.pyplotaspltimportnumpyasnpimport......
  • python画图学习
    1.plot绘制线型图plot是python中最基本的绘制二维线性折线图的函数基本使用方式:plt.plot(x,y,s)importmatplotlib.pyplotaspltimportnumpyasnpimportpandasa......
  • 马哥教育云原生学习笔记
    首先感谢我马哥!1.“云”中的资源在使用者看来是可以随时获取、按需使用、按量付费、按需扩展且能无限扩展的,是类似水电一样的IT基础设施。2.“云原生”的发展历程:......
  • 《分布式技术原理与算法解析》学习笔记Day24
    分布式缓存在计算机领域,缓存是一个非常重要的、用来提升性能的技术。什么是分布式缓存?缓存技术是指用一个更快的存储设备存储一些经常用到的数据,供用户快速访问。分布......
  • 联邦学习论文阅读笔记11 FGFL: A blockchain-based fair incentive governor for Fede
    面对的问题:激励分配不均、攻击者欺骗 方法:提出FGFL模型。1)设计了时间衰减SLM算法度量工作者声誉;2)设计了基于梯度相似度的轻量级方法度量工作者贡献;3)提出了一种公平的激......
  • 免费领取2023年上半年系统集成项目管理工程师重要知识点10G学习资料包
    课课家软考学院为2023年上半年系统集成项目管理工程师考生整理了2023年上半年系统集成项目管理工程师重要知识点10G学习资料的内容,希望能帮助考生掌握系统集成项目管理......
  • python学习1
    importpandasaspdimportnumpyasnpcatering_sale='D:\大三下\大数据实验课\data\catering_sale.xls'data=pd.read_excel(catering_sale,names=['data','sale'])......