You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

57 KiB

中文   English   日本語  Français




🤗 Hugging Face   |   🤖 魔搭社区   |    📑 论文      🖥️ Demo
微信      钉钉    |   Discord  



Qwen-Chat Qwen-Chat (Int4) Qwen-Chat (Int8) Qwen
7B 🤖 🤗 🤖 🤗 🤖 🤗 🤖 🤗
14B 🤖 🤗 🤖 🤗 🤖 🤗 🤖 🤗

我们开源了Qwen通义千问系列工作当前开源模型的参数规模为70亿7B和140亿14B。本次开源包括基础模型Qwen,即Qwen-7BQwen-14B,以及对话模型Qwen-Chat,即Qwen-7B-ChatQwen-14B-Chat。模型链接在表格中,请点击了解详情。同时,我们公开了我们的技术报告,请点击上方论文链接查看。

当前基础模型已经稳定训练了大规模高质量且多样化的数据覆盖多语言当前以中文和英文为主总量高达3万亿token。在相关基准评测中Qwen系列模型拿出非常有竞争力的表现显著超出同规模模型并紧追一系列最强的闭源模型。此外我们利用SFT和RLHF技术实现对齐从基座模型训练得到对话模型。Qwen-Chat具备聊天、文字创作、摘要、信息抽取、翻译等能力同时还具备一定的代码生成和简单数学推理的能力。在此基础上我们针对LLM对接外部系统等方面针对性地做了优化当前具备较强的工具调用能力以及最近备受关注的Code Interpreter的能力和扮演Agent的能力。

在这个项目中,你可以了解到以下内容

  • 快速上手Qwen-Chat教程玩转大模型推理
  • 量化模型相关细节包括GPTQ和KV cache量化
  • 推理性能数据,包括推理速度和显存占用
  • 微调的教程帮你实现全参数微调、LoRA以及Q-LoRA
  • 部署教程以vLLM和FastChat为例
  • 搭建Demo的方法包括WebUI和CLI Demo
  • 搭建API的方法我们提供的示例为OpenAI风格的API
  • 更多关于Qwen在工具调用、Code Interpreter、Agent方面的内容
  • 长序列理解能力及评测
  • 使用协议
  • ...

如果遇到问题,请优先考虑查询FAQ。如仍未解决随时提出issue但建议使用英语或提供翻译有助于帮助更多用户。如果想帮助我们提升欢迎提交Pull Requests

想和我们一起讨论和聊天的话赶紧加入我们的微信群和Discord server入口见文档开头部分

新闻

  • 2023年10月17日 我们推出了Int8量化模型Qwen-7B-Chat-Int8Qwen-14B-Chat-Int8
  • 2023年9月25日 🔥 在魔搭社区ModelScope和Hugging Face推出Qwen-14BQwen-14B-Chat模型,并开源 qwen.cppQwen-AgentQwen-7BQwen-7B-Chat的代码和模型也同步得到更新。请使用最新的代码和模型!
    • 相比原版Qwen-7B新版用了更多训练数据从2.2T增加到2.4T tokens序列长度从2048扩展至8192。整体中文能力以及代码能力均有所提升。
  • 2023年9月12日 支持Qwen-7B和Qwen-7B-Chat的微调其中包括全参数微调、LoRA以及Q-LoRA。
  • 2023年8月21日 发布Qwen-7B-Chat的Int4量化模型Qwen-7B-Chat-Int4。该模型显存占用低推理速度相比半精度模型显著提升在基准评测上效果损失较小。
  • 2023年8月3日 在魔搭社区ModelScope和Hugging Face同步推出Qwen-7B和Qwen-7B-Chat模型。同时我们发布了技术备忘录介绍了相关的训练细节和模型表现。

评测表现

Qwen-14B及Qwen-7B (最新版本使用更大量的token进行预训练)相比同规模模型均实现了效果的显著提升。我们评测的数据集包括MMLU、C-Eval、 GSM8K、 MATH、HumanEval、MBPP、BBH等数据集考察的能力包括自然语言理解、知识、数学计算和推理、代码生成、逻辑推理等。当然即便Qwen-14B相比GPT-3.5和GPT-4仍有差距。


Model MMLU C-Eval GSM8K MATH HumanEval MBPP BBH CMMLU
5-shot 5-shot 8-shot 4-shot 0-shot 3-shot 3-shot 5-shot
LLaMA2-7B 46.8 32.5 16.7 3.3 12.8 20.8 38.2 31.8
LLaMA2-13B 55.0 41.4 29.6 5.0 18.9 30.3 45.6 38.4
LLaMA2-34B 62.6 - 42.2 6.2 22.6 33.0 44.1 -
ChatGLM2-6B 47.9 51.7 32.4 6.5 - - 33.7 -
InternLM-7B 51.0 53.4 31.2 6.3 10.4 14.0 37.0 51.8
InternLM-20B 62.1 58.8 52.6 7.9 25.6 35.6 52.5 59.0
Baichuan2-7B 54.7 56.3 24.6 5.6 18.3 24.2 41.6 57.1
Baichuan2-13B 59.5 59.0 52.8 10.1 17.1 30.2 49.0 62.0
Qwen-7B (original) 56.7 59.6 51.6 10.4 24.4 31.2 40.6 58.8
Qwen-7B 58.2 63.5 51.7 11.6 29.9 31.6 45.0 62.2
Qwen-14B 66.3 72.1 61.3 24.8 32.3 40.8 53.4 71.0

对于以上所有对比模型,我们列出了其官方汇报结果与OpenCompass结果之间的最佳分数。

更多的实验结果和细节请查看我们的技术备忘录。点击这里

要求

  • python 3.8及以上版本
  • pytorch 1.12及以上版本推荐2.0及以上版本
  • 建议使用CUDA 11.4及以上GPU用户、flash-attention用户等需考虑此选项

快速使用

我们提供简单的示例来说明如何利用🤖 ModelScope和🤗 Transformers快速使用Qwen-7B和Qwen-7B-Chat。

在开始前,请确保你已经配置好环境并安装好相关的代码包。最重要的是,确保你满足上述要求,然后安装相关的依赖库。

pip install -r requirements.txt

如果你的显卡支持fp16或bf16精度我们还推荐安装flash-attention当前已支持flash attention 2)来提高你的运行效率以及降低显存占用。(flash-attention只是可选项不安装也可正常运行该项目)

git clone https://github.com/Dao-AILab/flash-attention
cd flash-attention && pip install .
# 下方安装可选,安装可能比较缓慢。
# pip install csrc/layer_norm
# pip install csrc/rotary

接下来你可以开始使用Transformers或者ModelScope来使用我们的模型。

🤗 Transformers

如希望使用Qwen-chat进行推理所需要写的只是如下所示的数行代码。请确保你使用的是最新代码,并指定正确的模型名称和路径,如Qwen/Qwen-7B-ChatQwen/Qwen-14B-Chat

from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import GenerationConfig

# 可选的模型包括: "Qwen/Qwen-7B-Chat", "Qwen/Qwen-14B-Chat"
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B-Chat", trust_remote_code=True)

# 打开bf16精度A100、H100、RTX3060、RTX3070等显卡建议启用以节省显存
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B-Chat", device_map="auto", trust_remote_code=True, bf16=True).eval()
# 打开fp16精度V100、P100、T4等显卡建议启用以节省显存
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B-Chat", device_map="auto", trust_remote_code=True, fp16=True).eval()
# 使用CPU进行推理需要约32GB内存
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B-Chat", device_map="cpu", trust_remote_code=True).eval()
# 默认使用自动模式,根据设备自动选择精度
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B-Chat", device_map="auto", trust_remote_code=True).eval()

# 可指定不同的生成长度、top_p等相关超参
model.generation_config = GenerationConfig.from_pretrained("Qwen/Qwen-7B-Chat", trust_remote_code=True)

# 第一轮对话
response, history = model.chat(tokenizer, "你好", history=None)
print(response)
# 你好!很高兴为你提供帮助。

# 第二轮对话
response, history = model.chat(tokenizer, "给我讲一个年轻人奋斗创业最终取得成功的故事。", history=history)
print(response)
# 这是一个关于一个年轻人奋斗创业最终取得成功的故事。
# 故事的主人公叫李明,他来自一个普通的家庭,父母都是普通的工人。从小,李明就立下了一个目标:要成为一名成功的企业家。
# 为了实现这个目标,李明勤奋学习,考上了大学。在大学期间,他积极参加各种创业比赛,获得了不少奖项。他还利用课余时间去实习,积累了宝贵的经验。
# 毕业后,李明决定开始自己的创业之路。他开始寻找投资机会,但多次都被拒绝了。然而,他并没有放弃。他继续努力,不断改进自己的创业计划,并寻找新的投资机会。
# 最终,李明成功地获得了一笔投资,开始了自己的创业之路。他成立了一家科技公司,专注于开发新型软件。在他的领导下,公司迅速发展起来,成为了一家成功的科技企业。
# 李明的成功并不是偶然的。他勤奋、坚韧、勇于冒险,不断学习和改进自己。他的成功也证明了,只要努力奋斗,任何人都有可能取得成功。

# 第三轮对话
response, history = model.chat(tokenizer, "给这个故事起一个标题", history=history)
print(response)
# 《奋斗创业:一个年轻人的成功之路》

运行Qwen同样非常简单。

运行Qwen
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import GenerationConfig

# 可选的模型包括: "Qwen/Qwen-7B", "Qwen/Qwen-14B"
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B", trust_remote_code=True)

# 打开bf16精度A100、H100、RTX3060、RTX3070等显卡建议启用以节省显存
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="auto", trust_remote_code=True, bf16=True).eval()
# 打开fp16精度V100、P100、T4等显卡建议启用以节省显存
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="auto", trust_remote_code=True, fp16=True).eval()
# 使用CPU进行推理需要约32GB内存
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="cpu", trust_remote_code=True).eval()
# 默认使用自动模式,根据设备自动选择精度
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="auto", trust_remote_code=True).eval()

# 可指定不同的生成长度、top_p等相关超参
model.generation_config = GenerationConfig.from_pretrained("Qwen/Qwen-7B", trust_remote_code=True)

inputs = tokenizer('蒙古国的首都是乌兰巴托Ulaanbaatar\n冰岛的首都是雷克雅未克Reykjavik\n埃塞俄比亚的首都是', return_tensors='pt')
inputs = inputs.to(model.device)
pred = model.generate(**inputs)
print(tokenizer.decode(pred.cpu()[0], skip_special_tokens=True))
# 蒙古国的首都是乌兰巴托Ulaanbaatar\n冰岛的首都是雷克雅未克Reykjavik\n埃塞俄比亚的首都是亚的斯亚贝巴Addis Ababa...

若在使用上述代码时由于各种原因无法从 HuggingFace 拉取模型和代码,可以先从 ModelScope 下载模型及代码至本地,再从本地加载模型:

from modelscope import snapshot_download
from transformers import AutoModelForCausalLM, AutoTokenizer

# Downloading model checkpoint to a local dir model_dir
# model_dir = snapshot_download('qwen/Qwen-7B')
# model_dir = snapshot_download('qwen/Qwen-7B-Chat')
# model_dir = snapshot_download('qwen/Qwen-14B')
model_dir = snapshot_download('qwen/Qwen-14B-Chat')

# Loading local checkpoints
# trust_remote_code is still set as True since we still load codes from local dir instead of transformers
tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
    model_dir,
    device_map="auto",
    trust_remote_code=True
).eval()

🤖 ModelScope

魔搭ModelScope是开源的模型即服务共享平台为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品。使用ModelScope同样非常简单代码如下所示

from modelscope import AutoModelForCausalLM, AutoTokenizer
from modelscope import GenerationConfig

# 可选的模型包括: "qwen/Qwen-7B-Chat", "qwen/Qwen-14B-Chat"
tokenizer = AutoTokenizer.from_pretrained("qwen/Qwen-7B-Chat", trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained("qwen/Qwen-7B-Chat", device_map="auto", trust_remote_code=True, fp16=True).eval()
model.generation_config = GenerationConfig.from_pretrained("Qwen/Qwen-7B-Chat", trust_remote_code=True) # 可指定不同的生成长度、top_p等相关超参

response, history = model.chat(tokenizer, "你好", history=None)
print(response)
response, history = model.chat(tokenizer, "浙江的省会在哪里?", history=history) 
print(response)
response, history = model.chat(tokenizer, "它有什么好玩的景点", history=history)
print(response)

Batch推理

千问支持batch批量推理。在开启flash-attention的状态下使用batch推理可以约40%的提速。示例代码如下所示:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers import GenerationConfig
from qwen_generation_utils import make_context, decode_tokens, get_stop_words_ids

tokenizer = AutoTokenizer.from_pretrained(
    './',
    pad_token='<|extra_0|>',
    eos_token='<|endoftext|>',
    padding_side='left',
    trust_remote_code=True
)
model = AutoModelForCausalLM.from_pretrained(
    './',
    pad_token_id=tokenizer.pad_token_id,
    device_map="auto",
    trust_remote_code=True
).eval()
model.generation_config = GenerationConfig.from_pretrained('./', pad_token_id=tokenizer.pad_token_id)

all_raw_text = ["我想听你说爱我。", "今天我想吃点啥,甜甜的,推荐下", "我马上迟到了,怎么做才能不迟到"]
batch_raw_text = []
for q in all_raw_text:
    raw_text, _ = make_context(
        tokenizer,
        q,
        system="You are a helpful assistant.",
        max_window_size=model.generation_config.max_window_size,
        chat_format=model.generation_config.chat_format,
    )
    batch_raw_text.append(raw_text)

batch_input_ids = tokenizer(batch_raw_text, padding='longest')
batch_input_ids = torch.LongTensor(batch_input_ids['input_ids']).to(model.device)
batch_out_ids = model.generate(
    batch_input_ids,
    return_dict_in_generate=False,
    generation_config=model.generation_config
)
padding_lens = [batch_input_ids[i].eq(tokenizer.pad_token_id).sum().item() for i in range(batch_input_ids.size(0))]

batch_response = [
    decode_tokens(
        batch_out_ids[i][padding_lens[i]:],
        tokenizer,
        raw_text_len=len(batch_raw_text[i]),
        context_length=(batch_input_ids[i].size(0)-padding_lens[i]),
        chat_format="chatml",
        verbose=False,
        errors='replace'
    ) for i in range(len(all_raw_text))
]
print(batch_response)

response, _ = model.chat(tokenizer, "我想听你说爱我。", history=None)
print(response)

response, _ = model.chat(tokenizer, "今天我想吃点啥,甜甜的,推荐下", history=None)
print(response)

response, _ = model.chat(tokenizer, "我马上迟到了,怎么做才能不迟到", history=None)
print(response)

CPU

我们推荐你使用 qwen.cpp 来实现CPU部署和推理。qwen.cpp是Qwen和tiktoken的C++实现。你可以点击链接进入repo了解详情。

当然直接在CPU上运行模型也是可以的示例如下

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B-Chat", device_map="cpu", trust_remote_code=True).eval()

但是,这样的推理效率大概率会非常低。

多GPU

如果你遇到显存不足的问题而希望使用多张GPU进行推理可以使用上述的默认的使用方法读取模型。此前提供的脚本utils.py已停止维护。

尽管这个方法很简单但它的效率相对较低。我们建议使用vLLM和FastChat并请阅读部署章节。

量化

GPTQ

请注意:我们更新量化方案为基于 AutoGPTQ 的量化提供Int4量化模型。该方案在模型评测效果几乎无损且存储需求更低推理速度更优。

以下我们提供示例说明如何使用Int4量化模型。在开始使用前请先保证满足要求如torch 2.0及以上transformers版本为4.32.0及以上,等等),并安装所需安装包:

pip install auto-gptq optimum

如安装auto-gptq遇到问题,我们建议您到官方repo搜索合适的wheel。

随后即可使用和上述一致的用法调用量化模型:

# 可选模型包括:"Qwen/Qwen-7B-Chat-Int4", "Qwen/Qwen-14B-Chat-Int4"
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen-7B-Chat-Int4",
    device_map="auto",
    trust_remote_code=True
).eval()
response, history = model.chat(tokenizer, "Hi", history=None)

我们对BF16Int8和Int4模型在基准评测上做了测试发现量化模型效果损失较小结果如下所示

Quantization MMLU CEval (val) GSM8K Humaneval
Qwen-7B-Chat (BF16) 55.8 59.7 50.3 37.2
Qwen-7B-Chat (Int8) 55.4 59.4 48.3 34.8
Qwen-7B-Chat (Int4) 55.1 59.2 49.7 29.9
Qwen-14B-Chat (BF16) 64.6 69.8 60.1 43.9
Qwen-14B-Chat (Int8) 63.6 68.6 60.0 48.2
Qwen-14B-Chat (Int4) 63.3 69.0 59.8 45.7

KV cache量化

注意由于Hugging Face的内部实现本功能的支持文件cache_autogptq_cuda_356.cppcache_autogptq_cuda_kernel_245.cu可能没被下载。如需开启使用,请手动从相关位置下载,并放置到相应文件中。

在模型infer时可以将中间结果key以及value的值量化后压缩存储这样便可以在相同的卡上存储更多的key以及value增加样本吞吐。

提供use_cache_quantization以及use_cache_kernel两个参数对模型控制当use_cache_quantization以及use_cache_kernel均开启时将启动kv-cache量化的功能。具体使用如下

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen-7B-Chat",
     device_map="auto",
     trust_remote_code=True,
     use_cache_quantization=True,
     use_cache_kernel=True,
     use_flash_attn=False
)

注意当前该功能目前不支持与flash attn同时开启如果你开了kv cache量化的同时又开了flash attnuse_flash_attn=True use_cache_quantization=True, use_cache_kernel=True会默认将use_flash_attn关闭。

效果方面我们验证过Int8 kv-cache的使用对模型整体的精度指标基本无损。我们做了针对显存占用的性能测试。评测运行于单张A100-SXM4-80G GPU模型默认使用BF16格式默认生成的seq-length=1024生成1024个token其中oom表示out of memory。

开启了kv-cache量化之后模型在infer的时候可以开启更大的batch size(bs)

USE KVCache bs=1 bs=4 bs=16 bs=32 bs=64 bs=100
no 16.3GB 24.1GB 31.7GB 48.7GB oom oom
yes 15.5GB 17.2GB 22.3GB 30.2GB 48.2GB 72.4GB

开启了kv-cache量化之后模型在infer时预测更长的seq-lengthsl生成的token数结果时可以节约更多的显存。

USE KVCache sl=512 sl=1024 sl=2048 sl=4096 sl=8192
no 15.2GB 16.3GB 17.6GB 19.5GB 23.2GB
yes 15GB 15.5GB 15.8GB 16.6GB 17.6GB

模型开启kv cache量化后再模型infer的时候会将原始存进layer_past的float格式的key/value变成int8格式的qkey/qvalue和相对应的量化参数。 具体操作如下: 1、将key/value进行量化操作

    qv,scale,zero_point=quantize_cache_v(v)

2、存入layer_past中: 量化格式的layer_past:

    layer_past=((q_key,key_scale,key_zero_point),
                (q_value,value_scale,value_zero_point))

原始格式的layer_past:

    layer_past=(key,value)

如果需要将layer_past中存好的keyvalue直接取出使用可以使用反量化操作将int8格式的key/value转回float格式

    v=dequantize_cache_torch(qv,scale,zero_point)

推理性能

这一部分将介绍模型推理的速度和显存占用的相关数据。下文的性能测算使用 此脚本 完成。

推理速度

我们测算了BF16、Int8和Int4模型在使用flash attention v2、v1或不使用时生成2048和8192个token的平均推理速度tokens/s。结果如下所示

Model SizePrecisionFlashAttnSequence Length
20488192
7BBF16v240.9336.14
v140.7535.34
Disabled37.5533.56
Int8v237.4732.54
v137.5132.39
Disabled37.8432.65
Int4v250.0938.61
v145.9836.47
Disabled48.1236.70
14BBF16v232.8824.87
v132.7628.89
Disabled29.3222.91
Int8v229.2824.22
v128.3123.87
Disabled31.1224.60
Int4v238.7227.33
v137.8126.46
Disabled37.6526.00

评测运行于单张A100-SXM4-80G GPU使用PyTorch 2.0.1和CUDA 11.4。推理速度是编码2048个token和生成8192个token的速度均值。

注意以上Int4/Int8模型生成速度使用autogptq库给出当前AutoModelForCausalLM.from_pretrained载入的模型生成速度会慢大约20%。我们已经将该问题汇报给HuggingFace团队若有解决方案将即时更新。

显存使用

我们还测算了BF16、Int8和Int4模型编码2048个token及生成8192个token的峰值显存占用情况。结果GB如下所示

Model SizePrecisionSequence Length
20488192
7BBF1616.9922.53
Int811.2016.62
Int48.2113.63
14BBF1630.1538.94
Int818.8127.54
Int413.0121.79

微调

使用方法

我们提供了finetune.py这个脚本供用户实现在自己的数据上进行微调的功能以接入下游任务。此外我们还提供了shell脚本减少用户的工作量。这个脚本支持 DeepSpeedFSDP 。我们提供的shell脚本使用了DeepSpeed因此建议您确保已经安装DeepSpeed。

首先你需要准备你的训练数据。你需要将所有样本放到一个列表中并存入json文件中。每个样本对应一个字典包含id和conversation其中后者为一个列表。示例如下所示

[
  {
    "id": "identity_0",
    "conversations": [
      {
        "from": "user",
        "value": "你好"
      },
      {
        "from": "assistant",
        "value": "我是一个语言模型,我叫通义千问。"
      }
    ]
  }
]

准备好数据后你可以使用我们提供的shell脚本实现微调。注意你需要在脚本中指定你的数据的路径。

微调脚本能够帮你实现:

  • 全参数微调
  • LoRA
  • Q-LoRA

全参数微调在训练过程中更新所有参数。你可以运行这个脚本开始训练:

# 分布式训练。由于显存限制将导致单卡训练失败,我们不提供单卡训练脚本。
sh finetune/finetune_ds.sh

尤其注意你需要在脚本中指定正确的模型名称或路径、数据路径、以及模型输出的文件夹路径。在这个脚本中我们使用了DeepSpeed ZeRO 3。如果你想修改这个配置可以删除掉--deepspeed这个输入或者自行根据需求修改DeepSpeed配置json文件。此外我们支持混合精度训练因此你可以设置--bf16 True或者--fp16 True。在使用fp16时请使用DeepSpeed支持混合精度训练。经验上如果你的机器支持bf16我们建议使用bf16这样可以和我们的预训练和对齐训练保持一致这也是为什么我们把默认配置设为它的原因。

运行LoRA的方法类似全参数微调。但在开始前请确保已经安装peft代码库。另外记住要设置正确的模型、数据和输出路径。我们建议你为模型路径使用绝对路径。这是因为LoRA仅存储adapter部分参数而adapter配置json文件记录了预训练模型的路径用于读取预训练模型权重。同样你可以设置bf16或者fp16。

# 单卡训练
sh finetune/finetune_lora_single_gpu.sh
# 分布式训练
sh finetune/finetune_lora_ds.sh

与全参数微调不同LoRA (论文) 只更新adapter层的参数而无需更新原有语言模型的参数。这种方法允许用户用更低的显存开销来训练模型也意味着更小的计算开销。

注意如果你使用预训练模型进行LoRA微调而非chat模型模型的embedding和输出层的参数将被设为可训练的参数。这是因为预训练模型没有学习过ChatML格式中的特殊token因此需要将这部分参数设为可训练才能让模型学会理解和预测这些token。这也意味着假如你的训练引入新的特殊token你需要通过代码中的modules_to_save将这些参数设为可训练的参数。此外这部分训练参数的引入会影响ZeRO 3的使用因此我们默认推荐使用ZeRO 2。当然如果你不需要引入这部分训练参数你可以通过替换DeepSpeed的配置文件来使用ZeRO 3。如果你想节省显存占用可以考虑使用chat模型进行LoRA微调显存占用将大幅度降低。下文的显存占用和训练速度的记录将详细介绍这部分细节。

如果你依然遇到显存不足的问题可以考虑使用Q-LoRA (论文) 。该方法使用4比特量化模型以及paged attention等技术实现更小的显存开销。

注意如你使用单卡Q-LoRA你可能需要安装mpi4py。你可以通过pip或者conda来安装。

运行Q-LoRA你只需运行如下脚本

# 单卡训练
sh finetune/finetune_qlora_single_gpu.sh
# 分布式训练
sh finetune/finetune_qlora_ds.sh

我们建议你使用我们提供的Int4量化模型进行训练即Qwen-7B-Chat-Int4。请不要使用非量化模型与全参数微调以及LoRA不同Q-LoRA仅支持fp16。注意由于我们发现torch amp支持的fp16混合精度训练存在问题因此当前的单卡训练Q-LoRA必须使用DeepSpeed。此外上述LoRA关于特殊token的问题在Q-LoRA依然存在。并且Int4模型的参数无法被设为可训练的参数。所幸的是我们只提供了Chat模型的Int4模型因此你不用担心这个问题。但是如果你执意要在Q-LoRA中引入新的特殊token很抱歉我们无法保证你能成功训练。

注意由于Hugging Face的内部实现模型在保存时一些非Python文件未保存例如*.cpp*.cu),如需要支持相关功能,请手动复制有关文件。

与全参数微调不同LoRA和Q-LoRA的训练只需存储adapter部分的参数。假如你需要使用LoRA训练后的模型你需要使用如下方法。假设你使用Qwen-7B训练模型你可以用如下代码读取模型

from peft import AutoPeftModelForCausalLM

model = AutoPeftModelForCausalLM.from_pretrained(
    path_to_adapter, # path to the output directory
    device_map="auto",
    trust_remote_code=True
).eval()

如果你觉得这样一步到位的方式让你很不安心或者影响你接入下游应用你可以选择先合并并存储模型LoRA支持合并Q-LoRA不支持再用常规方式读取你的新模型示例如下

from peft import AutoPeftModelForCausalLM

model = AutoPeftModelForCausalLM.from_pretrained(
    path_to_adapter, # path to the output directory
    device_map="auto",
    trust_remote_code=True
).eval()

merged_model = model.merge_and_unload()
# max_shard_size and safe serialization are not necessary. 
# They respectively work for sharding checkpoint and save the model to safetensors
merged_model.save_pretrained(new_model_directory, max_shard_size="2048MB", safe_serialization=True)

new_model_directory目录将包含合并后的模型参数与相关模型代码。请注意*.cu*.cpp文件可能没被保存,请手动复制。另外,merge_and_unload仅保存模型并未保存tokenizer如有需要请复制相关文件或使用以以下代码保存

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(
    path_to_adapter, # path to the output directory
    trust_remote_code=True
)
tokenizer.save_pretrained(new_model_directory)

注意:分布式训练需要根据你的需求和机器指定正确的分布式训练超参数。此外,你需要根据你的数据、显存情况和训练速度预期,使用--model_max_length设定你的数据长度。

显存占用及训练速度

下面记录7B和14B模型在单GPU使用LoRALoRA (emb)指的是embedding和输出层参与训练而LoRA则不优化这部分参数和QLoRA时处理不同长度输入的显存占用和训练速度的情况。本次评测运行于单张A100-SXM4-80G GPU使用CUDA 11.8和Pytorch 2.0并使用了flash attention 2。我们统一使用batch size为1gradient accumulation为8的训练配置记录输入长度分别为256、512、1024、2048、4096和8192的显存占用GB和训练速度s/iter。我们还使用2张A100测了Qwen-7B的全参数微调。受限于显存大小我们仅测试了256、512和1024token的性能。具体数值如下所示

Model SizeMethodSequence Length
2565121024204840968192
7BLoRA20.1G / 1.2s/it20.4G / 1.5s/it21.5G / 2.8s/it23.8G / 5.2s/it29.7G / 10.1s/it36.6G / 21.3s/it
LoRA (emb)33.7G / 1.4s/it34.1G / 1.6s/it35.2G / 2.9s/it35.1G / 5.3s/it39.2G / 10.3s/it48.5G / 21.7s/it
Q-LoRA11.5G / 3.0s/it11.5G / 3.0s/it12.3G / 3.5s/it13.9G / 7.0s/it16.9G / 11.6s/it23.5G / 22.3s/it
Full-parameter139.2G / 4.0s/it148.0G / 4.0s/it162.0G / 4.5s/it---
14BLoRA34.6G / 1.6s/it35.1G / 2.4s/it35.3G / 4.4s/it37.4G / 8.4s/it42.5G / 17.0s/it55.2G / 36.0s/it
LoRA (emb)51.2 / 1.7s/it51.1G / 2.6s/it51.5G / 4.6s/it54.1G / 8.6s/it56.8G / 17.2s/it67.7G / 36.3s/it
Q-LoRA18.7G / 5.3s/it18.4G / 6.3s/it18.9G / 8.2s/it19.9G / 11.8s/it23.0G / 20.1s/it27.9G / 38.3s/it

部署

vLLM

如希望部署及加速推理我们建议你使用vLLM和FastChat。首先安装相应的代码库

pip install vllm
pip install "fschat[model_worker,webui]"

你也可以通过git clonepip install -e .的方式通过源码安装。如果遇到安装问题,请阅读它们的官方文档。

使用vLLM和FastChat运行Qwen之前首先启动一个controller

python -m fastchat.serve.controller

然后启动model worker读取模型。如使用单卡推理运行如下命令

python -m fastchat.serve.vllm_worker --model-path $model_path --trust-remote-code

然而如果你希望使用多GPU加速推理或者增大显存你可以使用vLLM支持的模型并行机制。假设你需要在4张GPU上运行你的模型命令如下所示

python -m fastchat.serve.vllm_worker --model-path $model_path --trust-remote-code --tensor-parallel-size 4

启动model worker后你可以启动一个web demo或者OpenAI API。启动web demo的命令如下

python -m fastchat.serve.gradio_web_server

使用OpenAI API前请阅读我们的API章节配置好环境然后运行如下命令

python -m fastchat.serve.openai_api_server --host localhost --port 8000

Demo

Web UI

我们提供了Web UI的demo供用户使用 (感谢 @wysaid 支持)。在开始前,确保已经安装如下代码库:

pip install -r requirements_web_demo.txt

随后运行如下命令,并点击生成链接:

python web_demo.py



交互式Demo

我们提供了一个简单的交互式Demo示例请查看cli_demo.py。当前模型已经支持流式输出用户可通过输入文字的方式和Qwen-7B-Chat交互模型将流式输出返回结果。运行如下命令

python cli_demo.py




API

最简单的使用Qwen模型API服务的方法就是通过DashScope阿里云灵积模型服务。我们提供了简单介绍说明使用方法。同时我们还提供了自己部署OpenAI格式的API的方法。

DashScope

DashScope是阿里云提供的大语言模型的API服务目前支持Qwen。但请注意目前提供服务的Qwen模型为内部模型暂无更多具体细节对外透露。模型服务包括qwen-turboqwen-plus。前者速度更快,后者效果更优。详情请查看文档

请首先前往官网开通DashScope获得API KeyAK。建议通过环境变量设置AK

export DASHSCOPE_API_KEY="YOUR_DASHSCOPE_API_KEY"

随后安装相关代码包,点击此处查看安装文档。如使用python则直接通过pip安装

pip install dashscope

如安装JAVA SDK则通过如下命令安装

<!-- https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dashscope-sdk-java</artifactId>
    <version>the-latest-version</version>
</dependency>

最简单的使用方法就是通过messages调用用法类似OpenAI API。示例如下

import random
from http import HTTPStatus
from dashscope import Generation


def call_with_messages():
    messages = [{'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'user', 'content': '如何做西红柿鸡蛋?'}]
    gen = Generation()
    response = gen.call(
        Generation.Models.qwen_turbo,
        messages=messages,
        seed=random.randint(1, 10000),  # set the random seed, optional, default to 1234 if not set
        result_format='message',  # set the result to be "message" format.
    )
    return response


if __name__ == '__main__':
    response = call_with_messages()
    if response.status_code == HTTPStatus.OK:
        print(response)
    else:
        print('Request id: %s, Status code: %s, error code: %s, error message: %s' % (
            response.request_id, response.status_code,
            response.code, response.message
        ))

更多用法请查看官方文档了解详情。

OpenAI API

我们提供了OpenAI API格式的本地API部署方法感谢@hanpenggit。在开始之前先安装必要的代码库

pip install fastapi uvicorn openai "pydantic>=2.3.0" sse_starlette

随后即可运行以下命令部署你的本地API

python openai_api.py

你也可以修改参数,比如-c来修改模型名称或路径, --cpu-only改为CPU部署等等。如果部署出现问题更新上述代码库往往可以解决大多数问题。

使用API同样非常简单示例如下

import openai
openai.api_base = "http://localhost:8000/v1"
openai.api_key = "none"

# 使用流式回复的请求
for chunk in openai.ChatCompletion.create(
    model="Qwen",
    messages=[
        {"role": "user", "content": "你好"}
    ],
    stream=True
    # 流式输出的自定义stopwords功能尚未支持正在开发中
):
    if hasattr(chunk.choices[0].delta, "content"):
        print(chunk.choices[0].delta.content, end="", flush=True)

# 不使用流式回复的请求
response = openai.ChatCompletion.create(
    model="Qwen",
    messages=[
        {"role": "user", "content": "你好"}
    ],
    stream=False,
    stop=[] # 在此处添加自定义的stop words 例如ReAct prompting时需要增加 stop=["Observation:"]。
)
print(response.choices[0].message.content)



该接口也支持函数调用(Function Calling),但暂时仅限 stream=False 时能生效。用法见函数调用示例

工具调用

Qwen-Chat针对工具使用、函数调用能力进行了优化。用户可以开发基于Qwen的Agent、LangChain应用、甚至Code Interpreter。

我们提供了文档说明如何根据ReAct Prompting的原理实现工具调用请参见ReAct示例。基于该原理,我们在 openai_api.py 里提供了函数调用Function Calling的支持。 我们在已开源的中文评测数据集上测试模型的工具调用能力并发现Qwen-Chat能够取得稳定的表现

中文工具调用评测基准
ModelTool Selection (Acc.↑)Tool Input (Rouge-L↑)False Positive Error↓
GPT-495%0.9015.0%
GPT-3.585%0.8875.0%
Qwen-7B-Chat98%0.917.3%
Qwen-14B-Chat98%0.932.4%

为了考察Qwen使用Python Code Interpreter完成数学解题、数据可视化、及文件处理与爬虫等任务的能力我们专门建设并开源了一个评测这方面能力的评测基准。 我们发现Qwen在生成代码的可执行率、结果正确性上均表现较好

生成代码的可执行率 (%)
ModelMath↑Visualization↑General↑
GPT-491.985.982.8
GPT-3.589.265.074.1
LLaMA2-7B-Chat 41.9 33.1 24.1
LLaMA2-13B-Chat 50.0 40.5 48.3
CodeLLaMA-7B-Instruct 85.1 54.0 70.7
CodeLLaMA-13B-Instruct 93.2 55.8 74.1
InternLM-7B-Chat-v1.1 78.4 44.2 62.1
InternLM-20B-Chat 70.3 44.2 65.5
Qwen-7B-Chat 82.4 64.4 67.2
Qwen-14B-Chat 89.2 84.1 65.5
代码执行结果的正确率 (%)
ModelMath↑Visualization-Hard↑Visualization-Easy↑
GPT-482.866.760.8
GPT-3.547.333.355.7
LLaMA2-7B-Chat 3.9 14.3 39.2
LLaMA2-13B-Chat 8.3 8.3 40.5
CodeLLaMA-7B-Instruct 14.3 26.2 60.8
CodeLLaMA-13B-Instruct 28.2 27.4 62.0
InternLM-7B-Chat-v1.1 28.5 4.8 40.5
InternLM-20B-Chat 34.6 21.4 45.6
Qwen-7B-Chat 41.9 40.5 54.4
Qwen-14B-Chat 58.4 53.6 59.5



此外我们还提供了实验结果表明我们的模型具备扮演HuggingFace Agent的能力详见示例文档了解更多信息。模型在Hugging Face提供的评测数据集上表现如下

HuggingFace Agent评测基准 - Run模式
ModelTool Selection↑Tool Used↑Code↑
GPT-410010097.4
GPT-3.595.496.387.0
StarCoder-Base-15B86.187.068.9
StarCoder-15B87.088.068.9
Qwen-7B-Chat87.087.071.5
Qwen-14B-Chat93.594.487.0
HuggingFace Agent评测基准 - Chat模式
ModelTool Selection↑Tool Used↑Code↑
GPT-497.997.998.5
GPT-3.597.396.889.6
StarCoder-Base-15B97.997.991.1
StarCoder-15B97.997.989.6
Qwen-7B-Chat94.794.785.1
Qwen-14B-Chat97.997.995.5

长文本理解

我们引入了NTK插值、窗口注意力、LogN注意力缩放等技术来提升模型的上下文长度并突破训练序列长度的限制。通过arXiv数据集上的语言模型实验我们的原生长度为2K的Qwen-7B/14B在8K的序列长度下依然表现不错而原生长度扩展到8K的Qwen-7B能够在32K长序列的设置下取得不错的表现。

ModelSequence Length
10242048409681921638432768
Qwen-7B (original)4.233.7839.35469.812645.09-
+ dynamic_ntk4.233.783.593.665.71-
+ dynamic_ntk + logn4.233.783.583.564.62-
+ dynamic_ntk + logn + window_attn4.233.783.583.494.32-
Qwen-7B4.233.813.523.317.27181.49
+ dynamic_ntk4.233.813.523.313.233.33
+ dynamic_ntk + logn + window_attn4.233.813.523.333.223.17
Qwen-14B-3.4622.79334.653168.35-
+ dynamic_ntk + logn + window_attn-3.463.293.183.42-

Tokenization

作为术语的“tokenization”在中文中尚无共识的概念对应本文档采用英文表达以利说明。

基于tiktoken的tokenizer有别于其他分词器比如sentencepiece tokenizer。尤其在微调阶段需要特别注意特殊token的使用。关于tokenizer的更多信息以及微调时涉及的相关使用请参阅文档

复现

我们提供了评测脚本以供复现我们的实验结果。注意,由于内部代码和开源代码存在少许差异,评测结果可能与汇报结果存在细微的结果不一致。请阅读eval/EVALUATION.md了解更多信息。

FAQ

如遇到问题,敬请查阅FAQ以及issue区如仍无法解决再提交issue。

引用

如果你觉得我们的工作对你有帮助,欢迎引用!

@article{qwen,
  title={Qwen Technical Report},
  author={Jinze Bai and Shuai Bai and Yunfei Chu and Zeyu Cui and Kai Dang and Xiaodong Deng and Yang Fan and Wenbin Ge and Yu Han and Fei Huang and Binyuan Hui and Luo Ji and Mei Li and Junyang Lin and Runji Lin and Dayiheng Liu and Gao Liu and Chengqiang Lu and Keming Lu and Jianxin Ma and Rui Men and Xingzhang Ren and Xuancheng Ren and Chuanqi Tan and Sinan Tan and Jianhong Tu and Peng Wang and Shijie Wang and Wei Wang and Shengguang Wu and Benfeng Xu and Jin Xu and An Yang and Hao Yang and Jian Yang and Shusheng Yang and Yang Yao and Bowen Yu and Hongyi Yuan and Zheng Yuan and Jianwei Zhang and Xingxuan Zhang and Yichang Zhang and Zhenru Zhang and Chang Zhou and Jingren Zhou and Xiaohuan Zhou and Tianhang Zhu},
  journal={arXiv preprint arXiv:2309.16609},
  year={2023}
}

使用协议

研究人员与开发者可使用Qwen和Qwen-Chat或进行二次开发。我们同样允许商业使用具体细节请查看LICENSE。如需商用,请填写问卷(7B, 14B)申请。

联系我们

如果你想给我们的研发团队和产品团队留言欢迎加入我们的微信群和Discord server。当然也可以通过邮件qianwen_opensource@alibabacloud.com联系我们。