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.
...
構建分類model
import torch
import torch.nn as nn
from torch.nn import TransformerEncoder, TransformerEncoderLayerclass 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 Layersencoder_layers = TransformerEncoderLayer(d_model=embed_size, nhead=nhead)self.transformer_encoder = TransformerEncoder(encoder_layers, num_layers=num_layers)# Fully connected layer for outputself.fc = nn.Linear(embed_size, output_size)def forward(self, x):# Embedding layerembedded = self.embedding(x)# Transformer Encodertransformer_output = self.transformer_encoder(embedded)# Global average poolingpooled = torch.mean(transformer_output, dim=1)# Fully connected layeroutput = self.fc(pooled)return output
from torch.utils.data import Dataset, DataLoaderclass 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}passmodel = 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()
嵌入任務
對于訓練嵌入模型,是否需要使用標簽(label)取決于具體的任務和目標。嵌入模型通常有兩種主要應用場景:
監督學習任務:
目標: 生成的嵌入向量在某個監督學習任務中有用。
訓練方式: 在這種情況下,你可能需要使用標簽,以便在訓練過程中調整模型參數,使生成的嵌入向量對監督學習任務有更好的表現。
示例: 基于用戶行為數據生成用戶嵌入,用于預測用戶行為的監督學習任務。
無監督學習任務:
目標: 生成的嵌入向量本身是任務的目標,而不需要標簽。
訓練方式: 在這種情況下,你可以僅使用輸入數據,無需關聯的標簽。模型被訓練為捕捉數據中的潛在結構,使得相似的輸入在嵌入空間中更接近。
示例: Word2Vec、FastText等無監督學習嵌入模型,它們通過學習輸入數據的上下文信息生成嵌入。
在實際應用中,根據任務需求選擇是否使用標簽。如果嵌入向量在監督學習任務中發揮作用,那么使用標簽進行監督訓練通常是有意義的。如果目標是學習數據的結構或生成通用的嵌入表示,那么可以在無監督或自監督的設置中進行訓練,無需標簽。
監督學習任務
import torch
import torch.nn as nn
import torch.optim as optimclass 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()
label組織形式
embedding_vector1\tlabel1
embedding_vector2\tlabel2
embedding_vector3\tlabel1
embedding_vector4\tlabel3
...
非監督 學習任務(在大模型應用時,此處為常用任務)
訓練基礎示意代碼:數據集中的每個樣本只包含輸入數據,模型的目標是學習將輸入數據映射到嵌入向量。
這種訓練的目標是學習一個映射函數,能夠將輸入數據映射到一個嵌入向量空間。通過最小化均方差損失,我們迫使模型生成的嵌入向量在這個空間中更接近于真實輸入數據。
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_indextokens = 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()
indexed_text是一個樣本對應的預處理后的文本表示,outputs是模型生成的嵌入向量。損失計算時,使用均方差損失來比較模型生成的嵌入向量和原始文本的表示。在實際應用中,需要更復雜的嵌入模型結構和更復雜的文本預處理邏輯。
優化:考慮使用更復雜的嵌入模型,可能包括多層、多頭注意力等結構,以提高模型的表示能力,這樣的結構可能使模型能夠更好地捕捉輸入序列的復雜關系。
5.embedding在檢索任務和生成任務中的區別
在文本生成任務中,通常采用的是對每個token進行embedding,生成的向量維度是(序列長度,embedding大小)。這是因為對于一個給定的序列,嵌入模型將每個token映射為一個固定大小的嵌入向量。整個序列的嵌入表示是通過將每個token的嵌入向量按序列順序連接起來形成的。這個嵌入表示通常被送入生成模型,比如循環神經網絡(RNN)或Transformer,用于生成下一個token。
對于生成嵌入向量的任務,嵌入模型是對整個句子進行embedding,生成的向量是一個單一的向量,維度為(1,embedding大小)。這個向量的目標是捕捉整個句子的語義信息,可以用于后續任務,比如文本分類、聚類等。