最近在自己电脑上尝试着部署了下大模型,仅用此篇流水账记录一下。
环境准备
电脑 是 16寸 Mac M2 Pro,运行时内存是 16 GB。Mac 并没有独立显存,GPU 显存是和系统内存共享。
模型 选择的是 ChatGLM-6B ,它基本可以说是 10B 以下级别模型中性能最强之一。并且 ChatGLM-6B 有一个强点,就是在中英文切换对话方面表现突出。
语言 选择 Python,使用的是 3.12.2 版本,目前大多数大模型的推理过程都是用 Python 语言实现。conda 版本是 24.4.0,主要用来创建虚拟环境。下载 模型主体使用的是 modelscope,它比使用 git clone 下载模型快很多。
大模型资源准备
conda 安装
在 Terminal 中通过如下命令下载并安装 conda
go
curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh
sh Miniconda3-latest-MacOSX-arm64.sh
安装好 conda 之后,就可以在 Terminal 里创建一个虚拟环境了。
go
conda create -n chatglm3 python=3.12.2
创建好虚拟环境之后,通过如下命令激活创建的环境
go
conda activate chatglm3
你会在 Terminal 中看到环境由 base 转换为 chatglm3,如下:
最后通过 conda 安装开发需要的软件,命令如下
go
conda install pytorch torchvision torchaudio -c pytorch-nightly
这样基本的开发环境就算是配好了。顺便说下使用 conda 创建虚拟环境的最大好处就是 环境隔离。虚拟环境可以将项目的依赖隔离开来,避免与电脑系统的全局Python环境产生冲突。
下载模型 ChatGLM-6B
通常情况下是可以通过 git 命令来下载模型主体文件的
go
git clone https://huggingface.co/THUDM/chatglm3-6b
但是上述命令在国内很有可能下载不成功,或者下载很慢。我个人建议使用 ModelScope 下载的。
使用如下命令安装 ModelScope
go
pip install modelscope -U
然后创建一个 下载模型的 python 文件 model_download.py, 拷贝如下代码
go
from modelscope import snapshot_download
model_dir = snapshot_download("ZhipuAI/chatglm3-6b", revision = "v1.0.0")
模型默认保存在如下路径:
go
~/.cache/modelscope/hub/ZhipuAI/ChatGLM3-6B/
把玩大模型
环境配置好,模型也下载好。接下来就可以看下大模型能带来哪些体验了。
大模型聊天
大模型最常用也最简单的使用场景就是搭建一个chatbot。实现很简单,创建 glm_test.py 文件,代码如下:
go
import os
import platform
from transformers import AutoTokenizer, AutoModel
MODEL_PATH = os.environ.get('MODEL_PATH', '大模型下载绝对路径')
TOKENIZER_PATH = os.environ.get("TOKENIZER_PATH", MODEL_PATH)
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
# 创建 model 实例
model = AutoModel.from_pretrained(MODEL_PATH, trust_remote_code=True, device_map="auto", offload_folder="offload").eval()
# 调用 model.chat 方法获取大模型返回的结果
response, history = model.chat(tokenizer, "你好", history=[])
print(response)
执行上述代码,结果如下
可以看到,通过 Transformer 库直接调用 model.chat 方法就能获取大模型的返回结果。
另外,还可以将上下文保存在 history 中,再重新传给大模型。这样大模型就自带记忆功能了。 如下代码:
go
import os
import platform
from transformers import AutoTokenizer, AutoModel
MODEL_PATH = os.environ.get('MODEL_PATH', '大模型的绝对路径')
TOKENIZER_PATH = os.environ.get("TOKENIZER_PATH", MODEL_PATH)
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
model = AutoModel.from_pretrained(MODEL_PATH, trust_remote_code=True).to('mps')
response, history = model.chat(tokenizer, "你好", history=[])
print(response)
response, history = model.chat(tokenizer, "我的名字叫Jiang", history=history)
response, history = model.chat(tokenizer, "我是谁 ?", history=history)
print(response)
最终执行结果如下:
简单 Prompt
除了简单的聊天功能之外,基于简单的 Prompt Engineering 可以让大模型提供更高阶点的功能。
实现信息提取
通过 Prompt,大模型可以对一定的信息进行提取,并按照要求返回特定格式。添加如下 Prompt:
go
import os
import platform
from transformers import AutoTokenizer, AutoModel
MODEL_PATH = os.environ.get('MODEL_PATH', '大模型绝对路径')
TOKENIZER_PATH = os.environ.get("TOKENIZER_PATH", MODEL_PATH)
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
model = AutoModel.from_pretrained(MODEL_PATH, trust_remote_code=True).to('mps')
content="""ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型,
基于 General Language Model (GLM) 架构,具有 62 亿参数。
手机号 18888888888
结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存)。
ChatGLM-6B 使用了较 ChatGPT 更为高级的技术,针对中文问答和对话进行了优化。
邮箱 123456789@qq.com
经过约 1T 标识符的中英双语训练,辅以监督微调、反馈自助、人类反馈强化学习等技术的加持,
账号:root 密码:123456
62 亿参数的 ChatGLM-6B 已经能生成相当符合人类偏好的回答,更多信息请参考我们的博客。
"""
prompt='从上文中,提取"信息"(keyword,content),包括:"手机号"、"邮箱"、"账号"、"密码"等类型的实体,输出json格式内容'
input ='{}\n\n{}'.format(content,prompt)
print(input)
response, history = model.chat(tokenizer, input, history=[])
print(response)
最终执行结果如下:
实现 domain 理解
大模型既能做到信息提取,也能够对内容进行一定程度的理解与Mapping。就如同传统 NLU 返回的 Semantic 格式一样,基于大模型也能返回响应的格式,并且大模型的理解能力在传统 NLU 之上。添加如下 Prompt:
go
import os
import platform
from transformers import AutoTokenizer, AutoModel
MODEL_PATH = os.environ.get('MODEL_PATH', '大模型绝对路径')
TOKENIZER_PATH = os.environ.get("TOKENIZER_PATH", MODEL_PATH)
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
model = AutoModel.from_pretrained(MODEL_PATH, trust_remote_code=True).to('mps')
content="打开空调"
prompt="""
从上文中判断其所属的领域,并返回相应的domain。
所有跟空调相关的都返回domain=AC。比如我说'打开空调', 你就返回domain=AC。所有和车控操作相关的都返回domain=car_control。
比如我说打开车窗,你就返回domain=car_control。
目前你只能返回AC和car_control这2个domain,不要返回其它的domain匹配结果。
示例输入:
打开空调。
温度设置为22度。
将座椅加热调到最高。
关闭车窗。
空调风速调至最大。
示例输出:
domain=AC
domain=AC
domain=car_control
domain=car_control
domain=AC
"""
print(prompt)
input ='{}\n\n{}'.format(content,prompt)
response, history = model.chat(tokenizer, input, history=[])
print("用户输入:" + content)
print("response: ", response)
content="空调风速调高"
response, history = model.chat(tokenizer, input, history=[])
print("用户输入:" + content)
print("response: ", response)
content="打开天窗"
response, history = model.chat(tokenizer, input, history=[])
print("用户输入:" + content)
print("response: ", response)
最终执行结果如下:
可以看出,"打开空调"和"空调风速调高"这两句输入,大模型都返回了相应的 domain 。
注意:针对 "打开天窗" 大模型返回的也是 AC。很明显这是错误的,正确结果应该是 car_control。这就说明,虽然大模型理解力很强,但是还需要配合更加完善的 Prompt Engineering,甚至是 Fine Tuning。才能将大模型的潜力充分发挥。
go
如果你喜欢本文
长按二维码关注