中文模型的奋起直追:MOSS、baichuan-7B和ChatGLM2-6B的部署与微调

第一部分 复旦MOSS

MOSS是复旦大学邱锡鹏团队推出的一个支持中英双语和多种插件的开源对话语言模型,moss-moon系列模型具有160亿参数,在FP16精度下可在单张A100/A800或两张3090显卡运行,在INT4/8精度下可在单张3090显卡运行。MOSS基座语言模型在约七千亿中英文以及代码单词上预训练得到,后续经过对话指令微调、插件增强学习和人类偏好训练具备多轮对话能力及使用多种插件的能力

5.1 已开源的模型/数据

5.1.1 已开源的模型

  • moss-moon-003-base: MOSS-003基座模型,在高质量中英文语料上自监督预训练得到,预训练语料包含约700B单词,计算量约6.67x1022次浮点数运算。
  • moss-moon-003-sft: 基座模型在约110万多轮对话数据上微调得到,具有指令遵循能力、多轮对话能力、规避有害请求能力。
  • moss-moon-003-sft-plugin: 基座模型在约110万多轮对话数据和约30万插件增强的多轮对话数据上微调得到,在moss-moon-003-sft基础上还具备使用搜索引擎、文生图、计算器、解方程等四种插件的能力。
  • moss-moon-003-sft-int4: 4bit量化版本的moss-moon-003-sft模型,约占用12GB显存即可进行推理。
  • moss-moon-003-sft-int8: 8bit量化版本的moss-moon-003-sft模型,约占用24GB显存即可进行推理。
  • moss-moon-003-sft-plugin-int4: 4bit量化版本的moss-moon-003-sft-plugin模型,约占用12GB显存即可进行推理。
  • moss-moon-003-sft-plugin-int8: 8bit量化版本的moss-moon-003-sft-plugin模型,约占用24GB显存即可进行推理。
  • moss-moon-003-pm: 在基于moss-moon-003-sft收集到的偏好反馈数据上训练得到的偏好模型,将在近期开源。
  • moss-moon-003: 在moss-moon-003-sft基础上经过偏好模型moss-moon-003-pm训练得到的最终模型,具备更好的事实性和安全性以及更稳定的回复质量,将在近期开源。
  • moss-moon-003-plugin: 在moss-moon-003-sft-plugin基础上经过偏好模型moss-moon-003-pm训练得到的最终模型,具备更强的意图理解能力和插件使用能力,将在近期开源。

5.1.2 已开源的数据

  • moss-002-sft-data: MOSS-002所使用的多轮对话数据,覆盖有用性、忠实性、无害性三个层面,包含由text-davinci-003生成的约57万条英文对话和59万条中文对话
  • moss-003-sft-data: moss-moon-003-sft所使用的多轮对话数据,基于MOSS-002内测阶段采集的约10万用户输入数据和gpt-3.5-turbo构造而成,相比moss-002-sft-datamoss-003-sft-data更加符合真实用户意图分布,包含更细粒度的有用性类别标记、更广泛的无害性数据和更长对话轮数,约含110万条对话数据。目前仅开源少量示例数据,完整数据将在近期开源
  • moss-003-sft-plugin-data: moss-moon-003-sft-plugin所使用的插件增强的多轮对话数据,包含支持搜索引擎、文生图、计算器、解方程等四个插件在内的约30万条多轮对话数据。目前仅开源少量示例数据,完整数据将在近期开源
  • moss-003-pm-datamoss-moon-003-pm所使用的偏好数据,包含在约18万额外对话上下文数据及使用moss-moon-003-sft所产生的回复数据上构造得到的偏好对比数据,将在近期开源

5.2 MOSS模型量化版部署过程

我司七月杜助教写了一篇部署MOSS的教程,详情请点击:MOSS模型量化版部署过程

  • 项目背景
  • 配置环境与准备
  • 部署推理
    • 命令行部署
      • 报错1
      • 报错2:
  • 使用免费试用的阿里云GPU部署
  • 在AutoDL平台上部署

第二部分 baichuan-7B:与LLaMA的结构相同且表现优秀可商用

2.1 基于Transformer/RoPE/RMSNorm/SwiGLU + 1.2万亿训练数据/上下文窗口4096

baichuan-7B 是由百川智能(CEO为原搜狗创始人王小川)开发的一个开源可商用的大规模预训练语言模型

  • 基于 Transformer 结构,采用了和 LLaMA 一样的模型设计,比如
    位置编码:用的现阶段被大多模型采用的 rotary-embedding 方案,具有更好的外延效果
    激活层:SwiGLU, Feedforward 变化为 8/3 倍的隐含层大小,即 11,008
    Layer-Normalization: 基于 RMSNorm 的 Pre-Normalization

    关于LLaMA结构的解读,请参见:类ChatGPT模型LLaMA的解读与其微调:Alpaca-LoRA/Vicuna/BELLE
  • 在大约 1.2 万亿 tokens 上训练的 70 亿参数模型,支持中英双语
  • 上下文窗口长度为 4096
  • 在标准的中文和英文权威 benchmark(C-EVAL/MMLU)上均取得同尺寸最好的效果
    具体而言,C-Eval 数据集是一个全面的中文基础模型评测数据集,涵盖了 52 个学科和四个难度的级别
    我们使用该数据集的 dev 集作为 few-shot 的来源,在 test 集上进行了 5-shot 测试
    除了中文之外,作者团队也测试了模型在英文上的效果,MMLU 是包含 57 个多选任务的英文评测数据集,涵盖了初等数学、美国历史、计算机科学、法律等,难度覆盖高中水平到专家水平,是目前主流的LLM评测数据集


    一句话总结,即是在C-EVAL/MMLU等数据集上的表现好于ChatGLM-6B (当然,ChatGLM2-6B又变更强了)

2.2 baichuan-7B相比LLaMA-7B的优势

虽然baichuan-7B采用了和LLaMA一样的模型设计,但他们在原本的 LLaMA 框架上进行诸多修改

比如为提升模型的效果以及解码效率,做了

  • 分词改进
    词表大小为64K ,而LLaMA词表大小为32K

    具体而言,参考学术界方案使用 SentencePiece 中的 Byte-Pair Encoding (BPE) 作为分词算法,并且进行了以下的优化:
    目前大部分开源模型主要基于英文优化,因此对中文语料存在效率较低的问题,使用 2000 万条以中英为主的多语言语料训练分词模型,显著提升对于中文的压缩率

    对于数学领域,我们参考了 LLaMA 和 Galactica 中的方案,对数字的每一位单独分开,避免出现数字不一致的问题,对于提升数学能力有重要帮助
    对于罕见字词(如特殊符号等),支持 UTF-8 characters 的 byte 编码,因此做到未知字词的全覆盖
  • 数据集改进
    使用了大约 1.2T 中英 tokens 进行训练(基于开源的中英文数据和自行抓取的中文互联网数据以及部分高质量知识性数据进行的数据清洗),而 LLaMA 7B 使用 1T 英文 tokens 进行训练

比如为提升训练时的吞吐,做了以下优化

  • 算子优化技术:采用更高效算子,如 Flash-Attention,NVIDIA apex 的 RMSNorm 等。
  • 算子切分技术:将部分计算算子进行切分,减小内存峰值。
  • 混合精度技术:降低在不损失模型精度的情况下加速计算过程。
  • 训练容灾技术:训练平台和训练框架联合优化,IaaS + PaaS 实现分钟级的故障定位和任务恢复。
  • 通信优化技术,具体包括:
    采用拓扑感知的集合通信算法,避免网络拥塞问题,提高通信效率
    根据卡数自适应设置 bucket size,提高带宽利用率
    根据模型和集群环境,调优通信原语的触发时机,从而将计算和通信重叠

基于上述的几个优化技术,使得在千卡 A800 显卡上达到了 7B 模型 182 TFLOPS 的吞吐,GPU 峰值算力利用率高达 58.3%

2.3 baichuan-7B的微调

本次微调参考项目: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的步骤如下

  1. 微调之前的准备
    下载项目仓库
    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
    数据集下载
    sft 数据集采用的是belle 0.5M
    下载地址:https://huggingface.co/datasets/BelleGroup/train_0.5M_CN/tree/main
    将 belle 数据集 train_0.5M_CN 下载到本地放到项目目录下的dataset文件夹下
  2. 将百川LLM 采用qlora的 nf4 和双重量化方式进行量化
  3. 再采用lora进行指令微调
    wp931120x/baichuan_4bit_lora · Hugging Face
  4. 修改并运行sft_lora.py文件
    将sft_lora.py中的模型路径设置为自己的模型路径
    执行python sft_lora.py运行代码
    import os  # 导入os模块,这个模块提供了一种方便的使用操作系统依赖功能的方式
    os.environ['CUDA_VISIBLE_DEVICES'] = '0'  # 设置CUDA可见设备,'0'表示仅使用第一块GPUfrom 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 tokenif (result["input_ids"][-1] != tokenizer.eos_token_idand len(result["input_ids"]) < CUTOFF_LENand 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_idresult["attention_mask"][CUTOFF_LEN - 1] = 1# 输入和标签都是input_idsresult["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_texttarget_text = data_point["output"] + tokenizer.eos_tokenfull_prompt = input_text + target_texttokenized_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左右

 第三部分 ChatGLM2-6B的部署与微调

// 待更

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

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

相关文章

vue页面中一个小列表中多选框的选中状态的两种设置方法

第一种方法:所有类型都是固定的、后台提供了选中状态的接口(页面进入时默认展示所有类型和类型的选中状态 思路: 1、列出所有类型同时与后台规定好每种类型的id与对应的名称 2、在mounted中执行获取后台给定的选中状态(包含1个或多个的id数组) 3、将得到的结构绑定到el-ch…

【JavaWeb基础】分层解耦

一、知识点整理 1、IOC与DI入门 1&#xff09;控制反转: Inversion 0f Control&#xff0c;简称I0C。对象的创建控制权由程序自身转移到外部(容器)&#xff0c;这种思想称为控制反转。 2&#xff09;依赖注入: Dependency lnjection&#xff0c;简称DI。容器为应用程序提供运…

Z-NTFS2EXCEL 文件服务器权限可视化报告

Z-NTFS2EXCEL Z-NTFS2EXCEL是一个用于快速获取Windows文件服务器权限信息并进行确认或审计的程序。 github地址&#xff1a;https://github.com/ericzhong2010/Z-NTFS2EXCEL 使用示例 编辑ini配置文件 执行exe程序文件 检查与确认结果 作者信息 作者&#xff1a;Eric…

Pycharm远程设置 DDP简单介绍

前言 最近接到一些改代码或者帮助debug的需求&#xff0c;大多数不是在本地而是autodl这种服务器上&#xff0c;有些人可能不太了解如何设置远程环境。通常在实验室一般都是在本地调好代码然后scp到服务器上去训练&#xff0c;不过这就需要本地有显卡能测试代码是否能跑通&…

Python自动化测试框架:unittest介绍

Unittest是Python中最常用的测试框架之一&#xff0c;它提供了丰富和强大的测试工具和方法&#xff0c;可以帮助开发者更好地保证代码质量和稳定性&#xff0c;本文就来介绍下Unittest单元测试框架 1. 介绍 unittest是Python的单元测试框架&#xff0c;它提供了一套丰富的测试…

Leetcode---352周赛

周赛题目 2760. 最长奇偶子数组 2761. 和等于目标值的质数对 2762. 不间断子数组 2763. 所有子数组中不平衡数字之和 一、最长奇偶子数组 这题的数据范围允许用暴力来做&#xff0c;只要我们分别枚举左端点left和右端点right&#xff0c;然后看区间[left,right]是否符合题目条…

flutter3.7版本下使用flutter boost解决使用platview崩溃或异常问题

背景 工程使用了混合开发&#xff0c;使用flutter boost插件&#xff0c;flutter 的activity1 frament1 跳转activity2 frament2&#xff0c;frament1 包含platformView&#xff0c;按照上面老哥解决崩溃问题的基础上&#xff0c;出现activity2 frament2返回activity1 framen…

golang 协程的实现原理

核心概念 要理解协程的实现, 首先需要了解go中的三个非常重要的概念, 它们分别是G, M和P, 没有看过golang源代码的可能会对它们感到陌生, 这三项是协程最主要的组成部分, 它们在golang的源代码中无处不在. G (goroutine) G是goroutine的头文字, goroutine可以解释为受管理的…

C++图形开发(6):落下后能弹起的小球

文章目录 1.重复下落的小球2.落下后能弹起的小球3.能上下反弹的小球4.符合重力的能上下反弹的小球 今天我们来尝试实现一个落地后可以弹起的小球 1.重复下落的小球 首先&#xff0c;我们要来实现一个小球的重复下落 我们知道&#xff0c;在前面的代码中&#xff08;详见C图形…

ChatGPT与Excel结合_编写VBA宏

先来解释下什么是Excel vba宏 ⭐Excel VBA宏&#xff08;Visual Basic for Applications&#xff09;是一种用于在Microsoft Excel中自动化和扩展功能的编程语言。VBA允许用户编写自定义的脚本或宏&#xff0c;以便通过执行一系列指令来自动完成特定任务。 使用Excel VBA宏&a…

基于改进莱维飞行和混沌映射的金鹰优化算法(10种混沌映射随意切换),附matlab代码

“ 本篇文章对金鹰优化算法进行改进&#xff0c;首先通过引入混沌映射机制&#xff0c;对其群体进行初始化&#xff0c;增加金鹰个体的多样性&#xff1b;然后在金鹰个体的位置更新公式上引入改进的莱维飞行机制&#xff0c;提高搜索精度&#xff0c;帮助金鹰个体跳出局部最优。…

Work20230705

//main.c #include "uart4.h" extern void printf(const char *fmt, ...); void delay_ms(int ms) {int i,j;for(i 0; i < ms;i)for (j 0; j < 1800; j); }int main() {while(1){//将获取到的字符1发送到终端//hal_put_char(hal_get_char()1);hal_put_string…