为什么在做文本向量嵌入的时候,还需要再调一次 大模型呢
问题
为什么在做文本向量嵌入的时候,还需要再调一次 大模型呢?如下的代码,请解释原因?
from langchain_community.llms import Ollama #导入ollama包
from langchain_core.prompts import ChatPromptTemplate #提示词
from langchain_core.output_parsers import StrOutputParser #输出解析器
# from langchain_community.embeddings import GPT4AllEmbeddings #文本嵌入模型
# from langchain.document_loaders import TextLoader
# 文件加载
from langchain_community.document_loaders import TextLoader
# 文档分割
from langchain.text_splitter import CharacterTextSplitter
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 选用OpenAIEmbeddings作为embedding模型
# from langchain.embeddings.openai import OpenAIEmbeddings
# from langchain.embeddings.ollama import OllamaEmbeddings
from langchain_community.embeddings import OllamaEmbeddings
if __name__ == '__main__':
try:
# -------- 示例 1 RAG(检索增强生成)------
# 1、加载文本
loader = TextLoader('./doc.txt', encoding='utf-8')
doc = loader.load()
print(doc)
# 2、分割文档
text_spliter = RecursiveCharacterTextSplitter(chunk_size=128,
chunk_overlap=0,
separators=["\n"])
# 拆分文档
documents = text_spliter.split_documents(doc)
print(documents)
# ------------ 文本向量嵌入 (embedding) -----------
# 接下来对分割后的数据进行embedding,并写入数据库。
from langchain_community.vectorstores import FAISS
embedding = OllamaEmbeddings(model="llama3.1")
docsearch = FAISS.from_documents(documents, embedding)
res = docsearch.similarity_search("风险管理")
print(res)
# 配置提示词
#prompt = ChatPromptTemplate.from_template("《三国演义》{topic} 介绍")
# 通过ollama远程获取千问7b模型
# model = Ollama(model="qwen:7b", base_url="http://192.168.3.122:11435")
# 加载本地LLM
#model = Ollama(model="llama3.1") # 这里选gpu、cpu负担小的0.5b模型
#output_parser = StrOutputParser()
#chain = prompt | model | output_parser # 组成一条链
#res = chain.invoke({"topic": "曹操"})
# -------- 示例 2 RAG(检索增强生成)------
#print(res)
except Exception as e:
print(f"发生了错误:{e}")
原因
在你的示例代码中,文本向量嵌入过程中的大模型调用主要是为了生成更具语义信息的向量表示(embeddings),从而帮助更好地进行语义匹配和检索。具体来说,嵌入大模型的使用主要解决以下几个问题:
1. 高质量的语义表示
在自然语言处理中,词汇、短语或段落之间的语义相似性并不能简单通过词语本身的表面相似性来衡量。例如,两个句子虽然在字面上差异较大,但在语义上可能非常接近。这时需要通过大模型(如Llama等)的语义嵌入技术,将文本转化为向量表示。这些向量捕捉到了更深层的语义关系,能够更好地反映语义上的相似性。
2. 向量化以便检索
将文本转化为向量的目的,是为了能够将大规模文档存储在高效的向量数据库(如FAISS)中,从而实现基于向量相似度的检索。当用户输入查询时,大模型将查询转化为同样的向量形式,然后通过计算查询向量和文档向量之间的相似度(如余弦相似度)来找到最相关的结果。
3. 从原始文本到语义向量的过程
虽然文本已经通过分割成了较小的文档块(chunk),但这些文档块只是原始的字符或词汇序列,它们没有被转换为向量形式,无法进行有效的相似性计算。嵌入大模型通过对这些文本块的向量化处理,将它们转化为机器可以理解和操作的高维空间中的点。这一步骤为后续的相似性检索提供了必要的基础。
代码解析:
-
加载与分割文档:
你将一个大文本分割成了小块,以便后续处理。每个块虽然被分割出来,但仍然是原始的自然语言表示。 -
嵌入生成:
使用OllamaEmbeddings
模型对分割后的文本块进行嵌入,模型会为每个文本块生成相应的向量。 -
基于向量的相似性检索:
FAISS 是一个高效的向量检索库,它可以根据用户输入的查询向量,在嵌入后的文档中找到与之最相似的文本块。
因此,再次调用大模型的原因是在生成语义嵌入时,我们需要借助大模型强大的语言理解能力,把文本转化为有意义的向量表示,从而在语义层面上进行更有效的匹配和检索。
可以不用借助大模型来生成 向量数据库的内容吗?请给出说明?
是的,可以在不使用大模型的情况下生成向量数据库的内容,但是这通常会影响到文本向量嵌入的语义质量和检索效果。以下是几种替代方式及其特点:
1. 传统的基于词汇的表示方法
不使用大模型的情况下,通常会采用词袋模型(Bag of Words, BoW)、词频-逆文档频率(TF-IDF)等传统的文本表示方法。这些方法主要基于词汇的统计特征,而不是语义特征。它们不生成高维语义向量,而是基于词的频率来表示文本。
- 词袋模型(BoW):每个文档被表示为词汇的频率向量,没有考虑词与词之间的顺序和语义关系。这种方法简单,但在处理多义词或同义词时效果较差,无法捕捉到深层次的语义信息。
-
TF-IDF:通过调整词频来衡量词汇在文档中的重要性。相比词袋模型,它在特定词的重要性上有一定的改进,但仍然不能很好地捕捉语义相似性。
优点:计算简单,适用于规模较小的数据集和基本的关键词检索。
缺点:语义理解能力较弱,不能有效处理同义词、多义词或上下文信息。
2. 预训练的词嵌入模型
如果不使用像 LLaMA 这样的复杂大模型,也可以选择预训练的词嵌入模型(如 Word2Vec、GloVe、FastText),这些模型通过上下文关系来生成词汇的向量表示,但并不依赖大规模的神经网络推理。
- Word2Vec:通过上下文信息训练的词向量模型,将词映射到一个固定的向量空间。相近的词会有类似的向量。
- GloVe:通过统计信息生成词嵌入,捕捉到词与词之间的共现关系。
-
FastText:扩展了 Word2Vec,它不仅生成单词的嵌入,还将单词分解为多个子词,因此对未见过的词也能生成有效的嵌入。
优点:这些模型可以在不使用大型神经网络的情况下生成有意义的词向量,嵌入速度快,计算开销小。
缺点:虽然能够捕捉词的语义,但其嵌入是基于词级别的,对文档、段落或复杂语义信息的捕捉不如现代大模型。
3. 自定义的小型神经网络模型
如果不想依赖外部的大模型,也可以训练自己的小型神经网络模型,将文本转化为向量。例如,使用浅层的卷积神经网络(CNN)或长短时记忆网络(LSTM)进行文本的表示,这种方式可以控制模型的大小和复杂性。
优点:可以根据具体任务进行定制,适合特定领域的语义理解。
缺点:需要一定的训练数据和时间,效果取决于模型的训练质量和数据的丰富性。
结论:
可以不用大模型来生成向量数据库内容,尤其是可以通过传统的词汇表示方法或者预训练的词嵌入模型来替代。但大模型(如 BERT、GPT、LLaMA 等)的嵌入表示具有更高的语义理解能力,特别是在处理复杂查询和大规模数据时,它们提供了更精确的语义检索效果。如果任务场景对语义理解要求较高,使用大模型嵌入仍是当前最佳实践。
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)