ChatGPT(全名:Chat Generative Pre-trained Transformer),是OpenAI研发的一款聊天机器人程序,于2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语言处理工具,它能够基于在预训练阶段所见的模式和统计规律,来生成回答,还能根据聊天的上下文进行互动,真正像人类一样来聊天交流,甚至能完成撰写邮件、视频脚本、文案、翻译、代码,写论文等任务。
但是自己想要部署一套ChatGPT的话,首先数据集没有开源,其次对于硬件的要求,不可估量。所幸清华大学知识工程和数据挖掘小组(Knowledge Engineering Group (KEG) & Data Mining at Tsinghua University)发布的一个开源的对话机器人ChatGLM-6B。
ChatGLM 参考了 ChatGPT 的设计思路,在千亿基座模型 GLM-130B 中注入了代码预训练,通过有监督微调(Supervised Fine-Tuning)等技术实现人类意图对齐。ChatGLM 当前版本模型的能力提升主要来源于独特的千亿基座模型 GLM-130B。它是不同于 BERT、GPT-3 以及 T5 的架构,是一个包含多目标函数的自回归预训练模型。2022年8月,我们向研究界和工业界开放了拥有1300亿参数的中英双语稠密模型 GLM-130B,该模型有一些独特的优势:
2022年11月,斯坦福大学大模型中心对全球30个主流大模型进行了全方位的评测,GLM-130B 是亚洲唯一入选的大模型。在与 OpenAI、谷歌大脑、微软、英伟达、脸书的各大模型对比中,评测报告显示 GLM-130B 在准确性和恶意性指标上与 GPT-3 175B (davinci) 接近或持平,鲁棒性和校准误差在所有千亿规模的基座大模型(作为公平对比,只对比无指令提示微调模型)中表现不错(下图)。
关于 GLM-130B 的学术文章已被国际深度学习会议 ICLR'23 接收。自2022年8月开放以来,收到53个国家369个研究机构(截至2023年2月1日)的下载使用需求,包括谷歌、微软、脸书、AI2、华为、阿里巴巴、百度、腾讯、头条、小冰、小度、小米以及斯坦福、麻省理工、伯克利、卡耐基梅隆、哈佛、剑桥、牛津、北大、浙大、上交、复旦、中科大、国科大等国内外人工智能研究机构和高校。
通过使用与 ChatGLM(chatglm.cn)相同的技术,ChatGLM-6B 初具中文问答和对话功能,并支持在单张 2080Ti 上进行推理使用。具体来说,ChatGLM-6B 有如下特点:
因此,ChatGLM-6B 具备了一定条件下较好的对话与问答能力。当然,ChatGLM-6B 也有相当多已知的局限和不足:
高性能应用服务 HAI:澎湃算力,即开即用。以应用为中心,匹配GPU云算力资源,助力中小企业及开发者快速部署LLM、AI作画、数据科学等高性能应用。是为开发者量身打造的澎湃算力平台。无需复杂配置,便可享受即开即用的GPU云服务体验。在 HAI 中,根据应用智能匹配并推选出最适合的GPU算力资源,以确保您在数据科学、LLM、AI作画等高性能应用中获得最佳性价比。
智能选型 :根据应用匹配推选GPU算力资源,实现最高性价比。同时,打通必备云服务组件,大幅简化云服务配置流程。undefined 一键部署 :分钟级自动构建LLM、AI作画等应用环境。提供多种预装模型环境,包含如StableDiffusion、ChatGLM等热门模型。undefined 可视化界面 :友好的图形界面,AI调试更为简单
即插即用 · 轻松上手
基于腾讯云GPU云服务器底层算力,提供即插即用的高性能云服务。
智能选型
根据应用匹配推选GPU算力资源,实现最高性价比。同时,打通必备云服务组件,大幅简化云服务配置流程。
一键部署
分钟级自动构建LLM、AI作画等应用环境。提供多种预装模型环境,包含如StableDiffusion、ChatGLM等热门模型。
可视化界面
提供开发者友好的图形界面,支持jupyterlab、webui等多种算力连接方式,AI研究调试超低门槛。
大幅降低GPU云服务器使用门槛,多角度优化产品使用体验,开箱即用
AI作画(视觉设计、游戏)
基于StableDiffusion开源模型进行AI绘画
场景介绍
AI绘画是一种利用深度学习算法进行创作的绘图方式。广泛应用于数字媒体、游戏、动画、电影、广告等领域。
业务痛点
产品优势
AI对话/写作(Agent、企业知识库)大语言模型
基于开源大语言模型,创作属于自己的Agent、企业知识库
场景介绍
大语言模型在广泛的文本数据上进行训练,可以执行广泛的任务,包括文本总结、翻译、情感分析等等。
业务痛点
业务痛点
AI开发/测试(学术研究、论文)算法研发
学术研究、论文
场景介绍
面向高校、研究所等大量科研场景,需针对深度学习、机器学习等前沿算法进行开发探索。
业务痛点
业务痛点
基于HAI部署的 ChatGLM2-6B 快速进行AI对话 基于HAI部署的 ChatGLM2-6B API 快速实现开发者所需的相关API服务 基于HAI部署的 ChatGLM2-6B API 快速实现模型的微调
本次我们使用 腾讯云高性能应用服务 HAI 体验快速搭建并使用AI模型 ChatGLM2-6B ,实现思路如下:
1、体验 高性能应用服务HAI 一键部署 ChatGLM2-6B 2、启动 ChatGLM2-6B WebUI 进行简单的对话 3、开发者体验 JupyterLab 、 Cloud Studio 进行 ChatGLM2-6B API 的配置调用 4、开发者使用 Cloud Studio 应用推荐 ChatGPT Next Web 快速开发调用 ChatGLM2-6B OpenAI API 服务,搭建自己的GPT 5、开发者使用 高性能应用服务HAI 快速部署 ChatGLM2-6B-int4 本地模型及基于 P-Tuning v2 的微调
使用 ChatGLM2-6B WebUI 进行简单的对话
Cloud Studio 进行 ChatGLM2-6B API 的调用
Cloud Studio 调用 ChatGLM2-6B 流式 API 接口
Cloud Studio 创建应用 ChatGPT Next Web 并快速调用 ChatGLM2-6B OpenAI API 接口
开发者使用 高性能应用服务HAI 训练 ChatGLM2-6B 本地模型
开发者使用 高性能应用服务HAI 测试训练完成后的ChatGLM2-6B 模型
① . 点击链接进入 高性能应用服务 HAI 申请体验资格
② . 等待审核通过后,进入 高性能应用服务 HAI
③ . 点击前往体验HAI,登录 高性能应用服务 HAI 控制台
③ . 点击 新建 选择 AI模型,输入实例名称
④ . 等待创建完成 (预计等待3-8分钟,等待时间不计费)
⑤ . 创建完成,查看相关状态
⑥ . 查看配置详情
① . 选择 chatglm2_gradio 进入 WebUI 页面
② . 体验与 ChatGLM2-6B 简单的对话
① .使用 JupyterLab 启动 ChatGLM2-6B 提供的 API 服务
(1) .在 算力管理 页面,选择进入 jupyter_lab 页面
选择 终端命令
输入命令 用于开启 API 服务:
cd ./ChatGLM2-6B
python api.py
(2) .新增服务器端口规则
选择 编辑规则
选择 入站规则 中的添加规则
添加入站规则 (来源: 0.0.0.0/0 协议端口: TCP:8000)
② .使用 Cloud Studio 快速调用测试 ChatGLM2-6B 提供的 API 服务
(1) .打开 Cloud Studio 并创建开发空间
新建工作空间 输入 空间名称 ,选择 代码来源为空 ,开发环境 Python 即可
等待数十秒 工作空间启动完成
(2) .编写调用代码并运行测试
在 workspace 下右键选择 新建文件
创建 get_api.py 代码文件,并复制以下代码 用于测试请求
注意: 请确保将代码中的地址和端口更改为您的API服务器的实际地址和端口
import requests
# 定义测试数据,以及FastAPI服务器的地址和端口
server_url = "http://0.0.0.0:8000" # 请确保将地址和端口更改为您的API服务器的实际地址和端口
test_data = {
"prompt": "'你好,发热了怎么办?'",
"history": [],
"max_length": 50,
"top_p": 0.7,
"temperature": 0.95
}
# 发送HTTP POST请求
response = requests.post(server_url, json=test_data)
# 处理响应
if response.status_code == 200:
result = response.json()
print("Response:", result["response"])
print("History:", result["history"])
print("Status:", result["status"])
print("Time:", result["time"])
else:
print("Failed to get a valid response. Status code:", response.status_code)
查看 ChatGLM2-6B 实例 公网地址,并修改代码中 服务器地址 部分
修改完代码文件,可点击右上角的运行按钮进行测试
返回请求结果:
服务器端可查看记录并使用 Ctrl+C 关闭服务:
③ .使用 JupyterLab 开发 ChatGLM2-6B 流式返回 API 接口并使用 Cloud Studio 快速调用测试
(1) .使用 JupyterLab 编写基于 FastAPI 编写的服务器端代码并开启服务
在 JupyterLab 中选择文件夹操作界面,依次打开 root 文件夹下的 ChatGLM2-6B 文件夹,并创建一个 Python File ,拷贝一下代码并保存,同时将文件名修改为 chatglm2-6b-stream-api.py ,最后开启API服务
创建Python文件
粘贴 chatglm2-6b-stream-api.py 代码
# -*-coding:utf-8-*-
'''
File Name:chatglm2-6b-stream-api.py
Author:Luofan
Time:2023/6/26 13:33
'''
import os
import sys
import json
import torch
import uvicorn
import logging
import argparse
from fastapi import FastAPI
from transformers import AutoTokenizer, AutoModel
from fastapi.middleware.cors import CORSMiddleware
from sse_starlette.sse import ServerSentEvent, EventSourceResponse
def getLogger(name, file_name, use_formatter=True):
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
console_handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(asctime)s %(message)s')
console_handler.setFormatter(formatter)
console_handler.setLevel(logging.INFO)
logger.addHandler(console_handler)
if file_name:
handler = logging.FileHandler(file_name, encoding='utf8')
handler.setLevel(logging.INFO)
if use_formatter:
formatter = logging.Formatter('%(asctime)s - %(name)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
logger = getLogger('ChatGLM', 'chatlog.log')
MAX_HISTORY = 3
class ChatGLM():
def __init__(self) -> None:
logger.info("Start initialize model...")
self.tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", revision="v1.0", trust_remote_code=True)
self.model = AutoModel.from_pretrained("THUDM/chatglm2-6b", revision="v1.0", trust_remote_code=True).cuda()
self.model.eval()
logger.info("Model initialization finished.")
def clear(self) -> None:
if torch.cuda.is_available():
with torch.cuda.device(f"cuda:{args.device}"):
torch.cuda.empty_cache()
torch.cuda.ipc_collect()
def answer(self, query: str, history):
response, history = self.model.chat(self.tokenizer, query, history=history)
history = [list(h) for h in history]
return response, history
def stream(self, query, history):
if query is None or history is None:
yield {"query": "", "response": "", "history": [], "finished": True}
size = 0
response = ""
for response, history in self.model.stream_chat(self.tokenizer, query, history):
this_response = response[size:]
history = [list(h) for h in history]
size = len(response)
yield {"delta": this_response, "response": response, "finished": False}
logger.info("Answer - {}".format(response))
yield {"query": query, "delta": "[EOS]", "response": response, "history": history, "finished": True}
def start_server(http_address: str, port: int, gpu_id: str):
os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
os.environ['CUDA_VISIBLE_DEVICES'] = gpu_id
bot = ChatGLM()
app = FastAPI()
app.add_middleware(CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)
@app.get("/")
def index():
return {'message': 'started', 'success': True}
@app.post("/chat")
async def answer_question(arg_dict: dict):
result = {"query": "", "response": "", "success": False}
try:
text = arg_dict["query"]
ori_history = arg_dict["history"]
logger.info("Query - {}".format(text))
if len(ori_history) > 0:
logger.info("History - {}".format(ori_history))
history = ori_history[-MAX_HISTORY:]
history = [tuple(h) for h in history]
response, history = bot.answer(text, history)
logger.info("Answer - {}".format(response))
ori_history.append((text, response))
result = {"query": text, "response": response,
"history": ori_history, "success": True}
except Exception as e:
logger.error(f"error: {e}")
return result
@app.post("/stream")
def answer_question_stream(arg_dict: dict):
def decorate(generator):
for item in generator:
#yield ServerSentEvent(json.dumps(item, ensure_ascii=False), event='delta')
yield ServerSentEvent(json.dumps(item, ensure_ascii=False))
try:
text = arg_dict["query"]
ori_history = arg_dict["history"]
logger.info("Query - {}".format(text))
if len(ori_history) > 0:
logger.info("History - {}".format(ori_history))
history = ori_history[-MAX_HISTORY:]
history = [tuple(h) for h in history]
return EventSourceResponse(decorate(bot.stream(text, history)))
except Exception as e:
logger.error(f"error: {e}")
return EventSourceResponse(decorate(bot.stream(None, None)))
@app.get("/free_gc")
def free_gpu_cache():
try:
bot.clear()
return {"success": True}
except Exception as e:
logger.error(f"error: {e}")
return {"success": False}
logger.info("starting server...")
uvicorn.run(app=app, host=http_address, port=port, workers=1)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Stream API Service for ChatGLM2-6B')
parser.add_argument('--device', '-d', help='device,-1 means cpu, other means gpu ids', default='0')
parser.add_argument('--host', '-H', help='host to listen', default='0.0.0.0')
parser.add_argument('--port', '-P', help='port of this service', default=8000)
args = parser.parse_args()
start_server(args.host, int(args.port), args.device)
在 JupyterLab 中完成文件的创建并重命名 chatglm2-6b-stream-api.py 成功:
在 JupyterLab终端界面 中输入命令开启 chatglm2-6b-stream-api.py 服务:
python chatglm2-6b-stream-api.py
注意: 请将上一个 API服务 关闭,否则服务无法启动成功
(2) .使用 Cloud Studio 编写客户端代码
使用普通Http请求调用 /chat 接口
在 Cloud Studio 工作空间下继续创建 Python 代码文件 use_chatglm2-6b-stream-api.py
注意: 请将代码中的地址和端口更改为实际的服务器地址和端口
use_chatglm2-6b-stream-api.py 代码文件:
import requests
import json
# 设置服务器地址和端口
server_address = "http://0.0.0.0" # 请将地址和端口更改为实际的服务器地址和端口
server_port = 8000
# 构造请求数据
request_data = {
"query": "你好,发热了怎么办?",
"history": []
}
# 发送HTTP POST请求到聊天端点
response = requests.post(f"{server_address}:{server_port}/chat", json=request_data)
# 处理响应
if response.status_code == 200:
result = response.json()
if result["success"]:
print("Response:", result["response"])
print("History:", result["history"])
else:
print("Failed to get a valid response.")
else:
print("Failed to connect to the server. Status code:", response.status_code)
创建完成:
运行并查看返回结果:
在菜单栏中点击 终端 选择 新建终端,输入命令执行代码
python use_chatglm2-6b-stream-api.py
调用接口成功
服务端查看记录:
使用AioHttp调用 /stream 流式接口
在 Cloud Studio 工作空间下 继续创建 Python 代码文件 use_stream_chatglm2-6b-stream-api.py
注意: 请将代码中的地址和端口更改为实际的服务器地址和端口
use_stream_chatglm2-6b-stream-api.py 代码文件:
import aiohttp
import json
import asyncio
async def main():
async with aiohttp.ClientSession() as session:
server_address = "http://0.0.0.0" # 请将地址更改为实际的服务器地址
server_port = 8000
endpoint = f"{server_address}:{server_port}/stream" # 流式处理端点
request_data = {
"query": "你好,发热怎么办?",
"history": []
}
try:
async with session.post(endpoint, json=request_data, timeout=None) as response:
if response.status == 200:
async for line in response.content.iter_any():
data = line.decode('utf-8')
data = data.replace('event: delta\r\ndata: ','')
data = data.replace('\r\n','')
data = data.replace('data: ','')
try:
result = json.loads(data)
if result.get("finished"):
print("Response:", result["response"])
print('\r\n')
print("History:", result["history"])
#else:
# print("Delta:", result["delta"])
except json.JSONDecodeError:
print("Failed to parse JSON:")
else:
print(f"Failed to connect to the server. Status code: {response.status}")
except aiohttp.ClientError as e:
print(f"Client error occurred: {e}")
await asyncio.sleep(1) # Avoid continuous failures, wait a bit before retrying
print(f"Unexpected error occurred: {e}")
await asyncio.sleep(1) # Avoid continuous failures, wait a bit before retrying
if __name__ == '__main__':
asyncio.run(main())
在 终端 中输入命令 安装 aiohttp 模块
pip install aiohttp
运行并查看返回结果:
在 终端 中输入命令执行代码
python use_stream_chatglm2-6b-stream-api.py
① .使用 JupyterLab 修改 openai_api.py 代码并开启服务
打开 JupyterLab 后关闭上一次开启的 API 服务
使用 Ctrl+C 关闭服务
打开右边文件夹下的 openai_api.py 文件
如果直接使用会在调用时报错,复制以下 openai_api.py 代码直接覆盖源文件并 Ctrl+S 保存代码
# coding=utf-8
# Implements API for ChatGLM2-6B in OpenAI's format. (https://platform.openai.com/docs/api-reference/chat)
# Usage: python openai_api.py
# Visit http://localhost:8000/docs for documents.
import time
import torch
import uvicorn
from pydantic import BaseModel, Field
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from typing import Any, Dict, List, Literal, Optional, Union
from transformers import AutoTokenizer, AutoModel
from sse_starlette.sse import ServerSentEvent, EventSourceResponse
@asynccontextmanager
async def lifespan(app: FastAPI): # collects GPU memory
yield
if torch.cuda.is_available():
torch.cuda.empty_cache()
torch.cuda.ipc_collect()
app = FastAPI(lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class ModelCard(BaseModel):
id: str
object: str = "model"
created: int = Field(default_factory=lambda: int(time.time()))
owned_by: str = "owner"
root: Optional[str] = None
parent: Optional[str] = None
permission: Optional[list] = None
class ModelList(BaseModel):
object: str = "list"
data: List[ModelCard] = []
class ChatMessage(BaseModel):
role: Literal["user", "assistant", "system"]
content: str
class DeltaMessage(BaseModel):
role: Optional[Literal["user", "assistant", "system"]] = None
content: Optional[str] = None
class ChatCompletionRequest(BaseModel):
model: str
messages: List[ChatMessage]
temperature: Optional[float] = None
top_p: Optional[float] = None
max_length: Optional[int] = None
stream: Optional[bool] = False
class ChatCompletionResponseChoice(BaseModel):
index: int
message: ChatMessage
finish_reason: Literal["stop", "length"]
class ChatCompletionResponseStreamChoice(BaseModel):
index: int
delta: DeltaMessage
finish_reason: Optional[Literal["stop", "length"]]
class ChatCompletionResponse(BaseModel):
model: str
object: Literal["chat.completion", "chat.completion.chunk"]
choices: List[Union[ChatCompletionResponseChoice, ChatCompletionResponseStreamChoice]]
created: Optional[int] = Field(default_factory=lambda: int(time.time()))
@app.get("/v1/models", response_model=ModelList)
async def list_models():
global model_args
model_card = ModelCard(id="gpt-3.5-turbo")
return ModelList(data=[model_card])
@app.post("/v1/chat/completions", response_model=ChatCompletionResponse)
async def create_chat_completion(request: ChatCompletionRequest):
global model, tokenizer
if request.messages[-1].role != "user":
raise HTTPException(status_code=400, detail="Invalid request")
query = request.messages[-1].content
prev_messages = request.messages[:-1]
if len(prev_messages) > 0 and prev_messages[0].role == "system":
query = prev_messages.pop(0).content + query
history = []
if len(prev_messages) % 2 == 0:
for i in range(0, len(prev_messages), 2):
if prev_messages[i].role == "user" and prev_messages[i+1].role == "assistant":
history.append([prev_messages[i].content, prev_messages[i+1].content])
if request.stream:
generate = predict(query, history, request.model)
return EventSourceResponse(generate, media_type="text/event-stream")
response, _ = model.chat(tokenizer, query, history=history)
choice_data = ChatCompletionResponseChoice(
index=0,
message=ChatMessage(role="assistant", content=response),
finish_reason="stop"
)
return ChatCompletionResponse(model=request.model, choices=[choice_data], object="chat.completion")
async def predict(query: str, history: List[List[str]], model_id: str):
global model, tokenizer
choice_data = ChatCompletionResponseStreamChoice(
index=0,
delta=DeltaMessage(role="assistant"),
finish_reason=None
)
chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
#yield "{}".format(chunk.json(exclude_unset=True, ensure_ascii=False))
yield "{}".format(chunk.model_dump_json(exclude_unset=True))
current_length = 0
for new_response, _ in model.stream_chat(tokenizer, query, history):
if len(new_response) == current_length:
continue
new_text = new_response[current_length:]
current_length = len(new_response)
choice_data = ChatCompletionResponseStreamChoice(
index=0,
delta=DeltaMessage(content=new_text),
finish_reason=None
)
chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
#yield "{}".format(chunk.json(exclude_unset=True, ensure_ascii=False))
yield "{}".format(chunk.model_dump_json(exclude_unset=True))
choice_data = ChatCompletionResponseStreamChoice(
index=0,
delta=DeltaMessage(),
finish_reason="stop"
)
chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
#yield "{}".format(chunk.json(exclude_unset=True, ensure_ascii=False))
yield "{}".format(chunk.model_dump_json(exclude_unset=True))
yield '[DONE]'
if __name__ == "__main__":
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", revision="v1.0", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm2-6b", revision="v1.0", trust_remote_code=True).cuda()
# 多显卡支持,使用下面两行代替上面一行,将num_gpus改为你实际的显卡数量
# from utils import load_model_on_gpus
# model = load_model_on_gpus("THUDM/chatglm2-6b", num_gpus=2)
model.eval()
uvicorn.run(app, host='0.0.0.0', port=8000, workers=1)
修改后的 openai_api.py 示意图:
服务端开启服务:
python openai_api.py
② .使用 Cloud Studio 快速创建 应用推荐 下的 ChatGPT Next Web 开源项目
打开 Cloud Studio 开发空间下,我们创建的项目,并停止服务。
成功后,打开 应用推荐 选择 ChatGPT Next Web 项目
选择 Fork
等待数秒后,工作空间创建完毕
③ .使用 Cloud Studio 快速配置并启动项目
Fork 完成后,选择 .env.template 文件
修改配置信息如下:
修改文件 后缀名 为 .env
新建 终端命令
输入命令:
npm install
依赖安装完成后,输入命令开启服务
yarn dev
点击 端口 ,可使用 浏览器或标签页 两种方式运行项目
如遇到这个报错提醒,可点击关闭,不影响体验
web浏览器测试:
Cloud Studio 标签页查看:
服务端可查看相关的请求记录:
停止 Cloud Studio 工作空间服务:
服务端停止服务:
① .使用 JupyterLab 快速部署 ChatGLM2-6B-int4 本地模型
输入命令下载 ChatGLM2-6B-int4 相关源码:
cd ./ChatGLM2-6B
git clone https://gitee.com/dadac/chatglm2-6b-int4.git
# 输入你的gitee账号密码
cd chatglm2-6b-int4
在服务器上生成ssh密钥,在Jupyter终端中依次执行以下命令
ssh-keygen -t ed25519 -C "" #双引号里面填ssh key,一般填自己邮箱
# 回车一直默认即可,会在家目录生成 ~/.ssh 文件夹,存放密钥信息
cat ~/.ssh/id_ed25519.pub # 查看生成的公钥
在Jupyter终端中依次执行以下命令
git clone git@gitee.com:dadac/chatglm2-6b-int4.git
# 输入yes 回车确认
代码下载完成:
由于访问外网下载速度很慢,这里我们使用清华大学云盘下载 chatglm2-6b-int4 的相关模型文件
注意:下载链接 存在时效问题,需要手动找一下文件真实地址,方式如下:
打开浏览器控制台(window使用 F12
,macOs使用command
+option
+i
, 或者右键点击选择检查)
在控制台中选择网络选项卡(NetWork),筛选类型选择All,并清空当前网络请求记录
点击下载,在网络请求记录中找到文件下载链接并复制(防止给您的电脑产生垃圾文件,记得取消本地下载或删掉在您电脑上已下载的文件)
同样的方式找到 pytorch_model.bin
和 tokenizer.model
文件链接
找到链接地址后在 JupyterLab 中输入命令:
rm pytorch_model.bin #删除旧文件
wget http://xxxxxx # 复制的pytorch_model.bin 文件链接
rm tokenizer.model #删除旧文件
wget http://xxxxxx # 复制的tokenizer.model 文件链接
由于 pytorch_model.bin 模型文件较大下载大约需要13分钟左右,请您耐心等待。
完成下载后,修改代码来加载本地模型
返回到 ChatGLM2-6B 文件夹,找到 web_demo.py 文件,修改代码文件中第6、7行
tokenizer = AutoTokenizer.from_pretrained("./chatglm2-6b-int4", revision="v1.0", trust_remote_code=True)
model = AutoModel.from_pretrained("./chatglm2-6b-int4", revision="v1.0", trust_remote_code=True).half().cuda()
在web服务开启之前,为了优化服务器的性能,关闭 HAI 提供的 chatglm2_gradio webui,命令如下:
apt-get update && apt-get install sudo
sudo apt-get update
sudo apt-get install psmisc
sudo fuser -k 6889/tcp #执行这条命令将关闭 HAI提供的 chatglm2_gradio webui功能
关闭后输入命令可以启动web服务测试:
cd /root/ChatGLM2-6B
python web_demo.py --listen --port 8000
注意:为避免重复的配置,这里我们将端口配置为我们已经开启的 8000 端口
体验使用本地模型对话:
② .使用 JupyterLab 微调 ChatGLM2-6B 模型(基于 P-Tuning v2 ),创建个人的专属知识库
打开 JupyterLab 选择 ChatGLM2-6B 文件夹下的 ptuning 文件夹
添加训练集、验证集文件(您也可配置自己的训练集,添加的内容越多训练时间越长)
本地创建 train.json 文件
[
{
"content": "你好,你是谁",
"summary": "你好,我是腾讯云高性能应用HAI的助手小hai。"
},
{
"content": "你是谁",
"summary": "你好,我是HAI的助手小hai。"
},
{
"content": "HAI是谁",
"summary": "HAI是为开发者量身打造的澎湃算力平台。无需复杂配置,便可享受即开即用的GPU云服务体验。在HAI中,根据应用智能匹配并推选出最适合的GPU算力资源,以确保您在数据科学、LLM、AI作画等高性能应用中获得最佳性价比。"
}
]
在目录 /ChatGLM2-6B/ptuning/ 下点击上传按钮将本地已保存的 train.json 文件上传至 ptuning 目录
同样用相同的方法 本地创建 verify.json 文件,并上传至 ptuning 目录
[
{
"content": "你好,你是谁",
"summary": "你好,我是腾讯云高性能应用HAI的助手小hai。"
},
{
"content": "你是谁",
"summary": "你好,我是HAI的助手小hai。"
},
{
"content": "HAI是谁",
"summary": "HAI是为开发者量身打造的澎湃算力平台。无需复杂配置,便可享受即开即用的GPU云服务体验。在HAI中,根据应用智能匹配并推选出最适合的GPU算力资源,以确保您在数据科学、LLM、AI作画等高性能应用中获得最佳性价比。"
}
]
train.json 和 verify.json 上传成功
选择 train_chat.sh 文件复制以下配置信息替换并保存文件
PRE_SEQ_LEN=128
LR=1e-2
NUM_GPUS=1
torchrun --standalone --nnodes=1 --nproc-per-node=$NUM_GPUS main.py \
--do_train \
--train_file train.json \
--validation_file verify.json \
--preprocessing_num_workers 10 \
--prompt_column content \
--response_column summary \
--overwrite_cache \
--model_name_or_path /root/ChatGLM2-6B/chatglm2-6b-int4 \
--output_dir /root/ChatGLM2-6B/output/chatglm2-6b-int4−$LR \
--overwrite_output_dir \
--max_source_length 512 \
--max_target_length 512 \
--per_device_train_batch_size 1 \
--per_device_eval_batch_size 1 \
--gradient_accumulation_steps 16 \
--predict_with_generate \
--max_steps 3000 \
--logging_steps 10 \
--save_steps 1000 \
--learning_rate $LR \
--pre_seq_len $PRE_SEQ_LEN \
--quantization_bit 4
参数 | 描述 |
---|---|
PRE_SEQ_LEN=128 | 定义了一个名为PRE_SEQ_LEN的变量,并将其设置为128。这个变量的作用在后续的代码中会用到 |
LR=2e-2 | 定义了一个名为LR的变量,并将其设置为2e-2,即0.02。这个变量表示学习率。 |
train_file | 指定训练数据文件的路径和文件名为"train.json"。 |
validation_file | 指定验证数据文件的路径和文件名为"verify.json" |
prompt_column | 指定输入数据中作为提示的列名为"content" |
response_column | 指定输入数据中作为响应的列名为"summary" |
overwrite_cache | 一个命令行参数,指示在缓存存在的情况下覆盖缓存 |
model_name_or_path | 指定使用的模型的名称或路径为"/root/ChatGLM2-6B/chatglm2-6b-int4" |
output_dir | : 指定输出目录的路径和名称为"/root/ChatGLM2-6B/output/chatglm2-6b-int4−$LR "。这是训练结果和日志的保存位置。 |
overwrite_output_dir | 一个命令行参数,指示在输出目录存在的情况下覆盖输出目录。 |
max_source_length | 指定输入序列的最大长度为512 |
max_target_length | 指定输出序列的最大长度为512 |
per_device_train_batch_size | 指定每个训练设备的训练批次大小为1 |
per_device_eval_batch_size | 指定每个评估设备的评估批次大小为1 |
gradient_accumulation_steps | 指定梯度累积的步数为16。在每个更新步骤之前,将计算并累积一定数量的梯度。 |
predict_with_generate | 一个命令行参数,指示在生成模型的预测时使用生成模式 |
max_steps | 指定训练的最大步数为3000 |
logging_steps | 指定每隔10个步骤记录一次日志 |
save_steps | 指定每隔1000个步骤保存一次模型 |
learning_rate | 指定学习率为之前定义的LR变量的值 |
pre_seq_len | 指定预设序列长度为之前定义的PRE_SEQ_LEN变量的值 |
quantization_bit | 指定量化位数为4。这个参数可能是与模型相关的特定设置。 |
保存相关后截图:
在正式微调之前 我们还需要安装以下依赖, 新建 终端命令窗口
输入命令安装依赖,这里我们使用 腾讯云 提供的镜像:
pip install -i https://mirrors.cloud.tencent.com/pypi/simple rouge_chinese nltk jieba datasets
安装完成之后 执行下面的命令进行训练:
cd ChatGLM2-6B/ptuning
sh train_chat.sh
模型开始训练,数据集越多耗时越长,目前测试的三条训练集、验证集大约需要1个小时左右:
训练完成:
③ .使用 JupyterLab 测试微调后的模型
完成训练后 修改 ChatGLM2-6B 文件下的 web_demo.py 文件用来测试新训练的模型文件
修改 web_demo.py 文件
from transformers import AutoModel, AutoTokenizer,AutoConfig
import gradio as gr
import mdtex2html
import torch
import os
from utils import load_model_on_gpus
MODEL_PATH = "./chatglm2-6b-int4"
CHECKPOINT_PATH = "./output/chatglm2-6b-int4−1e-2/checkpoint-3000"
# 载入Tokenizer
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
config = AutoConfig.from_pretrained(MODEL_PATH, trust_remote_code=True, pre_seq_len=128)
model = AutoModel.from_pretrained(MODEL_PATH, config=config, trust_remote_code=True).cuda()
prefix_state_dict = torch.load(os.path.join(CHECKPOINT_PATH, "pytorch_model.bin"))
new_prefix_state_dict = {}
for k, v in prefix_state_dict.items():
if k.startswith("transformer.prefix_encoder."):
new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = v
model.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict)
print(f"Quantized to 4 bit")
model = model.quantize(4)
model = model.half().cuda()
model.transformer.prefix_encoder.float()
model = model.eval()
#tokenizer = AutoTokenizer.from_pretrained("./chatglm2-6b-int4", revision="v1.0", trust_remote_code=True)
#model = AutoModel.from_pretrained("./chatglm2-6b-int4", revision="v1.0", trust_remote_code=True).half().cuda()
# 多显卡支持,使用下面两行代替上面一行,将num_gpus改为你实际的显卡数量
# from utils import load_model_on_gpus
# model = load_model_on_gpus("THUDM/chatglm2-6B", num_gpus=2)
#model = model.eval()
"""Override Chatbot.postprocess"""
def postprocess(self, y):
if y is None:
return []
for i, (message, response) in enumerate(y):
y[i] = (
None if message is None else mdtex2html.convert((message)),
None if response is None else mdtex2html.convert(response),
)
return y
gr.Chatbot.postprocess = postprocess
def parse_text(text):
"""copy from https://github.com/GaiZhenbiao/ChuanhuChatGPT/"""
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("<", "<")
line = line.replace(">", ">")
line = line.replace(" ", " ")
line = line.replace("*", "*")
line = line.replace("_", "_")
line = line.replace("-", "-")
line = line.replace(".", ".")
line = line.replace("!", "!")
line = line.replace("(", "(")
line = line.replace(")", ")")
line = line.replace("$", "$")
lines[i] = "<br>"+line
text = "".join(lines)
return text
def predict(input, chatbot, max_length, top_p, temperature, history, past_key_values):
chatbot.append((parse_text(input), ""))
for response, history, past_key_values in model.stream_chat(tokenizer, input, history, past_key_values=past_key_values,
return_past_key_values=True,
max_length=max_length, top_p=top_p,
temperature=temperature):
chatbot[-1] = (parse_text(input), parse_text(response))
yield chatbot, history, past_key_values
def reset_user_input():
return gr.update(value='')
def reset_state():
return [], [], None
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--listen", action='store_true',
help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests")
parser.add_argument("--port", type=int,
help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available",
default=None)
args = parser.parse_args()
server_name = "0.0.0.0" if args.listen else None
server_port = args.port
with gr.Blocks() as demo:
gr.HTML("""<h1 align="center">ChatGLM2-6B</h1>""")
chatbot = gr.Chatbot()
with gr.Row():
with gr.Column(scale=4):
with gr.Column(scale=12):
user_input = gr.Textbox(show_label=False, placeholder="Input...", lines=10).style(
container=False)
with gr.Column(min_width=32, scale=1):
submitBtn = gr.Button("Submit", variant="primary")
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, 1, value=0.95, step=0.01, label="Temperature", interactive=True)
history = gr.State([])
past_key_values = gr.State(None)
submitBtn.click(predict, [user_input, chatbot, max_length, top_p, temperature, history, past_key_values],
[chatbot, history, past_key_values], show_progress=True)
submitBtn.click(reset_user_input, [], [user_input])
emptyBtn.click(reset_state, outputs=[chatbot, history, past_key_values], show_progress=True)
demo.queue().launch(share=False, inbrowser=True, server_name=server_name, server_port=server_port)
重新启动服务,命令:
python web_demo.py --listen --port 8000
训练前的:
训练后的:
1、清理 Cloud Studio 中创建的工作空间
2、销毁 高性能应用服务HAI 创建的 ChatGLM2 6B 服务
本次实验主要是引导大家如何使用 高性能应用服务 HAI 部署 ChatGLM2-6B 运行环境进行AI对话并创作个人专属的知识宇宙,开箱即用,可以快速上手;同时,也使用了 Cloud Studio 快速开发部署简单的应用程序。最后也欢迎大家一起探索 高性能应用服务 HAI 更多的功能,为工作中赋能增效降本!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。