如何在服务器上部署开源大模型 GLM-4-9B-Chat 并应用到RAG应用中

本地服务器部署开源大模型有一个前提,就是得有 GPU 显卡资源,在我下面的例子中我租用了 autodl 中的算力资源,具体是租用了一张消费级别的 RTX 3090 显卡。

在这里插入图片描述

环境配置

  • 操作系统及版本:ubuntu 22.04
  • CUDA 版本: 12.1
  • pytorch 版本:2.3.0+cu121

pip 换源和安装依赖包。

在这里插入图片描述

这里要注意 transformers 的版本是 4.42.4

模型下载

GLM-4-9B-Chat 模型大小为 18 GB,下载模型大概需要 10~20 分钟。

由于后面我们要使用一个开源的 embedding 模型 BAAI/bge-base-zh-v1.5

所以使用以下代码下载 2 个模型文件到本地文件系统:

运行 python download.py

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')
embedding_model_dir = snapshot_download('BAAI/bge-base-zh-v1.5', cache_dir='/root/autodl-tmp', revision='master')

模型测试

GLM 开源模型官方给了一个 Demo 方便我们做测试,以下是代码:

运行 python trans_cli_demo.py

"""
This script creates a CLI demo with transformers backend for the glm-4-9b model,
allowing users to interact with the model through a command-line interface.Usage:
- Run the script to start the CLI demo.
- Interact with the model by typing questions and receiving responses.Note: The script includes a modification to handle markdown to plain text conversion,
ensuring that the CLI interface displays formatted text correctly.If you use flash attention, you should install the flash-attn and  add attn_implementation="flash_attention_2" in model loading.
"""import os
import torch
from threading import Thread
from transformers import AutoTokenizer, StoppingCriteria, StoppingCriteriaList, TextIteratorStreamer, AutoModelForCausalLMMODEL_PATH = os.environ.get('MODEL_PATH', '/root/autodl-tmp/ZhipuAI/glm-4-9b-chat')tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)model = AutoModelForCausalLM.from_pretrained(MODEL_PATH,    trust_remote_code=True,    device_map="auto"
).eval()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 Falseif __name__ == "__main__":history = []    max_length = 8192    top_p = 0.8    temperature = 0.6    stop = StopOnTokens()    print("Welcome to the GLM-4-9B CLI chat. Type your messages below.")    while True:     user_input = input("\nYou: ")        if user_input.lower() in ["exit", "quit"]:         break        history.append([user_input, ""])        messages = []        for idx, (user_msg, model_msg) in enumerate(history):         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(model.device)        streamer = TextIteratorStreamer(         tokenizer=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": False,  # 改为 False            "top_p": top_p,            "temperature": temperature,            "stopping_criteria": StoppingCriteriaList([stop]),            "repetition_penalty": 1.2,            "eos_token_id": model.config.eos_token_id,        }        try:       t = Thread(target=model.generate, kwargs=generate_kwargs)            t.start()            print("GLM-4:", end="", flush=True)            for new_token in streamer:             if new_token:               print(new_token, end="", flush=True)                    history[-1][1] += new_token        except Exception as e:        print(f"An error occurred: {e}")            print(f"Error type: {type(e)}")            import traceback            traceback.print_exc()   history[-1][1] = history[-1][1].strip()

注意以上代码和 GLM 官方提供的可能不太一样,因为官方的有的报错,所以我略为修改了一下。

直接运行 trans_cli_demo.py 就可以和模型交互了

在这里插入图片描述

利用 FastApi 调用模型

运行以下代码创建并启动 Api 服务:

运行 python api.py

from fastapi import FastAPI, Request
from transformers import AutoTokenizer, AutoModelForCausalLM
import uvicorn
import json
import datetime
import torch# 设置设备参数
DEVICE = "cuda"  # 使用CUDA
DEVICE_ID = "0"  # CUDA设备ID,如果未设置则为空
CUDA_DEVICE = f"{DEVICE}:{DEVICE_ID}" if DEVICE_ID else DEVICE  # 组合CUDA设备信息# 清理GPU内存函数
def torch_gc():if torch.cuda.is_available():  # 检查是否可用CUDA    with torch.cuda.device(CUDA_DEVICE):  # 指定CUDA设备       torch.cuda.empty_cache()  # 清空CUDA缓存            torch.cuda.ipc_collect()  # 收集CUDA内存碎片# 创建FastAPI应用
app = FastAPI()# 处理POST请求的端点
@app.post("/")
async def create_item(request: Request):global model, tokenizer  # 声明全局变量以便在函数内部使用模型和分词器    json_post_raw = await request.json()  # 获取POST请求的JSON数据    json_post = json.dumps(json_post_raw)  # 将JSON数据转换为字符串    json_post_list = json.loads(json_post)  # 将字符串转换为Python对象    prompt = json_post_list.get('prompt')  # 获取请求中的提示    history = json_post_list.get('history')  # 获取请求中的历史记录    max_length = json_post_list.get('max_length', 2048)  # 获取请求中的最大长度    top_p = json_post_list.get('top_p', 0.7)  # 获取请求中的top_p参数    temperature = json_post_list.get('temperature', 0.95)  # 获取请求中的温度参数    # 准备输入    messages = []    if history:     for h in history:         messages.append({"role": "user", "content": h[0]})            messages.append({"role": "assistant", "content": h[1]})    messages.append({"role": "user", "content": prompt})    input_ids = tokenizer.apply_chat_template(messages, return_tensors="pt").to(model.device)  # 生成回复    with torch.no_grad():     outputs = model.generate(         input_ids,            max_new_tokens=max_length,            do_sample=True,            top_p=top_p,            temperature=temperature,        )    response = tokenizer.decode(outputs[0][input_ids.shape[1]:], skip_special_tokens=True)    now = datetime.datetime.now()  # 获取当前时间    time = now.strftime("%Y-%m-%d %H:%M:%S")  # 格式化时间为字符串    # 构建响应JSON    answer = {     "response": response,        "history": history + [[prompt, response]],        "status": 200,        "time": time    }    # 构建日志信息    log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr(response) + '"'    print(log)  # 打印日志    torch_gc()  # 执行GPU内存清理    return answer  # 返回响应# 主函数入口
if __name__ == '__main__':# 加载预训练的分词器和模型    tokenizer = AutoTokenizer.from_pretrained("/root/autodl-tmp/ZhipuAI/glm-4-9b-chat", trust_remote_code=True)    model = AutoModelForCausalLM.from_pretrained(      "/root/autodl-tmp/ZhipuAI/glm-4-9b-chat",        torch_dtype=torch.bfloat16,        trust_remote_code=True,        device_map="auto",    )    model.eval()  # 设置模型为评估模式    # 启动FastAPI应用    # 用6006端口可以将autodl的端口映射到本地,从而在本地使用api    uvicorn.run(app, host='0.0.0.0', port=6006, workers=1)  # 在指定端口和主机上启动应用

测试服务

curl -X POST "http://127.0.0.1:6006" \-H 'Content-Type: application/json' \     -d '{"prompt": "你好", "history": []}'     

利用 FastApi 同样可以测试模型的调用和交互。

在这里插入图片描述

注意,以上代码你可能会在网络上找到类似的,我在最开始使用那些代码的时候报各种错,原因大概包括模型和代码版本不兼容,组件库版本问题等。所以以上代码是经过我的修改之后可运行的代码

RAG

我们通过 Ollama 在笔记本电脑上部署过大模型,通过大模型产品的 API 调用过大模型 ,唯独没有在服务器上私有化部署一个大模型。

前文我们已经在服务器上部署好了大模型 glm-4-9b-chat 这是一个拥有 90 亿参数的模型。下面我们介绍如何在 llamaindex 中调用它。

很简单,首先我们还是先自定义一个LLM ,参考以下代码:

import logging
from typing import Any, List, Optional
from llama_index.core.llms import (CustomLLM,    CompletionResponse,    CompletionResponseGen,    LLMMetadata,
)
from llama_index.core.llms.callbacks import llm_completion_callback
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch# 设置日志
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)class LocalGLM4(CustomLLM):context_window: int = 8192  # 默认上下文窗口大小    num_output: int = 2048  # 默认输出的token数量    model_name: str = "glm-4-9b-chat"  # 模型名称    tokenizer: object = None  # 分词器    model: object = None  # 模型    def __init__(self, pretrained_model_name_or_path: str):     super().__init__()        # GPU方式加载模型        self.tokenizer = AutoTokenizer.from_pretrained(          pretrained_model_name_or_path, trust_remote_code=True        )        self.model = AutoModelForCausalLM.from_pretrained( pretrained_model_name_or_path,            torch_dtype=torch.float16,  # 或者使用 torch.bfloat16            low_cpu_mem_usage=True,            trust_remote_code=True,            device_map="auto",        )        # CPU方式加载模型        # self.tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path, device_map="cpu", trust_remote_code=True)        # self.model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path, device_map="cpu", trust_remote_code=True)        # self.model = self.model.float()      # 尝试获取模型的实际上下文窗口大小        if hasattr(self.model.config, 'seq_length'):          self.context_window = self.model.config.seq_length        elif hasattr(self.model.config, 'max_position_embeddings'):        self.context_window = self.model.config.max_position_embeddings        logger.info(f"Using context window size: {self.context_window}")    @property    def metadata(self) -> LLMMetadata:     """Get LLM metadata."""        # 得到LLM的元数据        return LLMMetadata(         context_window=self.context_window,            num_output=self.num_output,            model_name=self.model_name,        )    @llm_completion_callback()    def complete(self, prompt: str, **kwargs: Any) -> CompletionResponse:     # 完成函数        print("完成函数")     inputs = self.tokenizer.encode(prompt, return_tensors="pt").cuda()  # GPU方式        # inputs = self.tokenizer.encode(prompt, return_tensors='pt')  # CPU方式        outputs = self.model.generate(inputs, max_length=self.num_output)        response = self.tokenizer.decode(outputs[0])        return CompletionResponse(text=response)   @llm_completion_callback()    def stream_complete(self, prompt: str, **kwargs: Any) -> CompletionResponseGen:     # 流式完成函数        print("流式完成函数")        inputs = self.tokenizer.encode(prompt, return_tensors="pt").cuda()  # GPU方式        # inputs = self.tokenizer.encode(prompt, return_tensors='pt')  # CPU方式        outputs = self.model.generate(inputs, max_length=self.num_output)        response = self.tokenizer.decode(outputs[0])        for token in response:          yield CompletionResponse(text=token, delta=token)

剩下的步骤跟之前的调用方式、代码编程模型几乎没有任何区别:

在这里插入图片描述

相关代码可以在这里查看:https://github.com/xiaobox/llamaindex_test

总结

利用租用的 GPU 资源部署了开源大模型 glm-4-9b-chat ,通过熟悉部署方式和流程,你可以照猫画虎部署其他开源模型。接着我们将之前 RAG 项目中对LLM的调用改为服务器部署的本地开源模型,实现了模型和调用的私有化。希望这篇文章能够帮助到有类似需求的朋友。

如何学习AI大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/57510.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MATLAB源码-第263期】基于matlab的帝企鹅优化算法(EPO)无人机三维路径规划,输出做短路径图和适应度曲线.

操作环境: MATLAB 2022a 1、算法描述 帝企鹅优化算法(Emperor Penguin Optimizer,简称EPO)是一种基于自然现象的优化算法,灵感来自于帝企鹅在南极极寒环境中的生活习性。帝企鹅是一种群居动物,生活在极端…

再创佳绩 | 竹云荣获“数据要素×”大赛黑龙江分赛一等奖!

近日,由国家数据局、黑龙江省人民政府指导,黑龙江省发改委、黑龙江省数据局主办的2024年“数据要素”大赛黑龙江分赛决赛盛大召开。竹云作为联合单位参与《供热数据资产登记评价中心供热数据要素综合服务平台》项目,荣获绿色低碳赛道一等奖。…

C++ [项目] 愤怒的小鸟

现在才发现C游戏的支持率这么高,那就发几篇吧 零、前情提要 此篇为 制作,由于他没有CSDN,于是由我代发 一、基本介绍 支持Dev-C5.11版本(务必调为英文输入法),基本操作看游戏里的介绍,怎么做的……懒得说,能看懂就看注释,没有的自己猜,如果你很固执……私我吧 …

基于K8S的StatefulSet部署mysql主从

StatefulSet特性 StatefulSet的网络状态 拓扑状态:应用的多个实例必须按照某种顺序启动,并且必须成组存在,例如一个应用中必须存在一个A Pod和两个B Pod,且A Pod必须先于B Pod启动的场景 存储状态:应用存在多个实例&…

分享Vue3中的一个路由加载函数,基于Glob导入模式,根据路径自动生成路由

哈喽,大家好!我是「励志前端小黑哥」,我带着最新发布的文章又来了! 专注前端领域10年,专门分享那些没用的前端知识! 今天要分享的内容,是一段路由加载的函数代码,这段代码能自动读取…

Three.js实现小米 su7 压缩后的模型加载

Three.js实现小米 su7 压缩后的模型加载 预览: https://threehub.cn/#/codeMirror?navigationThreeJS&classifybasic&idgltfOptLoader import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js impo…

复旦大学全球供应链研究中心揭牌,合合信息共话大数据赋能

10月13日,复旦大学全球供应链研究中心(以下简称“中心”)揭牌仪式在复旦大学管理学院政立院区隆重举行。我国的供应链体系庞大复杂,在百年未有之大变局下,保障产业链供应链安全已成为我国的重要战略目标。中心的设立旨…

打造企业数字化转型的未来蓝图:架构蓝图的构建与实施策略深度解析

随着数字经济的蓬勃发展,全球企业正在经历前所未有的变革与挑战。企业的运营模式、客户体验和市场竞争格局都在迅速变化。为了应对这些挑战,企业必须从战略到技术层面进行深度重塑,架构蓝图的构建和实施是数字化转型过程中不可或缺的工具。架…

CSS - grid制作表格

1. grid-template-columns:网格布局中的列的数量,也可以设置列的宽度 .grid-container {display: grid;grid-template-columns: 80px 200px auto 40px; }.grid-container {display: grid;grid-template-columns: auto auto auto auto;//表示所有列的宽度…

Starrocks部署前期准备

前提条件 硬件要求 CPU StarRocks 依靠 AVX2 指令集充分发挥其矢量化能力。因此,在生产环境中,强烈建议您将 StarRocks 部署于 x86 架构 CPU 的服务器上。 您可以在终端中运行以下命令来检查 CPU 是否支持 AVX2 指令集: cat /proc/cpuin…

高效评优:基于SpringBoot的学生奖励管理系统

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理学生评奖评优管理系统的相关信息成为必然。…

[JAVAEE] 线程安全问题

目录 一. 什么是线程安全 二. 线程安全问题产生的原因 三. 线程安全问题的解决 3.1 解决修改操作不是原子性的问题 > 加锁 a. 什么是锁 b. 没有加锁时 c. 加锁时 d. 死锁 e. 避免死锁 3.2 解决内存可见性的问题 > volatile关键字 (易变的, 善变的) a. 不加…

古埃及象形文字在线字典

我在个人网站“小孔的埃及学站点”上推出了在线的象形文字字典,总共收罗了将近700条的象形文字(词)。在线字典的使用方法很简单,在网站各大版块首页的右上方会有如下图所示的查询入口。 点击文本框,输入中文或英文关键…

百度文心一言接入流程-java版

百度文心一言接入流程-java版 一、准备工作二、API接口调用-java三、百度Prompt工程参考资料: 百度文心一言:https://yiyan.baidu.com/百度千帆大模型:https://qianfan.cloud.baidu.com/百度千帆大模型文档:https://cloud.baidu.com/doc/WENXINWORKSHOP/index.html千tokens…

使用API有效率地管理Dynadot域名,通过域名命令删除域名服务器(NS)

前言 Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮箱&…

<Project-11 Calculator> 计算器 0.4 公制单位转换器 Metric Units Converter HTML JS

前言 这个参考的是时间转换器 <Project-11 Calculator> 计算器 0.1时间换算器 Time Conversion Calculator-CSDN博客,主要就是替换内容,相当于找不同。 改新内容 index.html 加了新页面链接 添加了 favicon.jpg 橘猫 就当是…

Qt开发-----线程调度

目录 前言 一、Linux下查看进程的情况 二、线程的创建 三、多线程的创建和使用 前言 以下引用内容源自正点原子Qt开发指南文档。 我们写的一个应用程序,应用程序跑起来后一般情况下只有一个线程,但是可能也有特殊情况。比如我们前面章节写的例程都跑…

让你的单细胞数据动起来!|iCellR(一)

今天在翻阅single cell 的github时候,我看见了这个R包,允许我们处理各种来自单细胞测序技术的数据,如scRNA-seq,scVDJ-seq和CITE-Seq。 单细胞转录组教程汇总 想看整套的学习流程还可以戳这里: https://vimeo.com/3…

CSS综合案例——新闻详情

一、知识点 1、文字颜色 属性名:color 属性值: 颜色表示方式属性值说明使用场景颜色关键字颜色英文单词red,green,blue学习测试rgb表示法rg(r,g,b)r,g,b表示红绿蓝三原色,取值0-255了解rgba表示法rgba(r,g,b,a)a表示透明度,取…

sed工具的基本使用

文章目录 sed工具介绍什么是sed工具,有什么用sed命令执行流程sed是按行读取文件的每当读取一行内容,都会进行一次判断,判断是否是想要的行默认不实质改变文件内容,仅临时输出给用户看(除非加-i选项)例1 例2…