【GLM-4部署实战】GLM-4-9B-Chat模型之对话机器人部署测试

系列篇章💥

No.文章
1【GLM-4部署实战】GLM-4-9B-Chat模型本地部署实践指南
2【GLM-4部署实战】GLM-4-9B-Chat模型之对话机器人部署测试
3【GLM-4部署实战】GLM-4-9B-Chat模型之vLLM部署推理实践
4【GLM-4微调实战】GLM-4-9B-Chat模型之Lora微调实战


引言

在人工智能的浪潮中,对话机器人作为人机交互的重要形式,正逐渐渗透到我们生活的方方面面。GLM-4-9B-Chat模型,以其强大的语言处理能力,为构建智能对话系统提供了坚实的基础。本文将带你一步步完成该模型的部署和测试,让你亲眼见证一个高效对话机器人的诞生。

一、环境准备

我们需要租用一台装有24G显存的显卡机器,例如NVIDIA 4090,以满足模型训练和部署的硬件需求。在挑选镜像时,建议选择PyTorch-2.1.0-3.10(ubuntu22.04)-12.1,这将为我们提供一个稳定且功能丰富的开发环境。完成机器租用流程后,启动JupyterLab并开启终端,开始进行环境配置。
在这里插入图片描述

二、安装依赖

  1. 升级pip&配置镜像
python -m pip install --upgrade pip
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
  1. 安装相关依赖包:
pip install torch>=2.3.0
pip install torchvision>=0.18.0
pip install transformers>=4.42.4
pip install huggingface-hub>=0.24.0
pip install sentencepiece>=0.2.0
pip install jinja2>=3.1.4
pip install pydantic>=2.8.2
pip install timm>=1.0.7
pip install tiktoken>=0.7.0
pip install accelerate>=0.32.1
pip install sentence_transformers>=3.0.1
pip install gradio>=4.38.1 # web demo
pip install openai>=1.35.0 # openai demo
pip install einops>=0.8.0
pip install pillow>=10.4.0
pip install sse-starlette>=2.1.2
pip install bitsandbytes>=0.43.1 # INT4 Loading

三、模型下载

使用 modelscope 中的 snapshot_download 函数下载模型。第一个参数为模型名称,参数 cache_dir 用于指定模型的下载路径。

import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('ZhipuAI/glm-4-9b-chat', cache_dir='/root/autodl-tmp', revision='master')

在 /root/autodl-tmp 路径下新建 download-model.py 文件,并在其中输入以上内容:
在这里插入图片描述

运行 python /root/autodl-tmp/download-model.py 执行下载。需注意,模型大小约为 18 GB,下载模型大概需要 10 - 20 分钟,请耐心等待。
在这里插入图片描述

四、代码准备

在 /root/autodl-tmp 路径下新建 trans_web_demo.py 文件,并在其中输入以下内容:

"""
此脚本使用Gradio为GLM-4-9B模型创建了一个交互式Web演示,
Gradio是一个用于为机器学习模型构建快速且易于使用的UI组件的Python库。
它旨在通过用户友好的界面展示GLM-4-9B模型的能力,允许用户通过类似聊天的界面与模型进行交互。
"""

import os
from pathlib import Path
from threading import Thread
from typing import Union

import gradio as gr
import torch
from peft import AutoPeftModelForCausalLM, PeftModelForCausalLM
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    PreTrainedModel,
    PreTrainedTokenizer,
    PreTrainedTokenizerFast,
    StoppingCriteria,
    StoppingCriteriaList,
    TextIteratorStreamer
)

ModelType = Union[PreTrainedModel, PeftModelForCausalLM]
TokenizerType = Union[PreTrainedTokenizer, PreTrainedTokenizerFast]

MODEL_PATH = os.environ.get('MODEL_PATH', '/root/autodl-tmp/ZhipuAI/glm-4-9b-chat')
TOKENIZER_PATH = os.environ.get("TOKENIZER_PATH", MODEL_PATH)


def _resolve_path(path: Union[str, Path]) -> Path:
    return Path(path).expanduser().resolve()


def load_model_and_tokenizer(
        model_dir: Union[str, Path], trust_remote_code: bool = True
) -> tuple[ModelType, TokenizerType]:
    model_dir = _resolve_path(model_dir)
    if (model_dir / 'adapter_config.json').exists():
        model = AutoPeftModelForCausalLM.from_pretrained(
            model_dir, trust_remote_code=trust_remote_code, device_map='auto'
        )
        tokenizer_dir = model.peft_config['default'].base_model_name_or_path
    else:
        model = AutoModelForCausalLM.from_pretrained(
            model_dir, trust_remote_code=trust_remote_code, device_map='auto'
        )
        tokenizer_dir = model_dir
    tokenizer = AutoTokenizer.from_pretrained(
        tokenizer_dir, trust_remote_code=trust_remote_code, use_fast=False
    )
    return model, tokenizer


model, tokenizer = load_model_and_tokenizer(MODEL_PATH, trust_remote_code=True)


class StopOnTokens(StoppingCriteria):
    def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:
        stop_ids = model.config.eos_token_id
        for stop_id in stop_ids:
            if input_ids[0][-1] == stop_id:
                return True
        return False


def parse_text(text):
    lines = text.split("\n")
    lines = [line for line in lines if line != ""]
    count = 0
    for i, line in enumerate(lines):
        if "```" in line:
            count += 1
            items = line.split('`')
            if count % 2 == 1:
                lines[i] = f'<pre><code class="language-{items[-1]}">'
            else:
                lines[i] = f'<br></code></pre>'
        else:
            if i > 0:
                if count % 2 == 1:
                    line = line.replace("`", "\`")
                    line = line.replace("<", "&lt;")
                    line = line.replace(">", "&gt;")
                    line = line.replace(" ", "&nbsp;")
                    line = line.replace("*", "&ast;")
                    line = line.replace("_", "&lowbar;")
                    line = line.replace("-", "&#45;")
                    line = line.replace(".", "&#46;")
                    line = line.replace("!", "&#33;")
                    line = line.replace("(", "&#40;")
                    line = line.replace(")", "&#41;")
                    line = line.replace("$", "&#36;")
                lines[i] = "<br>" + line
    text = "".join(lines)
    return text


def predict(history, prompt, max_length, top_p, temperature):
    stop = StopOnTokens()
    messages = []
    if prompt:
        messages.append({"role": "system", "content": prompt})
    for idx, (user_msg, model_msg) in enumerate(history):
        if prompt and idx == 0:
            continue
        if idx == len(history) - 1 and not model_msg:
            messages.append({"role": "user", "content": user_msg})
            break
        if user_msg:
            messages.append({"role": "user", "content": user_msg})
        if model_msg:
            messages.append({"role": "assistant", "content": model_msg})

    model_inputs = tokenizer.apply_chat_template(messages,
                                                 add_generation_prompt=True,
                                                 tokenize=True,
                                                 return_tensors="pt").to(next(model.parameters()).device)
    streamer = TextIteratorStreamer(tokenizer, timeout=60, skip_prompt=True, skip_special_tokens=True)
    generate_kwargs = {
        "input_ids": model_inputs,
        "streamer": streamer,
        "max_new_tokens": max_length,
        "do_sample": True,
        "top_p": top_p,
        "temperature": temperature,
        "stopping_criteria": StoppingCriteriaList([stop]),
        "repetition_penalty": 1.2,
        "eos_token_id": model.config.eos_token_id,
    }
    t = Thread(target=model.generate, kwargs=generate_kwargs)
    t.start()
    for new_token in streamer:
        if new_token:
            history[-1][1] += new_token
        yield history


with gr.Blocks() as demo:
    gr.HTML("""<h1 align="center">GLM-4-9B Gradio Simple Chat Demo</h1>""")
    chatbot = gr.Chatbot()

    with gr.Row():
        with gr.Column(scale=3):
            with gr.Column(scale=12):
                user_input = gr.Textbox(show_label=False, placeholder="Input...", lines=10, container=False)
            with gr.Column(min_width=32, scale=1):
                submitBtn = gr.Button("Submit")
        with gr.Column(scale=1):
            prompt_input = gr.Textbox(show_label=False, placeholder="Prompt", lines=10, container=False)
            pBtn = gr.Button("Set Prompt")
        with gr.Column(scale=1):
            emptyBtn = gr.Button("Clear History")
            max_length = gr.Slider(0, 32768, value=8192, step=1.0, label="Maximum length", interactive=True)
            top_p = gr.Slider(0, 1, value=0.8, step=0.01, label="Top P", interactive=True)
            temperature = gr.Slider(0.01, 1, value=0.6, step=0.01, label="Temperature", interactive=True)


    def user(query, history):
        return "", history + [[parse_text(query), ""]]


    def set_prompt(prompt_text):
        return [[parse_text(prompt_text), "成功设置prompt"]]


    pBtn.click(set_prompt, inputs=[prompt_input], outputs=chatbot)

    submitBtn.click(user, [user_input, chatbot], [user_input, chatbot], queue=False).then(
        predict, [chatbot, prompt_input, max_length, top_p, temperature], chatbot
    )
    emptyBtn.click(lambda: (None, None), None, [chatbot, prompt_input], queue=False)

demo.queue()
demo.launch(server_name="127.0.0.1", server_port=6006, inbrowser=True, share=True)

五、启动web chat

使用以下命令启动web服务,将对话机器人部署为一个web应用:

python trans_web_demo.py 

启动成功如下:
在这里插入图片描述

六、web chat对话测试

在web chat启动后,进行对话测试以验证机器人的响应能力和交互体验;观察机器人的回答是否准确、合理。
访问地址:http://localhost:6006/
在这里插入图片描述

提问:什么是机器学习?
回复:

机器学习是一种使计算机系统能够从数据中学习和改进的技术。它属于人工智能(AI)的一个子领域。以下是机器学习的几个关键点:
1.定义:机器学习是指让计算机通过数据和经验来自我学习和提高其性能的过程。
2.核心概念:
算法:用于处理数据的数学模型。
训练集:提供给模型的原始数据集合,用于教会模型如何识别模式和做出预测或决策。
测试集/验证集:用来评估模型在未见过的数据上的表现的数据集合。
泛化能力:指模型在新数据上继续准确工作的能力。
3.类型:
监督学习:使用带有标签的训练数据来“教授”模型如何对未知数据进行分类或回归。
无监督学习:没有明确的输出值,系统尝试找出数据中的结构、关联和模式。
半监督学习:结合了有监督和无监督学习方法,使用少量标记数据和大量未标记数据。
强化学习:通过与环境的交互进行学习,并不断优化策略以获得最大化的奖励。
4.应用:机器学习被广泛应用于各种领域中,包括但不限于图像和语音识别、自然语言处理、推荐系统、金融分析、医疗诊断等。
5.挑战:尽管机器学习取得了显著进展,但仍然存在一些挑战,如数据隐私保护、偏见与公平性、可解释性和计算效率问题。
简而言之,机器学习是构建能够执行特定任务并在完成这些任务的性能上自我提升的系统的科学。

效果截图如下:
在这里插入图片描述

结语

通过本文的实战演练,我们不仅掌握了GLM-4-9B-Chat模型的部署流程,还实现了一个能够进行流畅对话的机器人。希望大家能够将本文的知识应用到自己的项目中,不断提升对话系统的性能。随着技术的不断进步,我们期待与大家共同探索更多高效、创新的对话系统部署方案,以推动人工智能技术的进一步发展。

在这里插入图片描述

🎯🔖更多专栏系列文章:AI大模型提示工程完全指南AI大模型探索之路(零基础入门)AI大模型预训练微调进阶AI大模型开源精选实践AI大模型RAG应用探索实践🔥🔥🔥 其他专栏可以查看博客主页📑

😎 作者介绍:我是寻道AI小兵,资深程序老猿,从业10年+、互联网系统架构师,目前专注于AIGC的探索。
📖 技术交流:欢迎关注【小兵的AI视界】公众号或扫描下方👇二维码,加入技术交流群,开启编程探索之旅。
💘精心准备📚500本编程经典书籍、💎AI专业教程,以及高效AI工具。等你加入,与我们一同成长,共铸辉煌未来。
如果文章内容对您有所触动,别忘了点赞、⭐关注,收藏!加入我,让我们携手同行AI的探索之旅,一起开启智能时代的大门!

评论 84
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值