赞
踩
本笔记为【动手学大模型应用开发】https://datawhalechina.github.io/llm-universe/,DataWhale 六月组队学习的 llm-universe - 202406 的 任务三打卡笔记。
笔记首次发表在 我的个人网站 www.jiewong.com
大模型对于输入语言的处理 ,首先要经过分词,其次要经过向量化,输入的句子才会到大模型。
Tokenizer,即分词器,是将输入文本分解为更小单元(token)的工具。这些token可以是单词、子词(subword)、字符或其他单位。在大语言模型中,Tokenizer是文本预处理阶段的核心,因为模型不能直接处理原始文本字符串。
不同类型的Tokenizer包括:
在Tokenizer中,vocabulary size(词汇量)是指tokenizer使用的词汇表(vocabulary)中所包含的唯一token的总数。每个token都是一个独特的符号或字符串片段,代表输入文本的基本单元。词汇表中的token可以是单词、子词、字符或其他形式的表示。
在文本经过Tokenizer处理后,得到的token序列会通过Embedding Layer转换为高维向量。Embedding Layer是一个查找表,将每个token ID映射到一个向量表示。这些向量捕捉了token的语义信息,使模型能够在高维空间中处理这些token。
在机器学习和自然语言处理(NLP)中,词向量(Embeddings)是一种将非结构化数据,如单词、句子或者整个文档,转化为实数向量的技术。这些实数向量可以被计算机更好地理解和处理。
嵌入背后的主要想法是,相似或相关的对象在嵌入空间中的距离应该很近。
举个例子,我们可以使用词嵌入(word embeddings)来表示文本数据。在词嵌入中,每个单词被转换为一个向量,这个向量捕获了这个单词的语义信息。例如,“king” 和 “queen” 这两个单词在嵌入空间中的位置将会非常接近,因为它们的含义相似。而 “apple” 和 “orange” 也会很接近,因为它们都是水果。而 “king” 和 “apple” 这两个单词在嵌入空间中的距离就会比较远,因为它们的含义不同。
在RAG(Retrieval Augmented Generation,检索增强生成)方面词向量的优势主要有两点:
在搭建 RAG 系统时,我们往往可以通过使用嵌入模型来构建词向量,我们可以选择:
向量数据库是用于高效计算和管理大量向量数据的解决方案。向量数据库是一种专门用于存储和检索向量数据(embedding)的数据库系统。它与传统的基于关系模型的数据库不同,它主要关注的是向量数据的特性和相似性。
在向量数据库中,数据被表示为向量形式,每个向量代表一个数据项。这些向量可以是数字、文本、图像或其他类型的数据。向量数据库使用高效的索引和查询算法来加速向量数据的存储和检索过程。
向量数据库中的数据以向量作为基本单位,对向量进行存储、处理及检索。向量数据库通过计算与目标向量的余弦距离、点积等获取与目标向量的相似度。当处理大量甚至海量的向量数据时,向量数据库索引和查询算法的效率明显高于传统数据库。
import json import types from tencentcloud.common import credential from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException from tencentcloud.hunyuan.v20230901 import hunyuan_client, models from dotenv import load_dotenv import os try: # 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 # 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 # 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 load_dotenv() # 加载环境变量 SecretId = os.getenv("SecretId") SecretKey = os.getenv("SecretKey") cred = credential.Credential(SecretId, SecretKey) # 实例化一个http选项,可选的,没有特殊需求可以跳过 httpProfile = HttpProfile() httpProfile.endpoint = "hunyuan.tencentcloudapi.com" # 实例化一个client选项,可选的,没有特殊需求可以跳过 clientProfile = ClientProfile() clientProfile.httpProfile = httpProfile # 实例化要请求产品的client对象,clientProfile是可选的 client = hunyuan_client.HunyuanClient(cred, "", clientProfile) # 实例化一个请求对象,每个接口都会对应一个request对象 req = models.GetEmbeddingRequest() params = { "Input": "你好" } req.from_json_string(json.dumps(params)) # 返回的resp是一个GetEmbeddingResponse的实例,与请求对象对应 resp = client.GetEmbedding(req) # 输出json格式的字符串回包 print(resp.to_json_string()) except TencentCloudSDKException as err: print(err)
返回了一大堆内容
{"Data": [{"Embedding": [-0.0013065338134765625, -0.01026153564453125, 0.0185089111328125, -0.012054443359375, -0.03179931640625, -0.016082763671875, 0.0194854736328125, 0.019195556640625, -0.029754638671875, -0.00955963134765625, -0.000446319580078125, 0.03619384765625, -0.11041259765625, 0.029266357421875, -0.011444091796875, -0.028778076171875, -0.01357269287109375, 0.0029888153076171875, -0.028350830078125, 0.04351806640625, 省略
, 0.0304107666015625], "Index": 0, "Object": "embedding"}], "Usage": {"PromptTokens": 3, "TotalTokens": 3}, "RequestId": "063627d8-0b27-4285-a803-97143ad92a72"}
查看 Data 的 Object
data = json.loads(resp.to_json_string())
print(data["Data"][0]["Object"])
返回
embedding
查看embedding长度、前10、token使用情况
print(f'embedding长度为:{len(data["Data"][0]["Embedding"])}')
print(f'embedding(前10)为:{data["Data"][0]["Embedding"][:10]}')
print(f'本次token使用情况:{data["Usage"]}')
embedding长度为:1024
embedding(前10)为:[-0.0013065338134765625, -0.01026153564453125, 0.0185089111328125, -0.012054443359375, -0.03179931640625, -0.016082763671875, 0.0194854736328125, 0.019195556640625, -0.029754638671875, -0.00955963134765625]
本次token使用情况:{'PromptTokens': 3, 'TotalTokens': 3}
pip install langchain
pip install -U langchain-community
pip install pymupdf # pdf
pip install unstructured # markdown
选用 Datawhale 一些经典开源课程作为示例
#旧版 from langchain.document_loaders.pdf import PyMuPDFLoader
from langchain_community.document_loaders import PyMuPDFLoader
# 创建一个 PyMuPDFLoader Class 实例,输入为待加载的 pdf 文档路径
loader = PyMuPDFLoader("./data_base/knowledge_db/pumkin_book/pumpkin_book.pdf")
# 调用 PyMuPDFLoader Class 的函数 load 对 pdf 文件进行加载
pdf_pages = loader.load()
print(f"载入后的变量类型为:{type(pdf_pages)},", f"该 PDF 一共包含 {len(pdf_pages)} 页")
pdf_page = pdf_pages[1]
print(f"每一个元素的类型:{type(pdf_page)}.",
f"该文档的描述性数据:{pdf_page.metadata}",
f"查看该文档的内容:\n{pdf_page.page_content}",
sep="\n------\n")
from langchain_community.document_loaders import UnstructuredMarkdownLoader
loader = UnstructuredMarkdownLoader("./data_base/knowledge_db/prompt_engineering/1. 简介 Introduction.md")
md_pages = loader.load()
print(f"载入后的变量类型为:{type(md_pages)},", f"该 Markdown 一共包含 {len(md_pages)} 页")
md_page = md_pages[0]
print(f"每一个元素的类型:{type(md_page)}.",
f"该文档的描述性数据:{md_page.metadata}",
f"查看该文档的内容:\n{md_page.page_content[0:][:200]}",
sep="\n------\n")
# pdf删除换行符\n
import re
pattern = re.compile(r'[^\u4e00-\u9fff](\n)[^\u4e00-\u9fff]', re.DOTALL)
pdf_page.page_content = re.sub(pattern, lambda match: match.group(0).replace('\n', ''), pdf_page.page_content)
print(pdf_page.page_content)
# pdf·删除空格
pdf_page.page_content = pdf_page.page_content.replace('•', '')
pdf_page.page_content = pdf_page.page_content.replace(' ', '')
print(pdf_page.page_content)
# markdown删除多余换行符\n
md_page.page_content = md_page.page_content.replace('\n\n', '\n')
print(md_page.page_content)
from langchain.text_splitter import RecursiveCharacterTextSplitter # 知识库中单段文本长度 CHUNK_SIZE = 500 # 知识库中相邻文本重合长度 OVERLAP_SIZE = 50 # 使用递归字符文本分割器 text_splitter = RecursiveCharacterTextSplitter( chunk_size=CHUNK_SIZE, chunk_overlap=OVERLAP_SIZE ) text_splitter.split_text(pdf_page.page_content[0:1000]) split_docs = text_splitter.split_documents(pdf_pages) print(split_docs[3])#切分的文件内容 print(f"切分后的文件数量:{len(split_docs)}") print(f"切分后的字符数(可以用来大致评估 token 数):{sum([len(doc.page_content) for doc in split_docs])}")
封装的混元Embedding api 接口T encentCloudEmbedding.py
from __future__ import annotations import json import logging import os from typing import Dict, List, Any from dotenv import load_dotenv from tencentcloud.common import credential from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile from tencentcloud.hunyuan.v20230901 import hunyuan_client, models from langchain.embeddings.base import Embeddings from langchain.pydantic_v1 import BaseModel logger = logging.getLogger(__name__) class TencentCloudEmbeddings(BaseModel, Embeddings): """腾讯云 Hunyuan Embeddings 封装""" client: Any """腾讯云 Hunyuan 客户端""" def __init__(self, **data: Any): super().__init__(**data) self.client = self.initialize_client() def initialize_client(self): """初始化腾讯云 Hunyuan 客户端""" try: load_dotenv() # 加载环境变量 SecretId = os.getenv("SecretId") SecretKey = os.getenv("SecretKey") cred = credential.Credential(SecretId, SecretKey) httpProfile = HttpProfile() httpProfile.endpoint = "hunyuan.tencentcloudapi.com" clientProfile = ClientProfile() clientProfile.httpProfile = httpProfile client = hunyuan_client.HunyuanClient(cred, "", clientProfile) return client except TencentCloudSDKException as err: logger.error(f"初始化腾讯云客户端失败: {err}") raise def embed_query(self, text: str) -> List[float]: """生成输入文本的 embedding""" try: req = models.GetEmbeddingRequest() params = {"Input": text} req.from_json_string(json.dumps(params)) resp = self.client.GetEmbedding(req) data = json.loads(resp.to_json_string()) return data["Data"][0]["Embedding"] except TencentCloudSDKException as err: logger.error(f"获取 embedding 失败: {err}") return [] def embed_documents(self, texts: List[str]) -> List[List[float]]: """生成输入文本列表的 embedding""" return [self.embed_query(text) for text in texts]
main.py
import os from dotenv import load_dotenv, find_dotenv from langchain_community.document_loaders import PyMuPDFLoader, UnstructuredMarkdownLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from TencentCloudEmbedding import TencentCloudEmbeddings from langchain.vectorstores.chroma import Chroma # 获取folder_path下所有文件路径,储存在file_paths里 file_paths = [] folder_path = './data_base/knowledge_db' for root, dirs, files in os.walk(folder_path): for file in files: file_path = os.path.join(root, file) file_paths.append(file_path) print(file_paths[:3]) # 遍历文件路径并把实例化的loader存放在loaders里 loaders = [] for file_path in file_paths: file_type = file_path.split('.')[-1] if file_type == 'pdf': loaders.append(PyMuPDFLoader(file_path)) elif file_type == 'md': loaders.append(UnstructuredMarkdownLoader(file_path)) # 下载文件并存储到text texts = [] for loader in loaders: texts.extend(loader.load()) text = texts[1] print(f"每一个元素的类型:{type(text)}.", f"该文档的描述性数据:{text.metadata}", f"查看该文档的内容:\n{text.page_content[0:]}", sep="\n------\n") # 切分文档 text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50) split_docs = text_splitter.split_documents(texts) embedding = TencentCloudEmbeddings() # 定义持久化路径 persist_directory = './data_base/vector_db/chroma' vectordb = Chroma.from_documents( documents=split_docs[:20], # 为了速度,只选择前 20 个切分的 doc 进行生成;使用千帆时因QPS限制,建议选择前 5 个doc embedding=embedding, persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上 ) vectordb.persist() print(f"向量库中存储的数量:{vectordb._collection.count()}") question = "什么是大语言模型" sim_docs = vectordb.similarity_search(question, k=3) print(f"检索到的内容数:{len(sim_docs)}") for i, sim_doc in enumerate(sim_docs): print(f"检索到的第{i}个内容: \n{sim_doc.page_content[:200]}", end="\n--------------\n") mmr_docs = vectordb.max_marginal_relevance_search(question, k=3) for i, sim_doc in enumerate(mmr_docs): print(f"MMR 检索到的第{i}个内容: \n{sim_doc.page_content[:200]}", end="\n--------------\n")
花径不曾缘客扫,蓬门今始为君开。
你好,我的名字是汪朝杰,欢迎来到我的网站和数字花园声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/1010350
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。