Firefly-13B开源,QLoRA+百万数据,单卡可训百亿大模型
作者: AINLP 来源: [AINLP](https://mp.weixin.qq.com/s/yDDC8FZWLeHY9imUukmHqw)
前言 :欢迎关注我们的中文大语言模型开源项目Firefly(流萤)。目前我们的项目支持对baichuan、ziya、bloom、llama等主流大模型进行指令微调,同时支持全量微调和QLoRA高效微调。我们整理并开源了多个主流的高质量的中英文指令数据集,读者可以快速上手微调自己的大模型。
项目地址:https://github.com/yangjianxin1/Firefly
此前,Firefly项目依次开源了firefly-bloom-1b4、firefly-bloom-2b6、firefly-bloom-7b1和firefly-baichuan-7b等中文大模型,这些模型也见证了我们项目的迭代历程。
此次,我们将开源Firefly项目的第一个百亿参数规模的中英文大模型firefly-ziya-13b,该模型基于ziya-13b的预训练权重,使用百万中英文指令数据进行微调。
接下来的章节主要介绍firefly-ziya-13b的基座模型、训练策略、模型效果等。模型权重和训练数据等,详见文末链接。
01
Ziya模型简介
此次我们开源的firefly-ziya-13b模型,正如其名称所示,我们选择了IDEA团队的Ziya-LLaMA-13B-Pretrain-v1作为基座模型。本章节主要对该基座模型进行介绍。
Ziya-LLaMA-13B-Pretrain-v1 是基于LLaMA的130亿参数大规模预训练模型,针对中文分词优化,并完成了中英文 110B tokens 的增量预训练,进一步提升了中文生成和理解能力。
原始数据包含英文和中文,其中英文数据来自openwebtext、Books、Wikipedia和Code,中文数据来自清洗后的悟道数据集、IDEA自建的中文数据集。在对原始数据进行去重、模型打分、数据分桶、规则过滤、敏感主题过滤和数据评估后,最终得到125B tokens的有效数据。
为了解决LLaMA原生分词对中文编解码效率低下的问题,IDEA在LLaMA词表的基础上增加了7k+个常见中文字,通过和LLaMA原生的词表去重,最终得到一个39410大小的词表,并通过复用Transformers里LlamaTokenizer来实现了这一效果。
以下是Ziya-LLaMA-13B-Pertrain-v1 和原始的LLaMA 模型分别在中英文评测集上的表现。
可以看到,相比于LLaMA模型,Ziya-LLaMA-13B-Pertrain-v1在中文评测集上的0-shot与5-shot效果都更优秀,证明了其在中文能力上有显著的提升。且两者在英文评测集HELM上的效果基本上持平,在部分子任务上互有胜负,表明其英文能力没有受到较大的损失。
除此之外,我们关注到Ziya官方的sft模型在SuperCLUE中文大模型榜单上的表现也不错。
Ziya-LLaMA-13B-Pertrain-v1在增量预训练时,采用的是全量参数训练,而不是LoRA等轻量级微调的方式,理论上来说会比LoRA增量预训练的模型效果更好。
基于上述分析,我们项目选择了Ziya-LLaMA-13B-Pertrain-v1作为13b的基座模型。
02
训练策略
QLoRA是一种可以使用较低成本对大模型进行微调的技术,该方法具有非常不错的效果。QLoRA官方的Guanaco-65b模型在LLM Leaderboard中目前排名第二(注:该模型仅使用了9千多条OASST1的数据进行微调 )。
Firefly项目中集成了QLoRA训练流程,并且我们已经多次使用QLoRA训练模型,开源了firefly-bloom-7b1和firefly-baichuan-7b模型,获得了不错的效果。基于上述原因,我们依旧采用QLoRA技术训练firefly-ziya-13b模型。
对于QLoRA的原理和训练流程尚不熟悉的同学,可参考我们的往期文章:
训练数据方面,我们依旧使用moss-003-sft-data数据,并且从BELLE项目的数学数据中,随机采样了5000条数据。合并之后数据量为100万+,训练一个epoch。
训练时,我们将多轮对话拼接成如下格式,然后进行tokenize。
<s>input1</s>target1</s>input2</s>target2</s>...
在计算loss时,我们通过mask的方式,input部分的loss不参与参数更新,只有“target”部分的loss参与参数更新。这种方式充分利用了模型并行计算的优势,训练更加高效,且多轮对话中的每个target部分都参与了训练,训练更充分。否则,就需要把一个n轮对话,拆分成n条数据,且只计算最后一个target的loss,大大降低了训练效率。
loss计算的实现方式可参考以下代码:
https://github.com/yangjianxin1/Firefly/blob/master/component/loss.py#L3
对于QLoRA,除了embedding和lm_head外,我们在所有全连接层都插入adapter,其中lora_rank为64,lora_alpha为16,lora_dropout为0.05。最终参与训练的参数量约为2.5亿 。
训练超参数如下所示:
max length 1024
lr_scheduler_type constant_with_warmup
batch size 64
lr 1e-4
warmup step 3000
optimizer paged_adamw_32bit
training step 15k
在单张V100上,使用QLoRA技术并且开启gradient_checkpointing后,可以将batch size设为8,长度设为1024,对13b的模型进行训练,所以读者可以低资源复现我们的模型效果。
模型的训练损失的变化趋势如下图所示,训练损失的下降比较平滑,且比我们之前训练baichun-7b和bloom-7b1时的loss下降得更快更低。训完一个epoch之后,loss尚未有收敛的趋势。
03
使用方式
模型的用法非常简单,直接运行下面的脚本即可,我们提供了单轮对话和多轮对话的脚本。该脚本兼容多模型,只需要修改model_name,即可使用我们之前开源的firefly-bloom-7b1和firefly-baichuan-7b模型。
使用firefly-ziya-13b进行单轮对话的方式如下:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
"""
单轮对话,不具有对话历史的记忆功能
"""
def main():
# model_name = 'YeungNLP/firefly-baichuan-7b'
model_name = 'YeungNLP/firefly-ziya-13b'
# model_name = 'YeungNLP/firefly-bloom-7b1'
max_new_tokens = 500
top_p = 0.9
temperature = 0.35
repetition_penalty = 1.0
device = 'cuda'
input_pattern = '<s>{}</s>'
model = AutoModelForCausalLM.from_pretrained(
model_name,
trust_remote_code=True,
low_cpu_mem_usage=True,
torch_dtype=torch.float16,
device_map='auto'
).to(device).eval()
tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True,
# llama不支持fast
use_fast=False if model.config.model_type == 'llama' else True
)
text = input('User:')
while True:
text = text.strip()
text = input_pattern.format(text)
input_ids = tokenizer(text, return_tensors="pt", add_special_tokens=False).input_ids.to(device)
with torch.no_grad():
outputs = model.generate(
input_ids=input_ids, max_new_tokens=max_new_tokens, do_sample=True,
top_p=top_p, temperature=temperature, repetition_penalty=repetition_penalty,
eos_token_id=tokenizer.eos_token_id
)
outputs = outputs.tolist()[0][len(input_ids[0]):]
response = tokenizer.decode(outputs)
response = response.strip().replace(text, "").replace('</s>', "").replace('<s>', "").strip()
print("Firefly:{}".format(response))
text = input('User:')
if __name__ == '__main__':
main()
使用firefly-ziya-13b进行多轮对话的方式如下:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
def main():
# model_name = 'YeungNLP/firefly-baichuan-7b'
model_name = 'YeungNLP/firefly-ziya-13b'
# model_name = 'YeungNLP/firefly-bloom-7b1'
device = 'cuda'
max_new_tokens = 500 # 每轮对话最多生成多少个token
history_max_len = 1000 # 模型记忆的最大token长度
top_p = 0.9
temperature = 0.35
repetition_penalty = 1.0
# 加载模型
model = AutoModelForCausalLM.from_pretrained(
model_name,
trust_remote_code=True,
low_cpu_mem_usage=True,
torch_dtype=torch.float16,
device_map='auto'
).to(device).eval()
tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True,
# llama不支持fast
use_fast=False if model.config.model_type == 'llama' else True
)
# 记录所有历史记录
history_token_ids = tokenizer('<s>', return_tensors="pt").input_ids
# 开始对话
user_input = input('User:')
while True:
user_input = '{}</s>'.format(user_input)
user_input_ids = tokenizer(user_input, return_tensors="pt", add_special_tokens=False).input_ids
history_token_ids = torch.concat((history_token_ids, user_input_ids), dim=1)
model_input_ids = history_token_ids[:, -history_max_len:].to(device)
with torch.no_grad():
outputs = model.generate(
input_ids=model_input_ids, max_new_tokens=max_new_tokens, do_sample=True, top_p=top_p,
temperature=temperature, repetition_penalty=repetition_penalty, eos_token_id=tokenizer.eos_token_id
)
model_input_ids_len = model_input_ids.size(1)
response_ids = outputs[:, model_input_ids_len:]
history_token_ids = torch.concat((history_token_ids, response_ids.cpu()), dim=1)
response = tokenizer.batch_decode(response_ids)
print("Firefly:" + response[0].strip().replace('</s>', ""))
user_input = input('User:')
if __name__ == '__main__':
main()
04
模型效果
下面的样例均为firefly-ziya-13b模型所生成,未经修改,可能存在事实性错误,仅供参考。由于图片中的字体过小,建议放大图片后进行阅读。
更好的阅读效果,以及更丰富的生成样例,请查看文末的共享文档链接。
多轮对话
我们测试了模型的多轮对话能力,效果远超出了我们的预期,非常惊艳。模型在上下文理解、指代消歧方面的能力都非常优秀。即使是非常长的对话历史,模型也能正确地理解用户当前对话意图。**
对话示例1:
对话示例2:
数学题
尽管我们只在训练语料中加入了5000条数学题的数据,但是模型依然给了我们很大的惊喜。这5000条数据,激活了模型的数学推理能力,在做一些常见的加减乘除数学题时,大多数情况下,模型能够清晰地给出解题步骤,并给出正确的答案。
仅用5000条数学数据激活模型的数学推理能力,这与LIMA和Guanaco,以及近来的研究结论相契合:知识来源于预训练,指令微调更多是与人类指令对齐,少数高质量的指令数据,即可很大程度激活模型的能力。
由于topp解码方式中带有一定的随机性,有时可能会采样到错误的解题思路,从而得到错误的结果。在解数学题的时候,可以尝试beam search或者贪婪解码等确定性解码策略。
为了避免数学题在训练集中出现过,下面的测试题目均为我们大开脑洞,随机书写的。
知识库问答
我们从网上找了一些近期的新闻片段,来测试模型的知识库问答能力。模型的表现也相当不错,基本上都能够根据给定的文章内容,生成合适的答案,这在知识库问答场景中有非常大的实用价值。
医疗问答
中英翻译
我们测试了一些常规的中英翻译case,以及将古诗词翻译成英文的能力,表现也不错,翻译结果与古诗词表达的意境相近。****
邮件生成
商品文案生成
其他示例
05
结语
从有限的评测case来看,firefly-ziya-13b具有十分优秀的指令遵从能力,且Ziya-LLaMA-13B-Pretrain-v1+QLoRA的方式,值得在中英文下游任务中进行尝试。
由于尚未在开源测试集或LLM榜单上进行评测,客观的评测结果尚不得知。后续若有时间精力,将会对评测部分的工作进行补充。
后续我们将会在模型量化、推理加速、模型评测等方面对项目进行优化,欢迎大家持续关注Firefly项目:
https://github.com/yangjianxin1/Firefly
欢迎大家到知乎 评论区一起讨论交流,点击阅读原文 即可跳转到知乎文章。
firefly-ziya-13b权重:
https://huggingface.co/YeungNLP/firefly-ziya-13b
Ziya-LLaMA-13B-Pretrain-v1权重:
https://huggingface.co/YeungNLP/Ziya-LLaMA-13B-Pretrain-v1
moss数据集:
https://huggingface.co/datasets/YeungNLP/moss-003-sft-data
math数据集:
https://huggingface.co/datasets/YeungNLP/school_math_0.25M
**进技术交流群请添加AINLP小助手微信(id: ainlp2)**
**请备注具体方向+所用到的相关技术点**
![](https://api.allorigins.win/raw?url=https://mmbiz.qpic.cn/mmbiz_jpg/nW2ZPfuYqSJADkmZ2IX6Z23znAibuEevotDMq9iaMxiapK7jfMibiauGFkycicAJEs6x5U9SGyDJZ0S1tRed9TPNUUDQ/640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1)
**关于AINLP**
AINLP 是一个有趣有AI的自然语言处理社区,专注于 AI、NLP、机器学习、深度学习、推荐算法等相关技术的分享,主题包括文本摘要、智能问答、聊天机器人、机器翻译、自动生成、知识图谱、预训练模型、推荐系统、计算广告、招聘信息、求职经验分享等,欢迎关注!加技术交流群请添加AINLP小助手微信(id:ainlp2),备注工作/研究方向+加群目的。
![](https://api.allorigins.win/raw?url=https://mmbiz.qpic.cn/mmbiz_jpg/nW2ZPfuYqSKABHCqVVQkVYPrM4XY1vsd0iaeuXzyJnoFc8cibd5mYb4wdA3WMQtiaPVmr0XLZHMuVibqWncibpnTSnQ/640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1)
**阅读至此了,分享、点赞、在看三选一吧🙏**