当前位置:   article > 正文

embedding的原理和结构_embedding原理

embedding原理

embedding(向量化)是一个将数据转化为向量矩阵的过程,作用是:将高维稀疏向量转化为稠密向量,从而方便下游模型处理

简单的概念大家应该都知道了,以LLM为例
输入:文字
模型:embedding
输出:向量

我疑惑的难点主要为以下:
1.embedding的结构√
2.embedding的训练(根据不同的目标进行数据不同的组织形式,进行相对应任务的训练,可以看结构想到)
3.embedding的难点以及各种模型的优势(未解决)
4.embedding的技术原理(回归任务,根据离散token回归,帮助在得到一个新的语句时,生成对应的向量。)
5.embedding在检索任务和生成任务中的区别√

1.embedding的结构

对于嵌入模型,输出可以是两种常见形式之一:

类别概率分布: 如果你的任务是分类,模型的最后一层通常会输出每个类别的概率分布。这时,你可以使用交叉熵损失作为目标函数,模型的输出是对各个类别的概率预测。

嵌入向量: 如果你的任务是生成嵌入向量,模型的最后一层可能输出样本的嵌入表示。这时,你可以使用均方差损失(Mean Squared Error, MSE)或其他适当的损失函数,目标是使生成的嵌入向量接近于真实的嵌入。

分类任务

在分类任务中,一般来说,模型的最后一层输出类别概率分布更为常见。这是因为使用类别概率分布作为输出,可以直接使用交叉熵损失函数,它在多类别分类问题中效果良好。

#label
label1\tThis is a positive sentence.
label2\tNegative sentiment detected in this text.
label1\tThe product works well and meets my expectations.
label3\tI don't like the design of the app.
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

构建分类model

import torch
import torch.nn as nn
from torch.nn import TransformerEncoder, TransformerEncoderLayer

class TransformerEmbeddingModel(nn.Module):
    def __init__(self, vocab_size, embed_size, nhead, num_layers):
        super(TransformerEmbeddingModel, self).__init__()
        
        self.embedding = nn.Embedding(vocab_size, embed_size)
        
        # Transformer Encoder Layers
        encoder_layers = TransformerEncoderLayer(d_model=embed_size, nhead=nhead)
        self.transformer_encoder = TransformerEncoder(encoder_layers, num_layers=num_layers)
        
        # Fully connected layer for output
        self.fc = nn.Linear(embed_size, output_size)

    def forward(self, x):
        # Embedding layer
        embedded = self.embedding(x)
        
        # Transformer Encoder
        transformer_output = self.transformer_encoder(embedded)
        
        # Global average pooling
        pooled = torch.mean(transformer_output, dim=1)
        
        # Fully connected layer
        output = self.fc(pooled)
        
        return output
from torch.utils.data import Dataset, DataLoader

class TextDataset(Dataset):
    def __init__(self, data_path):
        # 从文件加载数据集
        self.data = self.load_data(data_path)

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

    def __getitem__(self, idx):
        return self.data[idx]['text'], self.data[idx]['label']

    def load_data(self, data_path):
        # 实现从文件加载数据的逻辑,返回一个包含文本和标签的列表
        # 例如,每个样本可以表示为 {'text': 'This is a sentence.', 'label': 1}
        pass

model = TransformerEmbeddingModel(vocab_size, embed_size, nhead, num_layers, output_size)

# 交叉熵损失函数
criterion = nn.CrossEntropyLoss()

# 优化器(例如Adam)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# 示例数据加载逻辑
def load_data(self, data_path):
    data = []
    with open(data_path, 'r', encoding='utf-8') as file:
        for line in file:
            label, text = line.strip().split('\t')
            data.append({'text': text, 'label': int(label)})
    return data

# 示例训练过程
for epoch in range(num_epochs):
    for input_data, labels in dataloader:
        # 模型前向传播
        outputs = model(input_data)
        
        # 计算损失
        loss = criterion(outputs, labels)
        
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

嵌入任务

对于训练嵌入模型,是否需要使用标签(label)取决于具体的任务和目标。嵌入模型通常有两种主要应用场景:
监督学习任务
目标: 生成的嵌入向量在某个监督学习任务中有用。
训练方式: 在这种情况下,你可能需要使用标签,以便在训练过程中调整模型参数,使生成的嵌入向量对监督学习任务有更好的表现。
示例: 基于用户行为数据生成用户嵌入,用于预测用户行为的监督学习任务。
无监督学习任务
目标: 生成的嵌入向量本身是任务的目标,而不需要标签。
训练方式: 在这种情况下,你可以仅使用输入数据,无需关联的标签。模型被训练为捕捉数据中的潜在结构,使得相似的输入在嵌入空间中更接近。
示例: Word2Vec、FastText等无监督学习嵌入模型,它们通过学习输入数据的上下文信息生成嵌入。
在实际应用中,根据任务需求选择是否使用标签。如果嵌入向量在监督学习任务中发挥作用,那么使用标签进行监督训练通常是有意义的。如果目标是学习数据的结构或生成通用的嵌入表示,那么可以在无监督或自监督的设置中进行训练,无需标签。

监督学习任务
import torch
import torch.nn as nn
import torch.optim as optim

class EmbeddingModel(nn.Module):
    def __init__(self, input_size, embedding_size, output_size):
        super(EmbeddingModel, self).__init__()
        self.fc = nn.Linear(input_size, embedding_size)
        self.output_layer = nn.Linear(embedding_size, output_size)

    def forward(self, x):
        x = self.fc(x)
        embedding_vector = torch.relu(x)  # 示例中使用了ReLU激活函数
        output = self.output_layer(embedding_vector)
        return output

# 参数设置
input_size = 100  # 输入维度
embedding_size = 50  # 嵌入向量维度
output_size = 1  # 输出维度,可以根据任务需求调整

# 创建模型实例
model = EmbeddingModel(input_size, embedding_size, output_size)

# 选择均方差损失函数
criterion = nn.MSELoss()

# 选择优化器(例如Adam)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# 示例数据集加载逻辑
def load_data(self, data_path):
    data = []
    with open(data_path, 'r', encoding='utf-8') as file:
        for line in file:
            embedding_vector, label = line.strip().split('\t')
            embedding_vector = [float(value) for value in embedding_vector.split(',')]
            label = float(label)
            data.append({'embedding_vector': torch.tensor(embedding_vector), 'label': torch.tensor(label)})
    return data

# 创建数据集实例
data_path = "path/to/your/data.txt"
dataset = EmbeddingDataset(data_path)

# 创建数据加载器
batch_size = 32
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

# 模型训练
for epoch in range(num_epochs):
    for sample in dataloader:
        input_data, labels = sample['embedding_vector'], sample['label']
        
        # 模型前向传播
        outputs = model(input_data)
        
        # 计算均方差损失
        loss = criterion(outputs, labels.view(-1, 1))  # 保持形状一致
        
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

label组织形式

embedding_vector1\tlabel1
embedding_vector2\tlabel2
embedding_vector3\tlabel1
embedding_vector4\tlabel3
...
  • 1
  • 2
  • 3
  • 4
  • 5
非监督 学习任务(在大模型应用时,此处为常用任务)

训练基础示意代码:数据集中的每个样本只包含输入数据,模型的目标是学习将输入数据映射到嵌入向量。
这种训练的目标是学习一个映射函数,能够将输入数据映射到一个嵌入向量空间。通过最小化均方差损失,我们迫使模型生成的嵌入向量在这个空间中更接近于真实输入数据。

import torch
import torch.nn as nn
import torch.optim as optim

# 示例嵌入模型
class TextEmbeddingModel(nn.Module):
    def __init__(self, vocab_size, embed_size):
        super(TextEmbeddingModel, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embed_size)

    def forward(self, x):
        embedded = self.embedding(x)
        embedding_vector = torch.mean(embedded, dim=1)  # 简单地取平均作为嵌入向量
        return embedding_vector

# 参数设置
vocab_size = 10000  # 假设有10000个词
embed_size = 50    # 假设嵌入向量维度为50

# 创建模型实例
model = TextEmbeddingModel(vocab_size, embed_size)

# 选择均方差损失
criterion = nn.MSELoss()

# 选择优化器(例如Adam)
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 示例数据集加载逻辑
def load_data(data_path):
    data = []
    with open(data_path, 'r', encoding='utf-8') as file:
        for line in file:
            data.append(line.strip())
    return data

# 示例文本预处理逻辑
def preprocess_text(text, word_to_index):
    # 假设已经建立了词到索引的映射表 word_to_index
    tokens = text.split()
    indexed_tokens = [word_to_index[word] for word in tokens]
    return torch.tensor(indexed_tokens)

# 创建数据集实例
data_path = "path/to/your/data.txt"
data = load_data(data_path)

# 示例词到索引的映射
word_to_index = {"This": 0, "is": 1, "a": 2, "positive": 3, "sentence": 4, ...}

# 预处理文本数据
indexed_data = [preprocess_text(text, word_to_index) for text in data]

# 创建数据加载器
batch_size = 32
dataloader = DataLoader(indexed_data, batch_size=batch_size, shuffle=True)

# 模型训练
for epoch in range(num_epochs):
    for indexed_text in dataloader:
        # 模型前向传播
        outputs = model(indexed_text)
        
        # 计算均方差损失
        loss = criterion(outputs, indexed_text.float())  # 输入数据需要是浮点型
        
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

indexed_text是一个样本对应的预处理后的文本表示,outputs是模型生成的嵌入向量。损失计算时,使用均方差损失来比较模型生成的嵌入向量和原始文本的表示。在实际应用中,需要更复杂的嵌入模型结构和更复杂的文本预处理逻辑。
优化:考虑使用更复杂的嵌入模型,可能包括多层、多头注意力等结构,以提高模型的表示能力,这样的结构可能使模型能够更好地捕捉输入序列的复杂关系。

5.embedding在检索任务和生成任务中的区别

在文本生成任务中,通常采用的是对每个token进行embedding,生成的向量维度是(序列长度,embedding大小)。这是因为对于一个给定的序列,嵌入模型将每个token映射为一个固定大小的嵌入向量。整个序列的嵌入表示是通过将每个token的嵌入向量按序列顺序连接起来形成的。这个嵌入表示通常被送入生成模型,比如循环神经网络(RNN)或Transformer,用于生成下一个token。

对于生成嵌入向量的任务,嵌入模型是对整个句子进行embedding,生成的向量是一个单一的向量,维度为(1,embedding大小)。这个向量的目标是捕捉整个句子的语义信息,可以用于后续任务,比如文本分类、聚类等。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号