• 【InternLM 笔记】使用InternLM2-chat-1.8b制作时事问答知识库


    环境版本

    模型版本:
    InternLM2-chat-1.8b

    准备环境

    还是使用InternStudio进行操作

    拉取环境

    /root/share/install_conda_env_internlm_base.sh internlm
    
    • 1

    开始实践

    创建工作目录

    cd ~
    mkdir temp
    cd temp
    
    • 1
    • 2
    • 3

    下载模型

    import torch
    from modelscope import snapshot_download, AutoModel, AutoTokenizer
    import os
    
    model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm2-1_8b', cache_dir='/root/model/', revision='master')
    
    • 1
    • 2
    • 3
    • 4
    • 5

    复制模型到工作目录

    cp -r /root/model/Shanghai_AI_Laboratory/internlm2-1_8b /root/temp
    
    • 1

    使用LangChain构建党史知识库

    准备工作

    安装依赖

    # 升级pip
    python -m pip install --upgrade pip
    
    pip install modelscope==1.9.5
    pip install transformers==4.35.2
    pip install streamlit==1.24.0
    pip install sentencepiece==0.1.99
    pip install accelerate==0.24.1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    LangChain 依赖包

    pip install langchain==0.0.292
    pip install gradio==4.4.0
    pip install chromadb==0.4.15
    pip install sentence-transformers==2.2.2
    pip install unstructured==0.10.30
    pip install markdown==3.3.7
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    安装huggingface-cli

    pip install -U huggingface_hub
    
    • 1

    下载sentence-transformer模型

    import os
    
    # 设置环境变量
    os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
    
    # 下载模型
    os.system('huggingface-cli download --resume-download --local-dir-use-symlinks False sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/data/model/sentence-transformer')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    下载 NLTK 相关资源

    cd /root
    git clone https://gitee.com/yzy0612/nltk_data.git  --branch gh-pages
    cd nltk_data
    mv packages/*  ./
    cd tokenizers
    unzip punkt.zip
    cd ../taggers
    unzip averaged_perceptron_tagger.zip
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    知识库搭建

    数据集采用了比赛赛题一的数据集中一些内容转化为txt使用

    数据集地址:
    https://openxlab.org.cn/models/detail/OpenLMLab/SMG/

    知识库搭建的脚本create_db.py

    # 首先导入所需第三方库
    from langchain.document_loaders import UnstructuredFileLoader
    from langchain.document_loaders import UnstructuredMarkdownLoader
    from langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain.vectorstores import Chroma
    from langchain.embeddings.huggingface import HuggingFaceEmbeddings
    from tqdm import tqdm
    import os
    
    # 获取文件路径函数
    def get_files(dir_path):
        # args:dir_path,目标文件夹路径
        file_list = []
        for filepath, dirnames, filenames in os.walk(dir_path):
            # os.walk 函数将递归遍历指定文件夹
            for filename in filenames:
                # 通过后缀名判断文件类型是否满足要求
                if filename.endswith("_CN.md"):
                    # 如果满足要求,将其绝对路径加入到结果列表
                    file_list.append(os.path.join(filepath, filename))
                elif filename.endswith("_CN.txt"):
                    file_list.append(os.path.join(filepath, filename))
        return file_list
    
    # 加载文件函数
    def get_text(dir_path):
        # args:dir_path,目标文件夹路径
        # 首先调用上文定义的函数得到目标文件路径列表
        file_lst = get_files(dir_path)
        # docs 存放加载之后的纯文本对象
        docs = []
        # 遍历所有目标文件
        for one_file in tqdm(file_lst):
            file_type = one_file.split('.')[-1]
            if file_type == 'md':
                loader = UnstructuredMarkdownLoader(one_file)
            elif file_type == 'txt':
                loader = UnstructuredFileLoader(one_file)
            else:
                # 如果是不符合条件的文件,直接跳过
                continue
            docs.extend(loader.load())
        return docs
    
    # 目标文件夹
    tar_dir = [
        "/root/data/docs"
    ]
    
    # 加载目标文件
    docs = []
    for dir_path in tar_dir:
        docs.extend(get_text(dir_path))
    
    # 对文本进行分块
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500, chunk_overlap=150)
    split_docs = text_splitter.split_documents(docs)
    
    # 加载开源词向量模型
    embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer")
    
    # 构建向量数据库
    # 定义持久化路径
    persist_directory = 'data_base/vector_db/chroma'
    # 加载数据库
    vectordb = Chroma.from_documents(
        documents=split_docs,
        embedding=embeddings,
        persist_directory=persist_directory  # 允许我们将persist_directory目录保存到磁盘上
    )
    # 将加载的向量数据库持久化到磁盘上
    vectordb.persist()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    执行

    python create_db.py
    
    • 1

    InternLM 接入 LangChain

    脚本

    from langchain.llms.base import LLM
    from typing import Any, List, Optional
    from langchain.callbacks.manager import CallbackManagerForLLMRun
    from transformers import AutoTokenizer, AutoModelForCausalLM
    import torch
    
    class InternLM_LLM(LLM):
        # 基于本地 InternLM 自定义 LLM 类
        tokenizer : AutoTokenizer = None
        model: AutoModelForCausalLM = None
    
        def __init__(self, model_path :str):
            # model_path: InternLM 模型路径
            # 从本地初始化模型
            super().__init__()
            print("正在从本地加载模型...")
            self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
            self.model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).to(torch.bfloat16).cuda()
            self.model = self.model.eval()
            print("完成本地模型的加载")
    
        def _call(self, prompt : str, stop: Optional[List[str]] = None,
                    run_manager: Optional[CallbackManagerForLLMRun] = None,
                    **kwargs: Any):
            # 重写调用函数
            system_prompt = """You are an AI assistant whose name is InternLM (书生·浦语).
            - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless.
            - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文.
            """
            
            messages = [(system_prompt, '')]
            response, history = self.model.chat(self.tokenizer, prompt , history=messages)
            return response
            
        @property
        def _llm_type(self) -> str:
            return "InternLM"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    将上述代码封装为 LLM.py,后续将直接从该文件中引入自定义的 LLM 类。

    部署 Web Demo

    from langchain.vectorstores import Chroma
    from langchain.embeddings.huggingface import HuggingFaceEmbeddings
    import os
    from LLM import InternLM_LLM
    from langchain.prompts import PromptTemplate
    from langchain.chains import RetrievalQA
    
    def load_chain():
        # 加载问答链
        # 定义 Embeddings
        embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer")
    
        # 向量数据库持久化路径
        persist_directory = 'data_base/vector_db/chroma'
    
        # 加载数据库
        vectordb = Chroma(
            persist_directory=persist_directory,  # 允许我们将persist_directory目录保存到磁盘上
            embedding_function=embeddings
        )
    
        # 加载自定义 LLM
        llm = InternLM_LLM(model_path = "/root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b")
    
        # 定义一个 Prompt Template
        template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
        案。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
        {context}
        问题: {question}
        有用的回答:"""
    
        QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],template=template)
    
        # 运行 chain
        qa_chain = RetrievalQA.from_chain_type(llm,retriever=vectordb.as_retriever(),return_source_documents=True,chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
        
        return qa_chain
    
    class Model_center():
        """
        存储检索问答链的对象 
        """
        def __init__(self):
            # 构造函数,加载检索问答链
            self.chain = load_chain()
    
        def qa_chain_self_answer(self, question: str, chat_history: list = []):
            """
            调用问答链进行回答
            """
            if question == None or len(question) < 1:
                return "", chat_history
            try:
                chat_history.append(
                    (question, self.chain({"query": question})["result"]))
                # 将问答结果直接附加到问答历史中,Gradio 会将其展示出来
                return "", chat_history
            except Exception as e:
                return e, chat_history
    
    import gradio as gr
    
    # 实例化核心功能对象
    model_center = Model_center()
    # 创建一个 Web 界面
    block = gr.Blocks()
    with block as demo:
        with gr.Row(equal_height=True):   
            with gr.Column(scale=15):
                # 展示的页面标题
                gr.Markdown("""

    InternLM

    书生浦语
    """
    ) with gr.Row(): with gr.Column(scale=4): # 创建一个聊天机器人对象 chatbot = gr.Chatbot(height=450, show_copy_button=True) # 创建一个文本框组件,用于输入 prompt。 msg = gr.Textbox(label="Prompt/问题") with gr.Row(): # 创建提交按钮。 db_wo_his_btn = gr.Button("Chat") with gr.Row(): # 创建一个清除按钮,用于清除聊天机器人组件的内容。 clear = gr.ClearButton( components=[chatbot], value="Clear console") # 设置按钮的点击事件。当点击时,调用上面定义的 qa_chain_self_answer 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。 db_wo_his_btn.click(model_center.qa_chain_self_answer, inputs=[ msg, chatbot], outputs=[msg, chatbot]) gr.Markdown("""提醒:
    1. 初始化数据库时间可能较长,请耐心等待。 2. 使用中如果出现异常,将会在文本输入框进行展示,请不要惊慌。
    """
    ) gr.close_all() # 直接启动 demo.launch()
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    通过将上述代码封装为 run_gradio.py 脚本,直接通过 python 命令运行,即可在本地启动知识库助手的 Web Demo,默认会在 7860 端口运行,接下来将服务器端口映射到本地端口即可访问

  • 相关阅读:
    自定义Feign的配置
    Python自动化测试之request库(五)
    C++----智能指针
    深度解析NLP定义、应用与PyTorch实战
    购物单-蓝桥杯
    搭载紫光展锐V510平台 移远通信RG500U-EA 5G模组获全球首个GCF认证
    【从零开始学习 SystemVerilog】8.17、SystemVerilog 约束—— Disable Randomization(关闭随机)
    推荐系统最经典的 排序模型 有哪些?你了解多少?
    GAN 生成对抗神经网络
    MySQL VARCHAR(M)最多能存储多少数据
  • 原文地址:https://blog.csdn.net/yichao_ding/article/details/136640599