从加载到对话:使用 Transformers 本地运行量化 LLM 大模型(GPTQ AWQ)

(无需显卡)使用 Transformers 在本地加载具有 70 亿参数的 LLM 大语言模型,通过这篇文章你将学会用代码创建属于自己的 GPT。

LLM 的加载、微调和应用涉及多个方面,今天我们先聚焦于加载,本文的难点仅在于正确安装和知晓模型量化的概念 : ),所以不用担心,这是一篇轻松的文章。

你可能已经听说过一些工具,比如 Ollama 和 GPT4ALL,这些都是即开即用的优秀开源项目。然而,仅仅使用这些工具并不能真正理解它们是怎么做的。因此,让我们更加深入一点,亲自通过代码来完成 LLM 部署和简单的对话交互。

在之前的文章《06. 开始实践:部署你的第一个LLM大语言模型》中,我们展示了如何使用一个较小的预训练模型来部署对话应用,旨在为初学者提供一个简单的入门教程。但如果你想基于那篇文章,真正部署更流行的大模型,可能会遇到:

  • 直接使用大模型:Out of Memory。
  • 大模型 4-bit 量化导入:确实可以,但下载一个 7B 的大模型再转 4-bit,需要先吃 30GB 的磁盘空间,不太适合部署去“玩”。
  • 想使用 GGUF 文件:查阅文档和攻略后,尝试用 Transformers 部署,但发现推理速度极慢(转换成了 FP32 并且运行在 CPU 上)。

这篇文章会解决这些问题,并通过使用 Transformers 和 Llama-cpp-python 分别进行演示,帮助你更好地理解和掌握,本文对应于 Transformers,19b 对应于 Llama-cpp-python。

注意:当前文章对显卡没有强制要求,无显卡一样可以实现(推理使用 CPU )。

与之前的文章不同是,为了直观感受,本文没有对代码进行函数封装,而是在需要时直接复用。

文中跳转的文章序号对应于这篇入门指南中的内容。

代码文件下载:Transformers | 🎡 AI Chat 脚本

文章目录

  • 前言
  • 手动下载模型(推荐)
    • GPTQ
    • AWQ
    • GGUF
    • 模型所在地
  • 使用 Transformers 开始加载
    • 环境配置
    • GPTQ
      • 安装
      • 导入库
      • 设置模型路径
      • 加载模型
      • 推理测试
    • AWQ
      • 安装
      • 导入库
      • 设置模型路径
      • 加载模型
      • 推理测试
    • 统一方式加载
    • 了解提示词模版(Prompt Template)
    • 流式输出
      • 单轮对话
      • 多轮对话
    • 用 🎡 脚本感受 AI 对话(可选)
      • 克隆仓库
      • 执行脚本
      • 加载和保存历史对话

前言

访问 Hugging Face,让我们先选择一个7B左右的语言模型:

  1. mistralai/Mistral-7B-Instruct-v0.3
  2. Qwen/Qwen2.5-7B-Instruct
  3. meta-llama/Llama-3.1-8B-Instruct

[!NOTE]

你可以随意更换你喜欢的模型,上面只是简单列举。

停一下,还记得 FP32 下 7B 模型的参数有多大吗?

“不严谨的说,好像是 28 GB,所以我们要用模型量化来导入模型,就是太大了,可能要下载比较久的时间:(”

是的,这个说法没有问题,不过上面列出的模型采用的是 BF16,所以还会更小点。

“那大概 14 GB,我晚点再开始正式学习,还是要下载很久”

诶,那你有没有想过,既然这些模型下载下来需要量化,为什么不直接去下一个量化版的模型?

是的,以上所列的三个模型,在 Hugging Face 中都有着量化版本:

GPTQAWQGGUF
neuralmagic/Mistral-7B-Instruct-v0.3-GPTQ-4bitsolidrust/Mistral-7B-Instruct-v0.3-AWQbartowski/Mistral-7B-Instruct-v0.3-GGUF
Qwen/Qwen2.5-7B-Instruct-GPTQ-Int4Qwen/Qwen2.5-7B-Instruct-AWQQwen/Qwen2.5-7B-Instruct-GGUF
hugging-quants/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4bartowski/Meta-Llama-3.1-8B-Instruct-GGUF

[!note]

注意,表格中 GPTQ 和 AWQ 的跳转链接均为 4-bit 量化。

Q:为什么 AWQ 不标注量化类型?

A:因为 3-bit 没什么需求,更高的 bit 官方现在还不支持(见 Issue #172),所以分享的 AWQ 文件基本默认是 4-bit。

Q:GPTQ,AWQ,GGUF 是什么?

A:简单了解见 18. 模型量化技术概述及 GGUF:GGML 文件格式解析。

Q:怎么去找其他模型对应的量化版本?

A:假设你要找的是 4 bit 量化,搜索 [模型名称]-[GPTQ]/[AWQ]/[GGUF][模型名称]-[4bit/INT4]

三种量化模型,该选哪个进行演示呢?选择困难症犯了 : )

索性不选了,接下来将逐一介绍 GPTQ,AWQ 以及 GGUF 的加载方式,读者选择一种进行即可。

[!important]

文章演示的模型为 Mistral-7B-Instruct-v0.3,对应的加载方法:

a. Transformers:GPTQ,AWQ

b. LLama-cpp-python:GGUF

Llama-cpp-python 的使用将位于文章 19b,建议在阅读完模型下载后再进行跳转。

默认读者只选取一种方式进行阅读,所以为了防止缺漏,每个类型会重复模型下载的指引,当然,你完全可以选择全看。

手动下载模型(推荐)

来试试多线程指定文件下载,对于 Linux,这里给出配置命令,其余系统可以参照《a. 使用 HFD 加快 Hugging Face 模型和数据集的下载》先进行环境配置。你也可以跳过这部分,后面会介绍自动下载。

sudo apt-get update
sudo apt-get install git git-lfs wget aria2
git lfs install

下载并配置 HFD 脚本:

wget https://huggingface.co/hfd/hfd.sh
chmod a+x hfd.sh
export HF_ENDPOINT=https://hf-mirror.com

使用多线程下载指定模型。

GPTQ

命令遵循 ./hfd.sh <model_path> --tool aria2c -x <线程数>的格式:

./hfd.sh neuralmagic/Mistral-7B-Instruct-v0.3-GPTQ-4bit --tool aria2c -x 16

AWQ

命令遵循 ./hfd.sh <model_path> --tool aria2c -x <线程数>的格式:

./hfd.sh solidrust/Mistral-7B-Instruct-v0.3-AWQ --tool aria2c -x 16

GGUF

使用多线程下载指定模型,命令遵循 ./hfd.sh <model_path> --include <file_name> --tool aria2c -x <线程数>的格式:

./hfd.sh bartowski/Mistral-7B-Instruct-v0.3-GGUF --include Mistral-7B-Instruct-v0.3-Q4_K_M.gguf --tool aria2c -x 16

下载完成你应该可以看到类似的输出:

Download Results:
gid   |stat|avg speed  |path/URI
======+====+===========+=======================================================
145eba|OK  |   6.8MiB/s|./Mistral-7B-Instruct-v0.3-Q4_K_M.ggufStatus Legend:
(OK):download completed.
Downloaded https://huggingface.co/bartowski/Mistral-7B-Instruct-v0.3-GGUF/resolve/main/Mistral-7B-Instruct-v0.3-Q4_K_M.gguf successfully.
Download completed successfully.

模型所在地

默认在当前目录下的 <model_name> 文件夹中(<model_path>id + / + model_name 组成)

3.9G    ./Mistral-7B-Instruct-v0.3-AWQ
3.9G    ./Mistral-7B-Instruct-v0.3-GPTQ-4bit
4.1G    ./Mistral-7B-Instruct-v0.3-GGUF

使用 Transformers 开始加载

环境配置

在开始之前,请确保环境已正确配置。运行以下命令安装所需的库:

pip install numpy==1.24.4
pip install --upgrade transformers

GPTQ

安装

你需要注意的是,如果安装不正确,GPTQ 将无法正确使用 GPU 进行推理,也就是说无法进行加速,即便 print(model.device) 显示为 “cuda”。类似的问题见 Is This Inference Speed Slow? #130 和 CUDA extension not installed #694。

这个问题是普遍存在的,当你直接使用 pip install auto-gptq 进行安装时,可能就会出现。

你可以通过以下命令检查已安装的版本:

pip list | grep auto-gptq

如果发现之前安装的版本不带 cuda 标识,卸载它,从源码重新进行安装(推理速度将提升为原来的 15 倍以上)。

pip uninstall auto-gptq
git clone https://github.com/PanQiWei/AutoGPTQ.git && cd AutoGPTQ
# 以下两种方式任选一种进行安装即可,经测试均有效
pip install -vvv --no-build-isolation -e .
# >> Successfully installed auto-gptq-0.8.0.dev0+cu121python setup.py install
# >> Finished processing dependencies for auto-gptq==0.8.0.dev0+cu121

[!Note]

如果仅在 CPU 上运行,可以直接使用 pip install auto-gptq 进行安装。

否则,请确保系统已安装 CUDA,可以通过 nvcc --version 检查。

导入库

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

接下来介绍两种导入模型的方法,根据需要选择本地导入或自动下载导入。

设置模型路径

如果已经在本地下载了模型,可以通过指定模型路径来加载模型。以下示例假设模型位于当前目录的 Mistral-7B-Instruct-v0.3-GPTQ-4bit 文件夹下:

# 指定本地模型的路径
model_path = "./Mistral-7B-Instruct-v0.3-GPTQ-4bit"

如果没有本地模型,设置远程路径(id + / + model_name),导入的时候会自动从 Hugging Face 下载模型:

# 指定远程模型的路径
model_path = "neuralmagic/Mistral-7B-Instruct-v0.3-GPTQ-4bit"

加载模型

# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(model_path)# 下载并加载模型
model = AutoModelForCausalLM.from_pretrained(model_path,torch_dtype="auto",  # 自动选择模型的权重数据类型device_map="auto"    # 自动选择可用的设备(CPU/GPU)
)

推理测试

# 输入文本
input_text = "Hello, World!"# 将输入文本编码为模型可接受的格式
input_ids = tokenizer.encode(input_text, return_tensors="pt").to(model.device)# 生成输出
with torch.no_grad():output_ids = model.generate(input_ids=input_ids,max_length=50,)# 解码生成的输出
output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True)# 打印生成的文本
print(output_text)

输出

Hello, World!I’m a software engineer, currently working at Google. I’ve been working in the tech industry for about 10 years now, and I’ve been fortunate enough to work on a variety of interesting

AWQ

安装

pip install autoawq autoawq-kernels

导入库

import torch
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

同样地,下面介绍两种导入 AWQ 模型的方法,根据需要选择本地导入或自动下载导入。

设置模型路径

如果已经在本地下载了模型,可以通过指定模型路径来加载模型。以下示例假设模型位于当前目录的 Mistral-7B-Instruct-v0.3-AWQ 文件夹下:

# 指定本地模型的路径
model_path = "./Mistral-7B-Instruct-v0.3-AWQ"

如果没有本地模型,设置远程路径(id + / + model_name),导入的时候会自动从 Hugging Face 下载模型:

# 指定远程模型的路径
model_path = "solidrust/Mistral-7B-Instruct-v0.3-AWQ"

加载模型

# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(model_path,trust_remote_code=True
)# 下载并加载模型
model = AutoAWQForCausalLM.from_quantized(model_path,fuse_layers=True  # 融合部分模型层以提高推理速度
)

推理测试

# 设置设备
device = 'cuda' if torch.cuda.is_available() else 'cpu'# 输入文本
input_text = "Hello, World!"# 将输入文本编码为模型可接受的格式
input_ids = tokenizer.encode(input_text, return_tensors="pt").to(device)# 生成输出
with torch.no_grad():output_ids = model.generate(input_ids=input_ids,max_length=50,pad_token_id=tokenizer.eos_token_id)# 解码生成的输出
output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True)# 打印生成的文本
print(output_text)

输出

Hello, World!I’m so excited to finally be able to share my passion for all things beauty with you!I’ve been a beauty enthusiast for as long as I can remember. I’ve always been

统一方式加载

值得一提的是,你可能已经注意到了 GPTQ 并不是使用 Auto-GPTQ 库,而是直接使用 Transformers(虽然背后仍然依赖于 Auto-GPTQ)。

“要是所有的模型都能统一就好了,这样就不用查阅其他库的文档了。”

事实上,AWQ 也可以通过 Transformers 来加载(如果你对参数设置没有更细致的要求):

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer# 指定模型,切换为对应的 GPTQ 或 AWQ 模型路径,可以是远程路径,会自动下载
model_path = "./Mistral-7B-Instruct-v0.3-AWQ"# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(model_path)# 加载模型
model = AutoModelForCausalLM.from_pretrained(model_path,torch_dtype="auto",  # 自动选择模型的权重数据类型device_map="auto"    # 自动选择可用的设备(CPU/GPU)
)# 设置设备
device = 'cuda' if torch.cuda.is_available() else 'cpu'# 输入文本
input_text = "Hello, World!"# 将输入文本编码为模型可接受的格式
input_ids = tokenizer.encode(input_text, return_tensors="pt").to(device)# 生成输出
with torch.no_grad():output_ids = model.generate(input_ids=input_ids,max_length=50,pad_token_id=tokenizer.eos_token_id)# 解码生成的输出
output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True)# 打印生成的文本
print(output_text)

输出

Hello, World! 🌐Since the age of 19, I have been capturing moments as a photographer. Over the years, I have expanded my passion to videography and film production, working in collaboration with

了解提示词模版(Prompt Template)

其实非常简单,就是曾经提到的占位符(下图对于 {{question}} 的应用)。

占位符

举个直观的例子:

# 定义 Prompt Template
prompt_template = "问:{question}\n答:"# 定义问题
question = "人工智能的未来发展方向是什么?"# 使用 Prompt Template 生成完整的提示
prompt = prompt_template.format(question=question)
print(prompt)

输出

问:人工智能的未来发展方向是什么?
答:

[!tip]

如果你对 "问:{question}\n答:".format() 的形式不太理解,可以将其理解为 f"问:{question}\n答:"

print(f"问:{question}\n答:")

输出

问:人工智能的未来发展方向是什么?
答:

在《02. 简单入门:通过API与Gradio构建AI应用》的第一部分,你应该见过它的使用。

Q: 应该选择哪种形式的 Prompt Template 呢?

A: 按照自己的喜好进行使用,但需要注意的是 f-string 在 Python 3.6 版本才引入。

Q: 提示词模版的应用在哪里,为什么能得到发展?

A:偷懒。

讲个小故事。假设团队正在进行大量的文献翻译任务。早在 GPT-3.5 刚发布时,我们就开始使用 ChatGPT 来帮忙「翻译」文章,为自己的摸鱼大业添砖加瓦。虽然每次都需要输入大量的文本才能让它进行地道的翻译,但这总比自己逐句翻译省力得多。「工资不变,吞吐量增加,加量不加价,直呼好员工」

经过一段时间,我们总结出了一套「模版」,每次只需要复制粘贴:将「模版」+「文本」丢给ChatGPT 就能得到结果(或许小组已经有人在偷偷用 API 写提示词模版🤣)。「虽然重复单调无趣,但是轻松还高效」

矜矜业业的当了一年 CV 机器人(Ctrl+C「模版」 V「模版」 + Ctrl+C「文本」 V「文本」 ),OpenAI 发布了 GPTs,这可太好了!我们可以定制 GPT 来做任务,将原来总结出的「模版」直接丢进去就行:一个 GPT 负责「分段」,另一个负责「翻译」,再加一个负责「润色」!「再也不用复制重复的「模版」了」

回归正题,在角色扮演或其他 AI 应用中,使用 Prompt 进行预设是很常见的方法(因为 In-context Learning 是有效的)。而用得多了,自然需要一个合适的名称来指代它,Prompt Template 确实很贴切。

让我们看看模型自身对应的聊天模版。

# 打印 chat_template 信息(如果存在的话)
if hasattr(tokenizer, 'chat_template'):print(tokenizer.chat_template)
else:print("Tokenizer 没有 'chat_template' 属性。")

输出

{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST] ' + message['content'] + ' [/INST]' }}{% elif message['role'] == 'assistant' %}{{ message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}

你应该能发现,这其中有很多非常熟悉的词:messagesroleuserassistant(在最早调用 API 时其实见到过),整理格式进行理解:

{{ bos_token }}
{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST] ' + message['content'] + ' [/INST]' }}{% elif message['role'] == 'assistant' %}{{ message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}
{% endfor %}

解释

  • {{ bos_token }}
    • bos_token 是序列的开始标记 (Beginning of Sequence),用于表示对话的开头。
  • {% for message in messages %}
    • 循环遍历对话中的所有消息。messages 是一个包含每条对话内容和角色的列表,message是其中以字典方式存储的条目。
  • {% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}
    • 该条件确保用户 (user) 和助手 (assistant) 的消息是交替出现的。如果顺序不对,将抛出异常。
    • loop.index0 是当前循环的索引(从 0 开始,当成 for i in len(messages) 中的 i 即可),通过判断 loop.index0 % 2 == 0 确定用户消息是否在正确的位置。
      • raise_exception('Conversation roles must alternate user/assistant/user/assistant/...')
        • 如果消息角色不交替,会调用 raise_exception() 抛出异常,提示消息必须按顺序交替出现,这就是🎡 脚本中 jinja2.exceptions.TemplateError 的来源。
  • {% if message['role'] == 'user' %}
    • 如果消息的角色是用户 (user),则将其内容包裹在 [INST] ... [/INST] 标记中,表示这是用户的输入。
  • {% elif message['role'] == 'assistant' %}
    • 如果消息的角色是助手 (assistant),在末尾添加 eos_token,表示对话结束。
  • {% else %}
    • 如果消息的角色既不是 user 也不是 assistant,将抛出异常,提示只支持这两种角色。

整理后的 chat_template 非常直观,完全可以当作 Python 伪代码进行理解。

上述模板是 Mistral-7B-Instruct-v0.3 模型的对话模板,并不意味着所有模型都通用,但设计起来非常简单,你完全可以进行自定义。

流式输出

在项目初期认识 API 的时候,文章《01. 初识LLM API:环境配置与多轮对话演示》有提到过流式输出,这是我们一直以来见到的大模型输出方式:逐字(token)打印而非等全部生成完再打印。

执行下面的代码试试(无论之前导入的是哪种模型,都可以继续):

from transformers import TextStreamerdevice = 'cuda' if torch.cuda.is_available() else 'cpu'# 创建 TextStreamer 实例
streamer = TextStreamer(tokenizer, skip_prompt=True,         # 在输出时跳过输入的提示部分,仅显示生成的文本skip_special_tokens=True  # 忽略生成过程中的特殊标记(比如 <pad> / <eos> ...)
)# 将提示编码为模型输入
input_ids = tokenizer.encode(prompt, return_tensors="pt").to(device)# 设置生成参数
generation_kwargs = {"input_ids": input_ids,  # 模型的输入 ID,注意,这不是 Embedding"max_length": 200,       # 生成的最大 token 数"streamer": streamer,    # 使用 TextStreamer 实现生成过程中逐步输出文本"pad_token_id": tokenizer.eos_token_id  # 默认行为,消除警告
}# 开始生成文本
with torch.no_grad():model.generate(**generation_kwargs)

** 是 Python 中的解包操作符,它将字典中的键值对解包为函数的关键字参数。在这里,**generation_kwargs 将字典中的参数逐一传递给 model.generate() 方法,等价于直接写出所有参数:

model.generate(input_ids=input_ids, max_length=200, ...
)

你需要注意到,这和之前采用了不同的传参方式,但本质是一样的。为了初见的直观,在后续的教程中,会较少地使用这种方式进行传参。

Q:为什么设置 pad_token_id=tokenizer.eos_token_id

A:如果不进行设置,你将在每次生成时看到这样的一行警告:

Setting `pad_token_id` to `eos_token_id`:{eos_token_id} for open-end generation.

让我们看看源码:

def _get_pad_token_id(self, pad_token_id: int = None, eos_token_id: int = None) -> int:if pad_token_id is None and eos_token_id is not None:logger.warning(f"Setting `pad_token_id` to `eos_token_id`:{eos_token_id} for open-end generation.")pad_token_id = eos_token_idreturn pad_token_id

pad_token_id 为 None 而 eos_token_id 不为 None 时,弹出这个警告,并且设置 pad_token_id = eos_token_id。

这里提前进行设置只是为了抑制这个警告,实际效果和不设置的默认行为一样。

同样的问题见:https://stackoverflow.com/a/71397707/20445396

输出

现在,你可以根据生成文本的质量决定是否终止输出。

另外,当前输出中不包含我们之前提到的 Prompt 模板。如果希望包含它,将 streamer 参数中的 skip_prompt 设置为 False 即可。

[!tip]

最近示出的 GPT-4o canvas 在对原回答进行修改时展示出的按行刷新原文比逐 Token 更赏心悦目,设计的很好(不过一番体验下来,现在还处于好玩有意思,但不够用的阶段)。

image-20241009180422603

单轮对话

让我们直接设计 messages,并应用 chat_template 进行对话:

prompt = "人工智能的未来发展方向是什么?"# 定义消息列表
messages = [{"role": "user", "content": prompt}
]# 使用 tokenizer.apply_chat_template() 生成模型输入
input_ids = tokenizer.apply_chat_template(messages, return_tensors="pt").to(device)# ========== 以下代码与之前一致 ==============
# 创建 TextStreamer 实例
streamer = TextStreamer(tokenizer, skip_prompt=True,         # 在输出时跳过输入的提示部分,仅显示生成的文本skip_special_tokens=True  # 忽略生成过程中的特殊标记(比如 <pad> / <eos> ...)
)# 设置生成参数
generation_kwargs = {"input_ids": input_ids,          # 模型的输入 ID"max_length": 200,               # 生成的最大 token 数"streamer": streamer,            # 使用 TextStreamer 实现生成过程中逐步输出文本"pad_token_id": tokenizer.eos_token_id  # 默认行为,消除警告
}# 开始生成文本
with torch.no_grad():model.generate(**generation_kwargs)

如果想进行单轮对话,那么修改 prompt 即可:

prompt = input("User: ")

多轮对话

接下来,让我们重现曾经见过的多轮对话:

from transformers import TextStreamerdevice = 'cuda' if torch.cuda.is_available() else 'cpu'# 初始化对话历史
messages = []# 开始多轮对话
while True:# 获取输入prompt = input("User: ")# 退出对话条件(当然,你也可以直接终止代码块)if prompt.lower() in ["exit", "quit", "bye"]:print("Goodbye!")break# 将输入添加到对话历史messages.append({"role": "user", "content": prompt})# 使用 tokenizer.apply_chat_template() 生成模型输入input_ids = tokenizer.apply_chat_template(messages, return_tensors="pt").to(device)# 创建 TextStreamer 实例streamer = TextStreamer(tokenizer, skip_prompt=True,         # 在输出时跳过输入的提示部分,仅显示生成的文本skip_special_tokens=True  # 忽略生成过程中的特殊标记(比如 <pad> / <eos> ...))# 设置生成参数generation_kwargs = {"input_ids": input_ids,                  # 模型的输入 ID"max_length": input_ids.shape[1] + 500,  # 生成的最大 token 数,input_ids.shape[1] 即输入对应的 tokens 数量"streamer": streamer,                    # 使用 TextStreamer 实现生成过程中逐步输出文本"pad_token_id": tokenizer.eos_token_id   # 默认行为,消除警告}# 开始生成回复with torch.no_grad():output_ids = model.generate(**generation_kwargs)# 获取生成的回复文本assistant_reply = tokenizer.decode(output_ids[0][input_ids.shape[1]:], skip_special_tokens=True)# 将模型的回复添加到对话历史messages.append({"role": "assistant", "content": assistant_reply})

输出

User:  如果你是大模型面试官,你会怎么出面试题
如果我是大模型面试官,我会出面试题如下:1. 你能解释什么是深度学习?
2. 你能给出一个例子,说明什么是卷积神经网络(CNN)?
3. 你能解释什么是反 Propagation 算法?
4. 你能给出一个例子,说明什么是自编码器(Autoencoder)?
5. 你能解释什么是 Transfer Learning?
6. 你能给出一个例子,说明什么是 Generative Adversarial Networks(GANs)?
7. 你能解释什么是 Reinforcement Learning?
8. 你能给出一个例子,说明什么是 Neural Turing Machines(NTMs)?
9. 你能解释什么是 One-Shot Learning?
10. 你能给出一个例子,说明什么是 Siamese Networks?
User:  对于第十个问题能否给我答案
对于第十个问题:给出一个例子,说明什么是 Siamese Networks?Siamese Networks 是一种双向的神经网络,用于学习两个相似的输入的相似性。例如,在人脸识别中,Siamese Networks 可以用来学习两个人脸的相似性,从而实现人脸识别的目的。

可以看到模型拥有之前的对话“记忆”。

注意,这里有一个小坑,你不能简单使用 output_ids[0] 来保存回复,因为output_ids 中实际上包含了 input_ids,打印它们:

print(tokenizer.decode(input_ids[0], skip_special_tokens=True))
print(tokenizer.decode(output_ids[0], skip_special_tokens=True))

输出:

如果你是大模型面试官,你会怎么出面试题
如果你是大模型面试官,你会怎么出面试题
如果我是大模型面试官,我会出面试题如下:1. 你能解释什么是深度学习?
2. 你能给出一个例子,说明什么是卷积神经网络(CNN)?
...

用户的输入被包含在了输出中,所以在保存时需要额外进行处理,当前简单使用output_ids[0][input_ids.shape[1]:] 或者 output_ids[:, input_ids.shape[1]:][0]

相关问题:No way to get ONLY the generated text, not including the prompt. #17117

可以看到模型拥有之前的对话“记忆”。

如果你对 GGUF 文件的加载或者 Llama-cpp-python 的使用感兴趣,继续阅读 19b。

用 🎡 脚本感受 AI 对话(可选)

这是可选的行为,脚本的代码处理逻辑与文章对应。

克隆仓库

# 如果已经克隆仓库的话跳过这行
git clone https://github.com/Hoper-J/AI-Guide-and-Demos-zh_CN

执行脚本

  1. 切换到 CodePlayground 文件夹:

    cd AI-Guide-and-Demos-zh_CN/CodePlayground
    
  2. 开始对话:

    # 使用方法:python chat.py <model_path> [可选参数],替换为你想用的 <model_path>
    # 本地加载
    python chat.py ../Demos/Mistral-7B-Instruct-v0.3-GPTQ-4bit# 远程加载
    python chat.py neuralmagic/Mistral-7B-Instruct-v0.3-GPTQ-4bit
    

加载和保存历史对话

使用 -i 参数指定文件加载,-o 参数进行保存,或者 -io 参数指明加载和保存的文件路径相同:

python chat.py <model_path> -io history

注意,Ctrl + C 将直接终止对话,只有使用 ‘exit’、‘quit’ 或 ‘bye’ 结束对话,或者使用 Ctrl + D (EOF) 退出时才会保存对话。

[!note]

暂时仅支持与拥有 tokenizer.chat_template 属性的模型对话。

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

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

相关文章

护理陪护系统|护理陪护小程序|护理陪护软件定制

护理陪护系统是针对需要长期照护的患者和老年人开发的一套系统&#xff0c;旨在帮助用户更加方便地获取医疗、护理等服务。用户端功能是系统的重要组成部分&#xff0c;通过用户端功能的设计和开发&#xff0c;可以让用户更加方便快捷地使用系统。首先&#xff0c;用户端功能应…

中兴通讯举办AI“兴”视野沙龙:求真务实 推动AI健康、向善、普惠发展

近日&#xff0c;由中兴通讯主办的“AI‘兴’视野沙龙”在北京举行&#xff0c;中兴通讯首席发展官崔丽与多名业界大咖聚焦人工智能技术发展的前世今生、最新进展、应用趋势、产业融合新路径等热点话题展开深入交流。 数智经济大势所趋 机遇与挑战并存 崔丽谈到&#xff0c;当…

Java利用itextpdf实现pdf文件生成

前言 最近公司让写一个数据页面生成pdf的功能&#xff0c;找了一些市面代码感觉都太麻烦&#xff0c;就自己综合性整合了一个便捷的工具类&#xff0c;开发只需简单组装数据直接调用即可快速生成pdf文件。望大家一起学习&#xff01;&#xff01;&#xff01; 代码获取方式&am…

Graphviz是一个开源的图形可视化软件

官网没有给出代码示例&#xff0c;所以需要自己琢磨&#xff0c; 这里最底下给了一些简单的&#xff0c; 确实可以出很好看的图片 Graphviz介绍 Graphviz是一个开源的图形可视化软件&#xff0c;主要用于绘制各种类型的图表&#xff0c;如流程图、结构图、网络拓扑图等。它通…

cmake模板-支持编译动态/静态文件

代码链接&#xff1a;代码仓库 git clone https://gitee.com/etsuyou/cmake-template.git模板 模板截图 如何使用 在src和inc中写代码 此处用我默认提供的代码 ./go.sh cmake 生成Makefile ./go.sh make 生成bin文件和.a以及.so ./go.sh run app 运行 ./go.sh clean 以…

基于FPGA的ov5640摄像头图像采集(二)

之前讲过ov5640摄像头图像采集&#xff0c;但是只包了的摄像头驱动与数据对齐两部分&#xff0c;但是由于摄像头输入的像素时钟与HDMI输出的驱动时钟并不相同&#xff0c;所有需要利用DDR3来将像素数据进行缓存再将像素数据从DDR3中读出&#xff0c;对DDR3的读写参考米联客的IP…

安装TDengine数据库3.3版本和TDengine数据库可视化管理工具

安装TDengine数据库3.3版本和TDengine数据库可视化管理工具 一、下载安装包二、解压安装包三、部署四、启动服务五、进入数据库六、创建数据库、表和往表中插入数据七、测试 TDengine 性能八、使用数据库九、查询数据十、TDengine数据库可视化界面 一、下载安装包 TDengine-cl…

EXCEL怎么锁定单元格(锁定的单元格不能修改)

选中你的需要保护的单元格&#xff0c;然后点击鼠标右键&#xff0c;在弹出来的下拉菜单里面找到单元格格式 设置单元格格式&#xff0c;弹出来的对话框里找到右侧的保护&#xff0c;勾上锁定 找到审阅按钮&#xff0c;在下面找到更改下面的保护工作表按钮 具体保护的操作…

获取京东商品历史价格接口item_history_price介绍

接口开发背景 京东作为中国知名的电商平台&#xff0c;提供了丰富的商品和服务。为了更好地满足用户和商家的需求&#xff0c;京东开放平台推出了多种API接口&#xff0c;其中“item_history_price”接口用于获取指定商品的历史价格信息。这一接口的开发背景在于帮助用户判断当…

JavaSE——集合5:Set(HashSet的底层原理)(重要!!!)

目录 一、Set接口基本介绍 二、Set接口的常用方法 三、Set接口实现类——HashSet 四、HashSet(HashMap底层原理:重要!!!) (一)第一次添加元素 (二)第二次添加不同的元素 (三)添加重复的元素 1.仍旧走到了putVal(hash(key), key, value, false, true);方法 2.判断计算出…

java-02 数据结构-队列

在Java中&#xff0c;队列是一种常见的数据结构&#xff0c;用于在保持顺序的同时存储和检索数据。Java提供了java.util.Queue接口&#xff0c;它的常见实现包括ArrayDeque、LinkedList和PriorityQueue等。 如果你觉得我分享的内容或者我的努力对你有帮助&#xff0c;或者你只…

PyQt5常用功能四

⽂本涂鸦 写⼀些⽂本上下居中对齐的俄罗斯Cylliric语⾔的⽂字 import sys from PyQt5.QtWidgets import QWidget, QApplication from PyQt5.QtGui import QPainter, QColor, QFont from PyQt5.QtCore import Qtclass Example(QWidget):def __init__(self):super().__init__()…

趋势(一)利用python绘制折线图

趋势&#xff08;一&#xff09;利用python绘制折线图 折线图&#xff08; Line Chart&#xff09;简介 折线图用于在连续间隔或时间跨度上显示定量数值&#xff0c;最常用来显示趋势和关系&#xff08;与其他折线组合起来&#xff09;。折线图既能直观地显示数量随时间的变化…

如何查看GB28181流媒体平台LiveGBS中对GB28181实时视频数据统计的负载信息

目录 1、负载信息2、负载信息说明3、会话列表查看 3.1、会话列表4、停止会话5、搭建GB28181视频直播平台 1、负载信息 实时展示直播、回放、播放、录像、H265、级联等使用数目 2、负载信息说明 直播&#xff1a;当前推流到平台的实时视频数目回放&#xff1a;当前推流到平台的回…

【无标题】基于情境依赖因果影响的多智能体协作强化学习

、文章探讨了大型语言模型&#xff08;LLMs&#xff09;&#xff0c;例如GPT-4&#xff0c;是否以及在何种意义上拥有知识。作者认为&#xff0c;这些模型展现了一种称为“工具性知识”的能力&#xff0c;这种知识允许它们根据输入上下文推断任务结构&#xff0c;并在此基础上进…

废水处理(一)——MDPI特刊推荐

特刊征稿 01 期刊名称&#xff1a; Removing Challenging Pollutants from Wastewater: Effective Approaches 截止时间&#xff1a; 摘要提交截止日期&#xff1a;2024年11月30日 投稿截止日期&#xff1a;2025年5月31日 目标及范围&#xff1a; 该主题是分享去除有毒物…

js操作元素的其他操作(4个案例+效果图+代码)

目录 1. 获取元素的位置和大小 案例:获取元素的位置和大小 1.代码 2.效果 2. 获取元素的可视区域 案例:获取元素的可视区域 1.代码 2.效果 3. 元素的滚动操作 案例:元素的滚动操作 1.代码 2.效果 4. 获取鼠标指针位置 案例:时刻获取鼠标位置 1.代码 2.效果 案例:拖动的小球 1.代…

万物智联创未来,第三届OpenHarmony技术大会在上海成功举办 深圳触觉智能参会

​10月12日&#xff0c;以“技术引领筑生态&#xff0c;万物智联创未来”为主题的第三届OpenHarmony技术大会&#xff08;以下简称“大会”&#xff09;在上海成功举办。本次大会由OpenHarmony项目群技术指导委员会&#xff08;TSC&#xff09;主办&#xff0c;华为、上海交通大…

阿里云物联网自有app创建之初始化SDK

文章目录 一、新建工程&#xff0c;配置gradle,导入.so文件&#xff0c;生成apk二、上传apk&#xff0c;集成安全图片&#xff0c;下载SDK三、SDK的集成四、初始化SDK 最近在研究阿里云自有app,这是自己的心得。 一、新建工程&#xff0c;配置gradle,导入.so文件&#xff0c;生…

Gin框架官方文档详解03:HTML渲染

注&#xff1a;本教程使用工作区方法管理项目&#xff0c;详见第一讲&#xff1a;创建一个简单的Gin应用。 目录 一、简单渲染二、使用不同目录下名称相同的模板三、自定义模板渲染器四、自定义分隔符五、自定义模板函数六、总结 一、简单渲染 首先&#xff0c;以03HTML渲染为…