分享Embedding 模型微调的实现

写在前面

\1. 当前比较主流的Embedding开源模型有哪些?
答:1. m3e(Moka Massive Mixed Embedding) 2. BAAI/bge-large-zh-v1.5。更多的开源模型评测榜单可见:
https://huggingface.co/spaces/mteb/leaderboard

\2. 模型的作用?
答:通过词,句子或者上下文的向量生成,从而来实现更高效的语义检索,语言理解的相关任务。

\3. 模型是如何捕获语义信息的?
答:在训练的过程中,模型学习用来反映语义相似性的方式将向量分配给单词或序列。简言之,通过分析数据中的词共现模式来实现。

\4. 为什么需要对Embedding 模型进行微调?
答:因为稀疏性的问题,在垂类数据下微调,可以得到更好的效果。

领域微调实现

如何从0-1的训练一个Embedding model 可以参考智源的论文:
https://arxiv.org/pdf/2309.07597.pdf,从中我们可以看到如果需要一个特定的领域向量模型,那么就需要这个行业的相关文本,和特定任务的文本对。例如某一个医学问题及其对应的内容的文本对。

这篇文章将从文本对的构建和微调上进行展开。

数据构建:

在通常情况下,我们可以比较容易的获取到一些垂类相关的无监督文本,比如:垂类书籍,论文等来源。难的是获取文本对,以往这些数据都是依赖于开源或者人工标注,但现在有了另一种解决方案,LLM生成文本对。

具体的做法是:
\1. 解析垂类数据,比如:pdf,docx等格式
\2. 将数据进行chunk 切分。
\3. 用LLM对每一个chunk 生成N个问题(或者生成简要的摘要),从而组合成文本对。

接下来是代码实现:

# coding=utf-8
import json

from llama_index import SimpleDirectoryReader
from llama_index.node_parser import SimpleNodeParser
from llama_index.schema import MetadataMode

def load_corpus(files):
    reader = SimpleDirectoryReader(input_files=files)    
    docs = reader.load_data()       
     
    parser = SimpleNodeParser.from_defaults()    
    nodes = parser.get_nodes_from_documents(docs, show_progress=True)    
    
    corpus = {node.node_id: node.get_content(metadata_mode=MetadataMode.NON
### 如何对Embedding模型进行微调 对于大型语言模型中的嵌入(embedding)部分,微调可以通过多种方式实现。一种有效的方法是Prefix Tuning,该方法旨在减少大模型微调的成本并简化过程[^1]。 #### Prefix Tuning简介 Prefix Tuning涉及向现有模型架构中引入额外的学习组件——前缀序列(prefix sequence)。此序列被设计成可以捕捉到特定任务的信息,并且仅这部分参数会在训练期间更新。这不仅降低了整体计算需求,而且有助于保留原始模型的知识迁移能力。 #### 微调的具体步骤 为了利用Prefix Tuning来优化基于embedding模型: - **准备数据集**:收集适合目标任务的数据样本集合。 - **初始化前缀模块**:创建一个新的小型神经网络结构用于生成前缀token embeddings。可以选择多层感知机(MLP)或其他简单有效的RNN变体如LSTM等[^3]。 ```python import torch.nn as nn class PrefixModel(nn.Module): def __init__(self, prefix_length=10, hidden_dim=768): super().__init__() self.prefix_encoder = nn.Sequential( nn.Linear(prefix_length * hidden_dim, hidden_dim), nn.ReLU(), nn.LayerNorm(hidden_dim) ) def forward(self, batch_size): # Generate random noise as input for the encoder prefix_input = torch.randn(batch_size, self.prefix_encoder[0].in_features).to(next(self.parameters()).device) # Encode into a set of continuous vectors (prefix tokens) prefix_tokens = self.prefix_encoder(prefix_input) return prefix_tokens.unsqueeze(dim=1) ``` - **组合原生与新添部件**:将上述构建好的前缀连接至原有Transformer编码器之前的位置,在输入实际文本之前先传递给模型处理过的前缀信息。 - **冻结大部分权重**:除了新增加的部分外,保持其余所有参数不变即不参与反向传播更新操作,从而确保只专注于改进目标领域内的表现而不破坏通用特性[^2]。 - **执行标准监督学习流程**:采用常规的方式定义损失函数、选择合适的优化算法完成整个系统的端到端训练过程[^4]。 #### 注意事项 当实施这类方案时需要注意几个方面: - 前缀长度的选择应当谨慎考虑资源消耗和预期效果之间的平衡; - 新增子网的设计不宜太过复杂以免造成过拟合现象发生; - 训练初期可能需要更多探索性的超参调节工作以找到最佳配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值