检索增强生成(RAG)实践:基于LlamaIndex和Qwen1.5搭建智能问答系统

检索增强生成(RAG)实践:基于LlamaIndex和Qwen1.5搭建智能问答系统

  • 什么是 RAG

LLM 会产生误导性的 “幻觉”,依赖的信息可能过时,处理特定知识时效率不高,缺乏专业领域的深度洞察,同时在推理能力上也有所欠缺。

正是在这样的背景下,检索增强生成技术(Retrieval-Augmented Generation,RAG)应时而生,成为 AI 时代的一大趋势。RAG 通过在语言模型生成答案之前,先从广泛的文档数据库中检索相关信息,然后利用这些信息来引导生成过程,极大地提升了内容的准确性和相关性。RAG 有效地缓解了幻觉问题,提高了知识更新的速度,并增强了内容生成的可追溯性,使得大型语言模型在实际应用中变得更加实用和可信

一个典型的 RAG 的例子:

这里面主要包括包括三个基本步骤:

  1. 索引 — 将文档库分割成较短的 Chunk,并通过编码器构建向量索引。
  2. 检索 — 根据问题和 chunks 的相似度检索相关文档片段。
  3. 生成 — 以检索到的上下文为条件,生成问题的回答。
    所有资料 ⚡️ ,朋友们如果有需要全套 《LLM大模型入门+进阶学习资源包》,扫码获取~

👉[CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)]()👈


1.通义千问Qwen 1.5

1.1 简介

Qwen1.5 版本年前开源了包括 0.5B、1.8B、4B、7B、14B 和 72B 在内的六种大小的基础和聊天模型,同时,也开源了量化模型。不仅提供了 Int4 和 Int8 的 GPTQ 模型,还有 AWQ 模型,以及 GGUF 量化模型。为了提升开发者体验,Qwen1.5 的代码合并到 Hugging Face Transformers 中,开发者现在可以直接使用 transformers>=4.37.0 而无需 trust_remote_code。

与之前的版本相比,Qwen1.5 显著提升了聊天模型与人类偏好的一致性,并且改善了它们的多语言能力。所有模型提供了统一的上下文长度支持,支持 32K 上下文。还有,基础语言模型的质量也有所小幅改进

Qwen1.5 全系列统一具备强大的链接外部系统能力(agent/RAG/Tool-use/Code-interpreter)

正因为 Qwen1.5 作为中文 LLM 率先合入了 Transformers,我们也可以使用 LLaMaIndex 的原生 HuggingFaceLLM 来加载模型。

当前基础模型已经稳定训练了大规模高质量且多样化的数据,覆盖多语言(当前以中文和英文为主),总量高达3万亿token。在相关基准评测中,Qwen系列模型拿出非常有竞争力的表现,显著超出同规模模型并紧追一系列最强的闭源模型。此外,我们利用SFT和RLHF技术实现对齐,从基座模型训练得到对话模型。Qwen-Chat具备聊天、文字创作、摘要、信息抽取、翻译等能力,同时还具备一定的代码生成和简单数学推理的能力。在此基础上,我们针对LLM对接外部系统等方面针对性地做了优化,当前具备较强的工具调用能力,以及最近备受关注的Code Interpreter的能力和扮演Agent的能力。我们将各个大小模型的特点列到了下表。

模型开源日期最大上下文长度System Prompt强化预训练token数微调(Q-Lora)最小GPU用量生成2048个token的最小显存占用工具调用
Qwen-1.8B23.11.3032K2.2T5.8GB2.9GB
Qwen-7B23.08.0332K2.4T11.5GB8.2GB
Qwen-14B23.09.258K3.0T18.7GB13.0GB
Qwen-72B23.11.3032K3.0T61.4GB48.9GB

Qwen系列模型相比同规模模型均实现了效果的显著提升。我们评测的数据集包括MMLU、C-Eval、 GSM8K、 MATH、HumanEval、MBPP、BBH等数据集,考察的能力包括自然语言理解、知识、数学计算和推理、代码生成、逻辑推理等。Qwen-72B在所有任务上均超越了LLaMA2-70B的性能,同时在10项任务中的7项任务中超越GPT-3.5.

ModelMMLUC-EvalGSM8KMATHHumanEvalMBPPBBHCMMLU
5-shot5-shot8-shot4-shot0-shot3-shot3-shot5-shot
LLaMA2-7B46.832.516.73.312.820.838.231.8
LLaMA2-13B55.041.429.65.018.930.345.638.4
LLaMA2-34B62.6-42.26.222.633.044.1-
ChatGLM2-6B47.951.732.46.5--33.7-
InternLM-7B51.053.431.26.310.414.037.051.8
InternLM-20B62.158.852.67.925.635.652.559.0
Baichuan2-7B54.756.324.65.618.324.241.657.1
Baichuan2-13B59.559.052.810.117.130.249.062.0
Yi-34B76.381.867.915.926.238.266.482.6
XVERSE-65B70.868.660.3-26.3---
Qwen-1.8B45.356.132.32.315.214.222.352.1
Qwen-7B58.263.551.711.629.931.645.062.2
Qwen-14B66.372.161.324.832.340.853.471.0
Qwen-72B77.483.378.935.235.452.267.783.6

1.2 推理性能

测算了BF16、Int8和Int4模型在生成2048个token时的平均推理速度(tokens/s)和显存使用。结果如下所示:

Model SizeQuantizationSpeed (Tokens/s)GPU Memory Usage
1.8BBF1654.094.23GB
Int855.563.48GB
Int471.072.91GB
7BBF1640.9316.99GB
Int837.4711.20GB
Int450.098.21GB
14BBF1632.2230.15GB
Int829.2818.81GB
Int438.7213.01GB
72BBF168.48144.69GB (2xA100)
Int89.0581.27GB (2xA100)
Int411.3248.86GB
72B + vLLMBF1617.602xA100

1.3 训练需要配置

下面记录7B和14B模型在单GPU使用LoRA(LoRA (emb)指的是embedding和输出层参与训练,而LoRA则不优化这部分参数)和QLoRA时处理不同长度输入的显存占用和训练速度的情况。本次评测运行于单张A100-SXM4-80G GPU,使用CUDA 11.8和Pytorch 2.0,并使用了flash attention 2。我们统一使用batch size为1,gradient accumulation为8的训练配置,记录输入长度分别为256、512、1024、2048、4096和8192的显存占用(GB)和训练速度(s/iter)。我们还使用2张A100测了Qwen-7B的全参数微调。受限于显存大小,我们仅测试了256、512和1024token的性能。

对于 Qwen-7B,我们额外测试了多机微调的性能。我们在两台服务器上运行评测,每台服务器包含两张A100-SXM4-80G GPU,其余配置与Qwen-7B的其他评测相同。多机微调的结果在表中以 LoRA (multinode) 标示。对于 Qwen-72B,我们测试了两种方案:1)使用4个 A100-SXM4-80G GPUs,通过 Lora + DeepSpeed ZeRO 3 微调和2)使用单张A100-SXM4-80G GPU,通过 QLora (int4) 微调。请注意,使用 LoRA (emb) 微调和不带 DeepSpeed ZeRO 3 的 LoRA 微调在4个A100-SXM4-80G GPUs 上都会出现OOM(你可以通过将--deepspeed finetune/ds_config_zero3.json参数传给finetune/finetune_lora_ds.sh来打开 DeepSpeed ZeRO 3 配置)。

具体数值如下所示:

Model SizeMethod#Nodes#GPUs per nodeSequence Length
2565121024204840968192
1.8BLoRA116.7G / 1.0s/it7.4G / 1.0s/it8.4G / 1.1s/it11.0G / 1.7s/it16.2G / 3.3s/it21.8G / 6.8s/it
LoRA (emb)1113.7G / 1.0s/it14.0G / 1.0s/it14.0G / 1.1s/it15.1G / 1.8s/it19.7G / 3.4s/it27.7G / 7.0s/it
Q-LoRA115.8G / 1.4s/it6.0G / 1.4s/it6.6G / 1.4s/it7.8G / 2.0s/it10.2G / 3.4s/it15.8G / 6.5s/it
Full-parameter1143.5G / 2.1s/it43.5G / 2.2s/it43.5G / 2.2s/it43.5G / 2.3s/it47.1G / 2.8s/it48.3G / 5.6s/it
7BLoRA1120.1G / 1.2s/it20.4G / 1.5s/it21.5G / 2.8s/it23.8G / 5.2s/it29.7G / 10.1s/it36.6G / 21.3s/it
LoRA (emb)1133.7G / 1.4s/it34.1G / 1.6s/it35.2G / 2.9s/it35.1G / 5.3s/it39.2G / 10.3s/it48.5G / 21.7s/it
Q-LoRA1111.5G / 3.0s/it11.5G / 3.0s/it12.3G / 3.5s/it13.9G / 7.0s/it16.9G / 11.6s/it23.5G / 22.3s/it
Full-parameter12139.2G / 4.0s/it148.0G / 4.0s/it162.0G / 4.5s/it---
LoRA (multinode)2274.7G / 2.09s/it77.6G / 3.16s/it84.9G / 5.17s/it95.1G / 9.25s/it121.1G / 18.1s/it155.5G / 37.4s/it
14BLoRA1134.6G / 1.6s/it35.1G / 2.4s/it35.3G / 4.4s/it37.4G / 8.4s/it42.5G / 17.0s/it55.2G / 36.0s/it
LoRA (emb)1151.2 / 1.7s/it51.1G / 2.6s/it51.5G / 4.6s/it54.1G / 8.6s/it56.8G / 17.2s/it67.7G / 36.3s/it
Q-LoRA1118.7G / 5.3s/it18.4G / 6.3s/it18.9G / 8.2s/it19.9G / 11.8s/it23.0G / 20.1s/it27.9G / 38.3s/it
72BLoRA + Deepspeed Zero314215.4G / 17.6s/it217.7G / 20.5s/it222.6G / 29.4s/it228.8G / 45.7s/it249.0G / 83.4s/it289.2G / 161.5s/it
Q-LoRA1161.4G / 27.4s/it61.4G / 31.5s/it62.9G / 41.4s/it64.1G / 59.5s/it68.0G / 97.7s/it75.6G / 179.8s/it

2. LLaMaIndex

2.1 简介

LlamaIndex 是一个基于 LLM 的应用程序的数据框架,受益于上下文增强。 这种 LLM 系统被称为 RAG 系统,代表 “检索增强生成”。LlamaIndex 提供了必要的抽象,可以更轻松地摄取、构建和访问私有或特定领域的数据,以便将这些数据安全可靠地注入 LLM 中,以实现更准确的文本生成。

首先,它有助于“摄取”数据,这意味着将数据从原始来源获取到系统中。其次,它有助于“结构化”数据,这意味着以语言模型易于理解的方式组织数据。第三,它有助于“检索”,这意味着在需要时查找和获取正确的数据。最后,它简化了“集成”,使您更容易将数据与各种应用程序框架融合在一起。

  • LllamaIndex 以专用索引的形式提供独特的数据结构:
    • 向量存储索引:最常用,允许您回答对大型数据集的查询。
    • 树索引:对于总结文档集合很有用。
    • 列表索引:对于合成一个结合了多个数据源信息的答案很有用。
    • 关键字表索引:用于将查询路由到不同的数据源。
    • 结构化存储索引:对于结构化数据(例如 SQL 查询)很有用。
    • 知识图谱索引:对于构建知识图谱很有用。

LlamaIndex 有用性的核心是其有助于构建 LLM 应用程序的功能和工具。在这里,我们详细讨论它们:

  • 数据连接器

LlamaIndex 提供数据连接器,可以提取您现有的数据源和格式。无论是 API、PDF、文档还是 SQL 数据库,LlamaIndex 都可以与它们无缝集成,为您的 LLM 准备数据。

  • 数据结构

使用 LLM 的主要挑战之一是以易于使用的方式构建数据。LlamaIndex 提供了在索引或图表中构建数据的工具。

  • 高级检索/查询界面

LlamaIndex 不仅仅是摄取和构建数据。它还为您的数据提供高级检索或查询界面。只需输入任何 LLM 输入提示,LlamaIndex 将返回检索到的上下文和知识增强输出。

  • 与其他框架集成

LlamaIndex 允许与您的外部应用程序框架轻松集成。您可以将它与 LangChain、Flask、Docker、ChatGPT 以及您的项目可能需要的任何其他工具一起使用。

  • 高级和低级 API

无论您的熟练程度如何,LlamaIndex 都能满足您的需求。初学者用户会喜欢高级 API,它允许使用 LlamaIndex 以仅五行代码来摄取和查询他们的数据。另一方面,高级用户可以根据需要利用较低级别的 API 自定义和扩展任何模块(数据连接器、索引、检索器、查询引擎、重新排名模块)。

2.2 快速使用

  • 使用 pip 安装 LlamaIndex 非常简单:
pip install llama-index

  • 如何构建向量存储索引并查询它的简单示例:
import os
os.environ["OPENAI_API_KEY"] = 'YOUR_OPENAI_API_KEY'
 
from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader
documents = SimpleDirectoryReader('data').load_data()
index = GPTVectorStoreIndex.from_documents(documents)
 
#o query:
query_engine = index.as_query_engine()
query_engine.query("<question_text>?")
 
#By default, data is stored in-memory. To persist to disk (under ./storage):
index.storage_context.persist()
 
#To reload from disk:
from llama_index import StorageContext, load_index
 
_from_storage
#rebuild storage context
storage_context = StorageContext.from_defaults(persist_dir='./storage')
#load index
index = load_index_from_storage(storage_context)

LlamaIndex 不仅仅是一个数据框架;它是更大的工具和资源生态系统的一部分: LlamaHub:数据加载器的社区库。 LlamaLab:使用 LlamaIndex 的尖端 AGI 项目平台。

3.GTE 文本向量

3.1 简介

文本表示是自然语言处理 (NLP) 领域的核心问题, 其在很多 NLP、信息检索的下游任务中发挥着非常重要的作用。近几年, 随着深度学习的发展,尤其是预训练语言模型的出现极大的推动了文本表示技术的效果, 基于预训练语言模型的文本表示模型在学术研究数据、工业实际应用中都明显优于传统的基于统计模型或者浅层神经网络的文本表示模型。这里, 我们主要关注基于预训练语言模型的文本表示。

文本表示示例, 输入一个句子, 输入一个固定维度的连续向量:

  • 输入: 吃完海鲜可以喝牛奶吗?
  • 输出: [0.27162,-0.66159,0.33031,0.24121,0.46122,…]

文本的向量表示通常可以用于文本聚类、文本相似度计算、文本向量召回等下游任务中。

基于监督数据训练的文本表示模型通常采用 Dual Encoder 框架, 如下图所示。在 Dual Encoder 框架中, Query 和 Document 文本通过预训练语言模型编码后, 通常采用预训练语言模型 [CLS] 位置的向量作为最终的文本向量表示。基于标注数据的标签, 通过计算 query-document 之间的 cosine 距离度量两者之间的相关性。

  • GTE-zh 模型使用 retromae 初始化训练模型,之后利用两阶段训练方法训练模型:
    • 第一阶段利用大规模弱弱监督文本对数据训练模型,
    • 第二阶段利用高质量精标文本对数据以及挖掘的难负样本数据训练模型。

具体训练方法请参考论文 Towards General Text Embeddings with Multi-stage Contrastive Learning

  • 使用方式:直接推理,对给定文本计算其对应的文本向量表示,向量维度 768

  • 使用范围:本模型可以使用在通用领域的文本向量表示及其下游应用场景, 包括双句文本相似度计算、query & 多 doc 候选的相似度排序

在 ModelScope 框架上,提供输入文本 (默认最长文本长度为 128),即可以通过简单的 Pipeline 调用来使用 GTE 文本向量表示模型。ModelScope 封装了统一的接口对外提供单句向量表示、双句文本相似度、多候选相似度计算功能

3.2 代码示例

from modelscope.models import Model
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks

model_id = "iic/nlp_gte_sentence-embedding_chinese-base"
pipeline_se = pipeline(Tasks.sentence_embedding,
                       model=model_id,
                       sequence_length=512
                       ) # sequence_length 代表最大文本长度,默认值为128

#当输入包含“soure_sentence”与“sentences_to_compare”时,会输出source_sentence中首个句子与sentences_to_compare中每个句子的向量表示,以及source_sentence中首个句子与sentences_to_compare中每个句子的相似度。
inputs = {
        "source_sentence": ["吃完海鲜可以喝牛奶吗?"],
        "sentences_to_compare": [
            "不可以,早晨喝牛奶不科学",
            "吃了海鲜后是不能再喝牛奶的,因为牛奶中含得有维生素C,如果海鲜喝牛奶一起服用会对人体造成一定的伤害",
            "吃海鲜是不能同时喝牛奶吃水果,这个至少间隔6小时以上才可以。",
            "吃海鲜是不可以吃柠檬的因为其中的维生素C会和海鲜中的矿物质形成砷"
        ]
    }

result = pipeline_se(input=inputs)
print (result)
'''
{'text_embedding': array([[ 1.6415151e-04,  2.2334497e-02, -2.4202393e-02, ...,
         2.7710509e-02,  2.5980933e-02, -3.1285528e-02],
       [-9.9107623e-03,  1.3627578e-03, -2.1072682e-02, ...,
         2.6786461e-02,  3.5029035e-03, -1.5877936e-02],
       [ 1.9877627e-03,  2.2191243e-02, -2.7656069e-02, ...,
         2.2540951e-02,  2.1780970e-02, -3.0861111e-02],
       [ 3.8688166e-05,  1.3409532e-02, -2.9691193e-02, ...,
         2.9900728e-02,  2.1570563e-02, -2.0719109e-02],
       [ 1.4484422e-03,  8.5943500e-03, -1.6661938e-02, ...,
         2.0832840e-02,  2.3828523e-02, -1.1581291e-02]], dtype=float32), 'scores': [0.8859604597091675, 0.9830712080001831, 0.966042160987854, 0.891857922077179]}
'''

#当输入仅含有soure_sentence时,会输出source_sentence中每个句子的向量表示。
inputs2 = {
        "source_sentence": [
            "不可以,早晨喝牛奶不科学",
            "吃了海鲜后是不能再喝牛奶的,因为牛奶中含得有维生素C,如果海鲜喝牛奶一起服用会对人体造成一定的伤害",
            "吃海鲜是不能同时喝牛奶吃水果,这个至少间隔6小时以上才可以。",
            "吃海鲜是不可以吃柠檬的因为其中的维生素C会和海鲜中的矿物质形成砷"
        ]
}
result = pipeline_se(input=inputs2)
print (result)
'''
{'text_embedding': array([[-9.9107623e-03,  1.3627578e-03, -2.1072682e-02, ...,
         2.6786461e-02,  3.5029035e-03, -1.5877936e-02],
       [ 1.9877627e-03,  2.2191243e-02, -2.7656069e-02, ...,
         2.2540951e-02,  2.1780970e-02, -3.0861111e-02],
       [ 3.8688166e-05,  1.3409532e-02, -2.9691193e-02, ...,
         2.9900728e-02,  2.1570563e-02, -2.0719109e-02],
       [ 1.4484422e-03,  8.5943500e-03, -1.6661938e-02, ...,
         2.0832840e-02,  2.3828523e-02, -1.1581291e-02]], dtype=float32), 'scores': []}
'''


默认向量维度 768, scores 中的 score 计算两个向量之间的内成积距离得到

  • 训练示例代码
#需在GPU环境运行
#加载数据集过程可能由于网络原因失败,请尝试重新运行代码
from modelscope.metainfo import Trainers                                                                                                                                                              
from modelscope.msdatasets import MsDataset
from modelscope.trainers import build_trainer
import tempfile
import os

tmp_dir = tempfile.TemporaryDirectory().name
if not os.path.exists(tmp_dir):
    os.makedirs(tmp_dir)

#load dataset
ds = MsDataset.load('dureader-retrieval-ranking', 'zyznull')
train_ds = ds['train'].to_hf_dataset()
dev_ds = ds['dev'].to_hf_dataset()
model_id = 'iic/nlp_gte_sentence-embedding_chinese-base'
def cfg_modify_fn(cfg):
    cfg.task = 'sentence-embedding'
    cfg['preprocessor'] = {'type': 'sentence-embedding','max_length': 256}
    cfg['dataset'] = {
        'train': {
            'type': 'bert',
            'query_sequence': 'query',
            'pos_sequence': 'positive_passages',
            'neg_sequence': 'negative_passages',
            'text_fileds': ['text'],
            'qid_field': 'query_id'
        },
        'val': {
            'type': 'bert',
            'query_sequence': 'query',
            'pos_sequence': 'positive_passages',
            'neg_sequence': 'negative_passages',
            'text_fileds': ['text'],
            'qid_field': 'query_id'
        },
    }
    cfg['train']['neg_samples'] = 4
    cfg['evaluation']['dataloader']['batch_size_per_gpu'] = 30
    cfg.train.max_epochs = 1
    cfg.train.train_batch_size = 4
    return cfg 
kwargs = dict(
    model=model_id,
    train_dataset=train_ds,
    work_dir=tmp_dir,
    eval_dataset=dev_ds,
    cfg_modify_fn=cfg_modify_fn)
trainer = build_trainer(name=Trainers.nlp_sentence_embedding_trainer, default_args=kwargs)
trainer.train()


3.3 模型效果评估

  • 中文多任务向量评测榜单C-MTEB结果如下:
Model SizeMethod#Nodes#GPUs per nodeSequence Length
2565121024204840968192
1.8BLoRA116.7G / 1.0s/it7.4G / 1.0s/it8.4G / 1.1s/it11.0G / 1.7s/it16.2G / 3.3s/it21.8G / 6.8s/it
LoRA (emb)1113.7G / 1.0s/it14.0G / 1.0s/it14.0G / 1.1s/it15.1G / 1.8s/it19.7G / 3.4s/it27.7G / 7.0s/it
Q-LoRA115.8G / 1.4s/it6.0G / 1.4s/it6.6G / 1.4s/it7.8G / 2.0s/it10.2G / 3.4s/it15.8G / 6.5s/it
Full-parameter1143.5G / 2.1s/it43.5G / 2.2s/it43.5G / 2.2s/it43.5G / 2.3s/it47.1G / 2.8s/it48.3G / 5.6s/it
7BLoRA1120.1G / 1.2s/it20.4G / 1.5s/it21.5G / 2.8s/it23.8G / 5.2s/it29.7G / 10.1s/it36.6G / 21.3s/it
LoRA (emb)1133.7G / 1.4s/it34.1G / 1.6s/it35.2G / 2.9s/it35.1G / 5.3s/it39.2G / 10.3s/it48.5G / 21.7s/it
Q-LoRA1111.5G / 3.0s/it11.5G / 3.0s/it12.3G / 3.5s/it13.9G / 7.0s/it16.9G / 11.6s/it23.5G / 22.3s/it
Full-parameter12139.2G / 4.0s/it148.0G / 4.0s/it162.0G / 4.5s/it---
LoRA (multinode)2274.7G / 2.09s/it77.6G / 3.16s/it84.9G / 5.17s/it95.1G / 9.25s/it121.1G / 18.1s/it155.5G / 37.4s/it
14BLoRA1134.6G / 1.6s/it35.1G / 2.4s/it35.3G / 4.4s/it37.4G / 8.4s/it42.5G / 17.0s/it55.2G / 36.0s/it
LoRA (emb)1151.2 / 1.7s/it51.1G / 2.6s/it51.5G / 4.6s/it54.1G / 8.6s/it56.8G / 17.2s/it67.7G / 36.3s/it
Q-LoRA1118.7G / 5.3s/it18.4G / 6.3s/it18.9G / 8.2s/it19.9G / 11.8s/it23.0G / 20.1s/it27.9G / 38.3s/it
72BLoRA + Deepspeed Zero314215.4G / 17.6s/it217.7G / 20.5s/it222.6G / 29.4s/it228.8G / 45.7s/it249.0G / 83.4s/it289.2G / 161.5s/it
Q-LoRA1161.4G / 27.4s/it61.4G / 31.5s/it62.9G / 41.4s/it64.1G / 59.5s/it68.0G / 97.7s/it75.6G / 179.8s/it
  • 英文多任务向量评测榜单MTEB结果如下:
Model NameModel Size (GB)DimensionSequence LengthAverage (56)Clustering (11)Pair Classification (3)Reranking (4)Retrieval (15)STS (10)Summarization (1)Classification (12)
gte-large0.67102451263.1346.8485.0059.1352.2283.3531.6673.33
gte-base0.2276851262.3946.284.5758.6151.1482.331.1773.01
e5-large-v21.34102451262.2544.4986.0356.6150.5682.0530.1975.24
e5-base-v20.4476851261.543.8085.7355.9150.2981.0530.2873.84
gte-small0.0738451261.3644.8983.5457.749.4682.0730.4272.31
text-embedding-ada-002-1536819260.9945.984.8956.3249.2580.9730.870.93
e5-small-v20.1338451259.9339.9284.6754.3249.0480.3931.1672.94
sentence-t5-xxl9.7376851259.5143.7285.0656.4242.2482.6330.0873.42
all-mpnet-base-v20.4476851457.7843.6983.0459.3643.8180.2827.4965.07
sgpt-bloom-7b1-msmarco28.274096204857.5938.9381.955.6548.2277.7433.666.19
all-MiniLM-L12-v20.1338451256.5341.8182.4158.4442.6979.827.963.21
all-MiniLM-L6-v20.0938451256.2642.3582.3758.0441.9578.930.8163.05
contriever-base-msmarco0.4476851256.0041.182.5453.1441.8876.5130.3666.68
sentence-t5-base0.2276851255.2740.2185.1853.0933.6381.1431.3969.81

4.魔搭社区最佳实践

4.1 逐步解析

  • 环境配置与安装

    1. python 3.10 及以上版本
    2. pytorch 1.12 及以上版本,推荐 2.0 及以上版本
    3. 建议使用 CUDA 11.4 及以上本文主要演示的模型推理代码可在魔搭社区免费实例 PAI-DSW 的配置下运行(显存 24G) :
  • 第一步:点击模型右侧 Notebook 快速开发按钮,选择 GPU 环境

  • 第二步:新建 Notebook

安装依赖库1

!pip install llama-index llama-index-llms-huggingface ipywidgets
!pip install transformers -U
import logging
import sys

logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))

from IPython.display import Markdown, display
import torch
from llama_index.llms.huggingface import HuggingFaceLLM
from llama_index.core.prompts import PromptTemplate
from modelscope import snapshot_download
from llama_index.core.base.embeddings.base import BaseEmbedding, Embedding
from abc import ABC
from typing import Any, List, Optional, Dict, cast
from llama_index.core import (
    VectorStoreIndex,
    ServiceContext,
    set_global_service_context,
    SimpleDirectoryReader,
)

  • 加载大语言模型

因为 Qwen 本次支持了 Transformers,使用 HuggingFaceLLM 加载模型,模型为(Qwen1.5-4B-Chat)1

#Model names 
qwen2_4B_CHAT = "qwen/Qwen1.5-4B-Chat"

selected_model = snapshot_download(qwen2_4B_CHAT)

SYSTEM_PROMPT = """You are a helpful AI assistant.
"""

query_wrapper_prompt = PromptTemplate(
    "[INST]<<SYS>>\n" + SYSTEM_PROMPT + "<</SYS>>\n\n{query_str}[/INST] "
)

llm = HuggingFaceLLM(
    context_window=4096,
    max_new_tokens=2048,
    generate_kwargs={"temperature": 0.0, "do_sample": False},
    query_wrapper_prompt=query_wrapper_prompt,
    tokenizer_name=selected_model,
    model_name=selected_model,
    device_map="auto",
    # change these settings below depending on your GPU
    model_kwargs={"torch_dtype": torch.float16},
)

  • 加载数据:导入测试数据
!mkdir -p 'data/xianjiaoda/'
!wget 'https://modelscope.oss-cn-beijing.aliyuncs.com/resource/rag/xianjiaoda.md' -O 'data/xianjiaoda/xianjiaoda.md'
documents = SimpleDirectoryReader("/mnt/workspace/data/xianjiaoda/").load_data()
documents

  • 构建 Embedding 类

加载 GTE 模型,使用 GTE 模型构造 Embedding 类

embedding_model = "iic/nlp_gte_sentence-embedding_chinese-base"
class ModelScopeEmbeddings4LlamaIndex(BaseEmbedding, ABC):
    embed: Any = None
    model_id: str = "iic/nlp_gte_sentence-embedding_chinese-base"

    def __init__(
            self,
            model_id: str,
            **kwargs: Any,
    ) -> None:
        super().__init__(**kwargs)
        try:
            from modelscope.models import Model
            from modelscope.pipelines import pipeline
            from modelscope.utils.constant import Tasks
            # 使用modelscope的embedding模型(包含下载)
            self.embed = pipeline(Tasks.sentence_embedding, model=self.model_id)

        except ImportError as e:
            raise ValueError(
                "Could not import some python packages." "Please install it with `pip install modelscope`."
            ) from e

    def _get_query_embedding(self, query: str) -> List[float]:
        text = query.replace("\n", " ")
        inputs = {"source_sentence": [text]}
        return self.embed(input=inputs)['text_embedding'][0].tolist()

    def _get_text_embedding(self, text: str) -> List[float]:
        text = text.replace("\n", " ")
        inputs = {"source_sentence": [text]}
        return self.embed(input=inputs)['text_embedding'][0].tolist()

    def _get_text_embeddings(self, texts: List[str]) -> List[List[float]]:
        texts = list(map(lambda x: x.replace("\n", " "), texts))
        inputs = {"source_sentence": texts}
        return self.embed(input=inputs)['text_embedding'].tolist()

    async def _aget_query_embedding(self, query: str) -> List[float]:
        return self._get_query_embedding(query)


  • 建设索引

加载数据后,基于文档对象列表(或节点列表),建设他们的 index,就可以方便的检索他们。1

embeddings = ModelScopeEmbeddings4LlamaIndex(model_id=embedding_model)
service_context = ServiceContext.from_defaults(embed_model=embeddings, llm=llm)
set_global_service_context(service_context)

index = VectorStoreIndex.from_documents(documents)

  • 查询和问答

搭建基于本地知识库的问答引擎1


query_engine = index.as_query_engine()
response = query_engine.query("西安交大是由哪几个学校合并的?")
print(response)

4.2 完整代码

!pip install pypdf langchain unstructured transformers_stream_generator
!pip install modelscope  nltk pydantic  tiktoken  llama-index

!wget https://modelscope.oss-cn-beijing.aliyuncs.com/resource/rag/averaged_perceptron_tagger.zip
!wget https://modelscope.oss-cn-beijing.aliyuncs.com/resource/rag/punkt.zip
!wget https://modelscope.oss-cn-beijing.aliyuncs.com/resource/rag/xianjiaoda.md

!mkdir -p /root/nltk_data/tokenizers
!mkdir -p /root/nltk_data/taggers
!cp /mnt/workspace/punkt.zip /root/nltk_data/tokenizers
!cp /mnt/workspace/averaged_perceptron_tagger.zip /root/nltk_data/taggers
!cd /root/nltk_data/tokenizers; unzip punkt.zip;
!cd /root/nltk_data/taggers; unzip averaged_perceptron_tagger.zip;

!mkdir -p /mnt/workspace/custom_data
!mv /mnt/workspace/xianjiaoda.md /mnt/workspace/custom_data

!cd /mnt/workspace

import os
from abc import ABC
from typing import Any, List, Optional, Dict, cast

import torch
from langchain_core.language_models.llms import LLM
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from modelscope import AutoModelForCausalLM, AutoTokenizer
from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader
from llama_index import ServiceContext
from llama_index.embeddings.base import BaseEmbedding
from llama_index import set_global_service_context
from langchain_core.retrievers import BaseRetriever
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from llama_index.retrievers import VectorIndexRetriever

# configs for LLM
llm_name = "Qwen/Qwen-1_8B-Chat"
llm_revision = "master"

# configs for embedding model
embedding_model = "damo/nlp_gte_sentence-embedding_chinese-small"

# file path for your custom knowledge base
knowledge_doc_file_dir = "/mnt/workspace/custom_data/"
knowledge_doc_file_path = knowledge_doc_file_dir + "xianjiaoda.md"

# define our Embedding class to use models in Modelscope
class ModelScopeEmbeddings4LlamaIndex(BaseEmbedding, ABC):
    embed: Any = None
    model_id: str = "damo/nlp_gte_sentence-embedding_chinese-small"

    def __init__(
            self,
            model_id: str,
            **kwargs: Any,
    ) -> None:
        super().__init__(**kwargs)
        try:
            from modelscope.models import Model
            from modelscope.pipelines import pipeline
            from modelscope.utils.constant import Tasks
            self.embed = pipeline(Tasks.sentence_embedding, model=self.model_id)

        except ImportError as e:
            raise ValueError(
                "Could not import some python packages." "Please install it with `pip install modelscope`."
            ) from e

    def _get_query_embedding(self, query: str) -> List[float]:
        text = query.replace("\n", " ")
        inputs = {"source_sentence": [text]}
        return self.embed(input=inputs)['text_embedding'][0]

    def _get_text_embedding(self, text: str) -> List[float]:
        text = text.replace("\n", " ")
        inputs = {"source_sentence": [text]}
        return self.embed(input=inputs)['text_embedding'][0]

    def _get_text_embeddings(self, texts: List[str]) -> List[List[float]]:
        texts = list(map(lambda x: x.replace("\n", " "), texts))
        inputs = {"source_sentence": texts}
        return self.embed(input=inputs)['text_embedding']

    async def _aget_query_embedding(self, query: str) -> List[float]:
        return self._get_query_embedding(query)

# define our Retriever with llama-index to co-operate with Langchain
# note that the 'LlamaIndexRetriever' defined in langchain-community.retrievers.llama_index.py
# is no longer compatible with llamaIndex code right now.
class LlamaIndexRetriever(BaseRetriever):
    index: Any
    """LlamaIndex index to query."""

    def _get_relevant_documents(
        self, query: str, *, run_manager: CallbackManagerForRetrieverRun
    ) -> List[Document]:
        """Get documents relevant for a query."""
        try:
            from llama_index.indices.base import BaseIndex
            from llama_index.response.schema import Response
        except ImportError:
            raise ImportError(
                "You need to install `pip install llama-index` to use this retriever."
            )
        index = cast(BaseIndex, self.index)
        print('@@@ query=', query)

        response = index.as_query_engine().query(query)
        response = cast(Response, response)
        # parse source nodes
        docs = []
        for source_node in response.source_nodes:
            print('@@@@ source=', source_node)
            metadata = source_node.metadata or {}
            docs.append(
                Document(page_content=source_node.get_text(), metadata=metadata)
            )
        return docs

def torch_gc():
    os.environ["TOKENIZERS_PARALLELISM"] = "false"
    DEVICE = "cuda"
    DEVICE_ID = "0"
    CUDA_DEVICE = f"{DEVICE}:{DEVICE_ID}" if DEVICE_ID else DEVICE
    a = torch.Tensor([1, 2])
    a = a.cuda()
    print(a)

    if torch.cuda.is_available():
        with torch.cuda.device(CUDA_DEVICE):
            torch.cuda.empty_cache()
            torch.cuda.ipc_collect()

# global resources used by QianWenChatLLM (this is not a good practice)
tokenizer = AutoTokenizer.from_pretrained(llm_name, revision=llm_revision, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(llm_name, revision=llm_revision, device_map="auto",
                                             trust_remote_code=True, fp16=True).eval()

# define QianWen LLM based on langchain's LLM to use models in Modelscope
class QianWenChatLLM(LLM):
    max_length = 10000
    temperature: float = 0.01
    top_p = 0.9

    def __init__(self):
        super().__init__()

    @property
    def _llm_type(self):
        return "ChatLLM"

    def _call(
            self,
            prompt: str,
            stop: Optional[List[str]] = None,
            run_manager=None,
            **kwargs: Any,
    ) -> str:
        print(prompt)
        response, history = model.chat(tokenizer, prompt, history=None)
        torch_gc()
        return response

# STEP1: create LLM instance
qwllm = QianWenChatLLM()
print('STEP1: qianwen LLM created')

# STEP2: load knowledge file and initialize vector db by llamaIndex
print('STEP2: reading docs ...')
embeddings = ModelScopeEmbeddings4LlamaIndex(model_id=embedding_model)
service_context = ServiceContext.from_defaults(embed_model=embeddings, llm=None)
set_global_service_context(service_context)     # global config, not good

llamaIndex_docs = SimpleDirectoryReader(knowledge_doc_file_dir).load_data()
llamaIndex_index = GPTVectorStoreIndex.from_documents(llamaIndex_docs, chunk_size=512)
retriever = LlamaIndexRetriever(index=llamaIndex_index)
print(' 2.2 reading doc done, vec db created.')

# STEP3: create chat template
prompt_template = """请基于内的内容回答问题。"{context}
我的问题是:{question}。
"""
prompt = ChatPromptTemplate.from_template(template=prompt_template)
print('STEP3: chat prompt template created.')

# STEP4: create RAG chain to do QA
chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | qwllm
        | StrOutputParser()
)
chain.invoke('西安交大的校训是什么?')
# chain.invoke('魔搭社区有哪些模型?')
# chain.invoke('modelscope是什么?')
# chain.invoke('萧峰和乔峰是什么关系?')

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值