MOSS是复旦大学邱锡鹏团队推出的一个支持中英双语和多种插件的开源对话语言模型,moss-moon系列模型具有160亿参数,在FP16精度下可在单张A100/A800或两张3090显卡运行,在INT4/8精度下可在单张3090显卡运行
其基座语言模型在约七千亿中英文以及代码单词上预训练得到,后续经过对话指令微调、插件增强学习和人类偏好训练具备多轮对话能力及使用多种插件的能力
moss-moon-003-sft
基础上还具备使用搜索引擎、文生图、计算器、解方程等四种插件的能力。moss-moon-003-sft
模型,约占用12GB显存即可进行推理。moss-moon-003-sft
模型,约占用24GB显存即可进行推理。moss-moon-003-sft-plugin
模型,约占用12GB显存即可进行推理。moss-moon-003-sft-plugin
模型,约占用24GB显存即可进行推理。moss-moon-003-sft
收集到的偏好反馈数据上训练得到的偏好模型,将在近期开源。moss-moon-003-sft
基础上经过偏好模型moss-moon-003-pm
训练得到的最终模型,具备更好的事实性和安全性以及更稳定的回复质量,将在近期开源。moss-moon-003-sft-plugin
基础上经过偏好模型moss-moon-003-pm
训练得到的最终模型,具备更强的意图理解能力和插件使用能力,将在近期开源。text-davinci-003
生成的约57万条英文对话和59万条中文对话moss-moon-003-sft
所使用的多轮对话数据,基于MOSS-002内测阶段采集的约10万用户输入数据和gpt-3.5-turbo
构造而成,相比moss-002-sft-data
,moss-003-sft-data
更加符合真实用户意图分布,包含更细粒度的有用性类别标记、更广泛的无害性数据和更长对话轮数,约含110万条对话数据。目前仅开源少量示例数据,完整数据将在近期开源moss-moon-003-sft-plugin
所使用的插件增强的多轮对话数据,包含支持搜索引擎、文生图、计算器、解方程等四个插件在内的约30万条多轮对话数据。目前仅开源少量示例数据,完整数据将在近期开源moss-moon-003-pm
所使用的偏好数据,包含在约18万额外对话上下文数据及使用moss-moon-003-sft
所产生的回复数据上构造得到的偏好对比数据,将在近期开源我司七月杜助教写了一篇部署MOSS的教程,详情请点击:MOSS模型量化版部署过程
baichuan-7B 是由百川智能(CEO为原搜狗创始人王小川)开发的一个开源可商用的大规模预训练语言模型
虽然baichuan-7B采用了和LLaMA一样的模型设计,但他们在原本的 LLaMA 框架上进行诸多修改
比如为提升模型的效果以及解码效率,做了
比如为提升训练时的吞吐,做了以下优化
基于上述的几个优化技术,使得在千卡 A800 显卡上达到了 7B 模型 182 TFLOPS 的吞吐,GPU 峰值算力利用率高达 58.3%
本次微调参考项目:https://github.com/wp931120/baichuan_sft_lora
由于baichuan没有 supervised finetune 这一步,没有和人类意图进行对齐,经常听不懂你下达的指令。该项目遂利用belle 0.5M 指令微调数据,采用qlora的量化微调的方式对百川大模型进行人类意图对齐训练
训练前置条件,先从huggingface 中将baichuan7b 大模型权重 ,然后,最后运行sft_lora.py 脚本
先将百川LLM 采用qlora的 nf4 和双重量化方式进行量化
在采用lora进行指令微调
本次微调baichuan-7B的步骤如下
git clone https://github.com/wp931120/baichuan_sft_lora.git
cd baichuan_sft_lora
配置环境 conda create -n baichuan-7b python=3.9
conda activate baichuan-7b
pip install -r requirements.txt
数据集下载import os # 导入os模块,这个模块提供了一种方便的使用操作系统依赖功能的方式
os.environ['CUDA_VISIBLE_DEVICES'] = '0' # 设置CUDA可见设备,'0'表示仅使用第一块GPU
from datasets import load_dataset # 导入load_dataset函数,用于加载数据集
import transformers # 导入transformers库,这是一个常用的NLP库
# 导入Trainer和TrainingArguments,分别用于模型的训练和训练参数的设置
from transformers import Trainer, TrainingArguments
# 导入AutoTokenizer和AutoModelForCausalLM,分别用于自动化地从预训练模型中获取Tokenizer和模型
from transformers import AutoTokenizer, AutoModelForCausalLM
# 导入BitsAndBytesConfig,用于设置模型的量化配置
from transformers import BitsAndBytesConfig
# 导入一些特定的函数和配置类
from peft import (
LoraConfig,
get_peft_model,
prepare_model_for_kbit_training,
set_peft_model_state_dict,
)
import torch # 导入PyTorch库,这是一个常用的深度学习库
# 定义一些配置信息
CUTOFF_LEN = 1024
VAL_SET_SIZE = 2000
DATA_PATH = "./dataset/Belle_open_source_0.5M.json"
OUTPUT_DIR = "baichuansft"
resume_from_checkpoint = "baichuansft"
# 设置设备映射,""表示默认设备,0表示设备编号
device_map = {"": 0}
# 使用AutoTokenizer从预训练模型中获取Tokenizer
tokenizer = AutoTokenizer.from_pretrained("./baichuan-7B",trust_remote_code=True)
# 使用AutoModelForCausalLM从预训练模型中获取模型,并设置量化配置
model = AutoModelForCausalLM.from_pretrained("./baichuan-7B",
trust_remote_code=True,
quantization_config=BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type='nf4'
),
device_map=device_map)
model = prepare_model_for_kbit_training(model) # 准备模型进行kbit训练
# 导入bitsandbytes模块
import bitsandbytes as bnb
# 定义一个函数,用于找到模型中所有的线性层的名称
def find_all_linear_names(model):
cls = bnb.nn.Linear4bit
lora_module_names = set()
for name, module in model.named_modules(): # 遍历模型中的所有模块
if isinstance(module, cls): # 如果模块是线性层
names = name.split('.')
lora_module_names.add(names[0] if len(names) == 1 else names[-1]) # 添加到线性层名称集合中
if 'lm_head' in lora_module_names: # 如果'lm_head'在名称集合中,需要移除
lora_module_names.remove('lm_head')
return list(lora_module_names) # 返回线性层名称列表
# 获取所有的线性层的名称
modules = find_all_linear_names(model)
# 设置LoRA配置
config = LoraConfig(
r=8,
lora_alpha=16,
lora_dropout=0.05,
bias="none",
target_modules=modules,
task_type="CAUSAL_LM",
)
# 获取用于训练的模型
model = get_peft_model(model, config)
tokenizer.pad_token_id = 0 # 设置tokenizer的pad_token_id为0
# 如果有设置从检查点恢复
if resume_from_checkpoint:
# 检查可用的权重并加载
checkpoint_name = os.path.join(
resume_from_checkpoint, "pytorch_model.bin"
) # 完整的检查点
# 如果完整的检查点不存在,则加载LoRA模型的检查点
if not os.path.exists(checkpoint_name):
checkpoint_name = os.path.join(
resume_from_checkpoint, "adapter_model.bin"
) # 仅LoRA模型 - 上面的LoRA配置必须匹配
resume_from_checkpoint = (
False # 所以训练器不会尝试加载状态
)
if os.path.exists(checkpoint_name):
print(f"Restarting from {checkpoint_name}")
adapters_weights = torch.load(checkpoint_name)
set_peft_model_state_dict(model, adapters_weights) # 设置模型的状态字典
else:
print(f"Checkpoint {checkpoint_name} not found")
# 加载数据集
data = load_dataset("json", data_files=DATA_PATH)
# 定义tokenize函数,用于将输入进行tokenize
def tokenize(prompt, add_eos_token=True):
# 这里是tokenize的具体操作
result = tokenizer(
prompt,
truncation=True,
max_length=CUTOFF_LEN,
padding=False,
return_tensors=None,
)
# 添加EOS token
if (
result["input_ids"][-1] != tokenizer.eos_token_id
and len(result["input_ids"]) < CUTOFF_LEN
and add_eos_token
):
result["input_ids"].append(tokenizer.eos_token_id)
result["attention_mask"].append(1)
if add_eos_token and len(result["input_ids"]) >= CUTOFF_LEN:
result["input_ids"][CUTOFF_LEN - 1] = tokenizer.eos_token_id
result["attention_mask"][CUTOFF_LEN - 1] = 1
# 输入和标签都是input_ids
result["labels"] = result["input_ids"].copy()
return result
# 定义generate_and_tokenize_prompt函数,用于生成并tokenize输入
def generate_and_tokenize_prompt(data_point):
instruction = data_point['instruction']
input_text = data_point["input"]
input_text = "Human: " + instruction + input_text + "\n\nAssistant: "
input_text = tokenizer.bos_token + input_text if tokenizer.bos_token != None else input_text
target_text = data_point["output"] + tokenizer.eos_token
full_prompt = input_text + target_text
tokenized_full_prompt = tokenize(full_prompt)
return tokenized_full_prompt
# 划分训练集和验证集,并进行shuffle和map操作
if VAL_SET_SIZE > 0:
train_val = data["train"].train_test_split(
test_size=VAL_SET_SIZE, shuffle=True, seed=42
)
train_data = train_val["train"].shuffle().map(generate_and_tokenize_prompt)
val_data = train_val["test"].shuffle().map(generate_and_tokenize_prompt)
else:
train_data = data['train'].shuffle().map(generate_and_tokenize_prompt)
val_data = None
# 创建Trainer对象,用于进行训练
trainer = Trainer(
model=model,
train_dataset=train_data,
eval_dataset=val_data,
args=TrainingArguments(
num_train_epochs=1,
per_device_train_batch_size=1,
per_device_eval_batch_size=1,
learning_rate=3e-4,
gradient_accumulation_steps=4,
evaluation_strategy="steps" if VAL_SET_SIZE > 0 else "no",
save_strategy="steps",
eval_steps=2000 if VAL_SET_SIZE > 0 else None,
save_steps=2000,
output_dir=OUTPUT_DIR,
report_to = "tensorboard",
save_total_limit=3,
load_best_model_at_end=True if VAL_SET_SIZE > 0 else False,
optim="adamw_torch"
),
data_collator=transformers.DataCollatorForSeq2Seq(tokenizer,
pad_to_multiple_of=8,
return_tensors="pt",
padding=True),
)
# 进行训练
trainer.train(resume_from_checkpoint=False)
# 保存预训练模型
model.save_pretrained(OUTPUT_DIR)
最终,显存占用为7G左右// 待更