[大模型]MiniCPM-2B-chat Lora Full 微调

news2024/11/24 9:39:20

MiniCPM-2B-chat 介绍

MiniCPM 是面壁智能与清华大学自然语言处理实验室共同开源的系列端侧大模型,主体语言模型 MiniCPM-2B 仅有 24亿(2.4B)的非词嵌入参数量。

经过 SFT 后,MiniCPM 在公开综合性评测集上,MiniCPM 与 Mistral-7B相近(中文、数学、代码能力更优),整体性能超越 Llama2-13B、MPT-30B、Falcon-40B 等模型。
经过 DPO 后,MiniCPM 在当前最接近用户体感的评测集 MTBench上,MiniCPM-2B 也超越了 Llama2-70B-Chat、Vicuna-33B、Mistral-7B-Instruct-v0.1、Zephyr-7B-alpha 等众多代表性开源大模型。
以 MiniCPM-2B 为基础构建端侧多模态大模型 MiniCPM-V,整体性能在同规模模型中实现最佳,超越基于 Phi-2 构建的现有多模态大模型,在部分评测集上达到与 9.6B Qwen-VL-Chat 相当甚至更好的性能。
经过 Int4 量化后,MiniCPM 可在手机上进行部署推理,流式输出速度略高于人类说话速度。MiniCPM-V 也直接跑通了多模态大模型在手机上的部署。
一张1080/2080可高效参数微调,一张3090/4090可全参数微调,一台机器可持续训练 MiniCPM,二次开发成本较低。

环境准备

在autodl平台中租一个单卡3090等24G显存的显卡机器,如下图所示镜像选择PyTorch–>2.1.0–>3.10(ubuntu22.04)–>12.1
接下来打开刚刚租用服务器的JupyterLab, 图像 并且打开其中的终端开始环境配置、模型下载和运行演示。

注意:这里要选择一个 cpuintel 的机器,amdcpu 有可能会导致 deepspeed zero2 offload加载失败。

在这里插入图片描述

接下来打开刚刚租用服务器的JupyterLab,并且打开其中的终端开始环境配置、模型下载和运行demo

pip换源和安装依赖包

# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

pip install modelscope transformers sentencepiece accelerate langchain

MAX_JOBS=8 pip install flash-attn --no-build-isolation

pip install peft deepspeed

注意:flash-attn 安装会比较慢,大概需要十几分钟。

模型下载

使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。

/root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py执行下载,模型大小为 10 GB,下载模型大概需要 5~10 分钟

import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('OpenBMB/MiniCPM-2B-sft-fp32', cache_dir='/root/autodl-tmp', revision='master')

数据集构建

LLM 的微调一般指指令微调过程。所谓指令微调,是说我们使用的微调数据形如:

{
    "instrution":"回答以下用户问题,仅输出答案。",
    "input":"1+1等于几?",
    "output":"2"
}

其中,instruction 是用户指令,告知模型其需要完成的任务;input 是用户输入,是完成用户指令所必须的输入内容;output 是模型应该给出的输出。

即我们的核心训练目标是让模型具有理解并遵循用户指令的能力。因此,在指令集构建时,我们应针对我们的目标任务,针对性构建任务指令集。例如,在本节我们使用由笔者合作开源的 Chat-甄嬛 项目作为示例,我们的目标是构建一个能够模拟甄嬛对话风格的个性化 LLM,因此我们构造的指令形如:

{
    "instruction": "现在你要扮演皇帝身边的女人--甄嬛",
    "input":"你是谁?",
    "output":"家父是大理寺少卿甄远道。"
}

我们所构造的全部指令数据集在根目录的dataset下。

数据格式化

Lora 训练的数据是需要经过格式化、编码之后再输入给模型进行训练的,如果是熟悉 Pytorch 模型训练流程的同学会知道,我们一般需要将输入文本编码为 input_ids,将输出文本编码为 labels,编码之后的结果都是多维的向量。我们首先定义一个预处理函数,这个函数用于对每一个样本,编码其输入、输出文本并返回一个编码后的字典:

def process_func(example):
    MAX_LENGTH = 512    # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer(f"<用户>{example['instruction']+example['input']}<AI>", add_special_tokens=False)  # add_special_tokens 不在开头加 special_tokens
    response = tokenizer(f"{example['output']}", add_special_tokens=False)
    input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
    attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1]  # 因为eos token咱们也是要关注的所以 补充为1
    labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]  
    if len(input_ids) > MAX_LENGTH:  # 做一个截断
        input_ids = input_ids[:MAX_LENGTH]
        attention_mask = attention_mask[:MAX_LENGTH]
        labels = labels[:MAX_LENGTH]
    return {
        "input_ids": input_ids,
        "attention_mask": attention_mask,
        "labels": labels
    }

MiniCPM 所使用的 Prompt_Templatetransformers默认的Prompt_Template,感兴趣的同学可以在transformers仓库查看源码构造哦~

加载模型

模型以半精度形式加载,如果你的显卡比较新的话,可以用torch.bfolat形式加载。对于自定义的模型一定要指定trust_remote_code参数为True

tokenizer = AutoTokenizer.from_pretrained('./OpenBMB/miniCPM-bf32', use_fast=False, trust_remote_code=True)
tokenizer.padding_side = 'right'
tokenizer.pad_token_id = tokenizer.eos_token_id

model = AutoModelForCausalLM.from_pretrained('./OpenBMB/miniCPM-bf32', trust_remote_code=True, torch_dtype=torch.half, device_map="auto")

定义LoraConfig

LoraConfig这个类中可以设置很多参数,但主要的参数没多少,简单讲一讲,感兴趣的同学可以直接看源码。

  • task_type:模型类型
  • target_modules:需要训练的模型层的名字,主要就是attention部分的层,不同的模型对应的层的名字不同,可以传入数组,也可以字符串,也可以正则表达式。
  • rlora的秩,具体可以看Lora原理
  • lora_alphaLora alaph,具体作用参见 Lora 原理
config = LoraConfig(
    task_type=TaskType.CAUSAL_LM, 
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    inference_mode=False, # 训练模式
    r=8, # Lora 秩
    lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
    lora_dropout=0.1# Dropout 比例
)

注意:如果要进行全量微调的话,可以在加载模型的时候选择不加载LoraConfig

自定义 TrainingArguments 参数

TrainingArguments这个类的源码也介绍了每个参数的具体作用,当然大家可以来自行探索,这里就简单说几个常用的。

  • output_dir:模型的输出路径
  • per_device_train_batch_size:顾名思义 batch_size
  • gradient_accumulation_steps: 梯度累加,如果你的显存比较小,那可以把 batch_size 设置小一点,梯度累加增大一些。
  • logging_steps:多少步,输出一次log
  • num_train_epochs:顾名思义 epoch

等等,还有很多参数可以调整,感兴趣的同学可以去看看transformers的源码哦,也欢迎各位同学来给本项目提交PR哦~

使用deepspeed训练

deepspeed 是一个分布式训练的工具,可以很方便的进行分布式训练,这里我们使用deepspeed进行训练。

  • 如果你要进行lora训练,那请在train.py中将67行代码的注释取消掉,然后运行train.sh脚本即可。

lora 训练大概需要14G显存左右,因为没有开梯度检查所以显存占用会多一点。

# 创建模型并以半精度形式加载
model = AutoModelForCausalLM.from_pretrained(finetune_args.model_path, trust_remote_code=True, torch_dtype=torch.half, device_map={"": int(os.environ.get("LOCAL_RANK") or 0)})

model = get_peft_model(model, config)
  • 全量训练直接运行train.sh脚本即可。

全量训练,大概需要22G显存左右,因为开启了deepspeed zero2 的 cpu offload 功能,优化器参数会加载到cpu上进行计算,所以降低了显存。

完整train.py源码

from datasets import Dataset
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, HfArgumentParser, Trainer
import os
import torch
from peft import LoraConfig, TaskType, get_peft_model
from dataclasses import dataclass, field
import deepspeed
deepspeed.ops.op_builder.CPUAdamBuilder().load()

@dataclass
class FinetuneArguments:
    # 微调参数
    # field:dataclass 函数,用于指定变量初始化
    model_path: str = field(default="./OpenBMB/miniCPM-bf32")

# 用于处理数据集的函数
def process_func(example):
    MAX_LENGTH = 512    # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer(f"<用户>{example['instruction']+example['input']}<AI>", add_special_tokens=False)  # add_special_tokens 不在开头加 special_tokens
    response = tokenizer(f"{example['output']}", add_special_tokens=False)
    input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
    attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1]  # 因为eos token咱们也是要关注的所以 补充为1
    labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]  
    if len(input_ids) > MAX_LENGTH:  # 做一个截断
        input_ids = input_ids[:MAX_LENGTH]
        attention_mask = attention_mask[:MAX_LENGTH]
        labels = labels[:MAX_LENGTH]
    return {
        "input_ids": input_ids,
        "attention_mask": attention_mask,
        "labels": labels
    }

 # loraConfig
config = LoraConfig(
    task_type=TaskType.CAUSAL_LM, 
    target_modules=["q_proj", "v_proj"],  # 这个不同的模型需要设置不同的参数,需要看模型中的attention层
    inference_mode=False, # 训练模式
    r=8, # Lora 秩
    lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
    lora_dropout=0.1# Dropout 比例
)


if "__main__" == __name__:
    # 解析参数
    # Parse 命令行参数
    finetune_args, training_args = HfArgumentParser(
        (FinetuneArguments, TrainingArguments)
    ).parse_args_into_dataclasses()

    # 处理数据集
    # 将JSON文件转换为CSV文件
    df = pd.read_json('./huanhuan.json')
    ds = Dataset.from_pandas(df)
    # 加载tokenizer
    tokenizer = AutoTokenizer.from_pretrained(finetune_args.model_path, use_fast=False, trust_remote_code=True)
    tokenizer.padding_side = 'right'
    tokenizer.pad_token_id = tokenizer.eos_token_id
    # 将数据集变化为token形式
    tokenized_id = ds.map(process_func, remove_columns=ds.column_names)

    # 创建模型并以半精度形式加载
    model = AutoModelForCausalLM.from_pretrained(finetune_args.model_path, trust_remote_code=True, torch_dtype=torch.half, device_map={"": int(os.environ.get("LOCAL_RANK") or 0)})
    # model = get_peft_model(model, config)
    # 使用trainer训练
    trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=tokenized_id,
        data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
        )
    trainer.train() # 开始训练
    trainer.save_model() # 保存模型

train.sh

num_gpus=1

deepspeed --num_gpus $num_gpus train.py \
    --deepspeed ./ds_config.json \
    --output_dir="./output/MiniCPM" \
    --per_device_train_batch_size=4 \
    --gradient_accumulation_steps=4 \
    --logging_steps=10 \
    --num_train_epochs=3 \
    --save_steps=500 \
    --learning_rate=1e-4 \
    --save_on_each_node=True \

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++题解】1469. 数的统计

问题&#xff1a;1469. 数的统计 类型&#xff1a;嵌套循环 题目描述&#xff1a; 试计算在区间 1 到 n 的所有整数中&#xff0c;数字 x ( 0≤x≤9 )共出现了多少次&#xff1f; 例如&#xff0c;在 1 到 11 中&#xff0c;即在 1,2,3,4,5,6,7,8,9,10,11 中&#xff0c;数字…

HCIA 10 网络安全之结合ACL访问控制列表登录Telnet及FTP

ACL 本质上是一种报文过滤器&#xff0c;规则是过滤器的滤芯。设备基于这些规则进行报文匹配&#xff0c;可以过滤出特定的报文&#xff0c;并根据应用 ACL 的业务模块的处理策略来允许或阻止该报文通过。 1.实验介绍及拓扑 R3 为telnet服务器&#xff0c;R1 为客户端&#…

简单的基于Transformer的滚动轴承故障诊断(Pytorch)

递归神经网络在很长一段时间内是序列转换任务的主导模型&#xff0c;其固有的序列本质阻碍了并行计算。因此&#xff0c;在2017年&#xff0c;谷歌的研究人员提出了一种新的用于序列转换任务的模型架构Transformer&#xff0c;它完全基于注意力机制建立输入与输出之间的全局依赖…

计算机图形学入门09:深度缓存

在前面知道了怎么将一个三角形显示到屏幕上&#xff0c;那么如果有很多三角形&#xff0c;各自距离相机的远近也不一样&#xff0c;并且三角形会相互遮挡。也就是三维空间中有很多物体&#xff0c;通常近处的物体会遮挡住远处的物体&#xff0c;那么在计算机渲染中该如何处理呢…

出现 Error creating bean with name xxx defined in class 的解决方法

目录 1. 问题所示2. 原理分析3. 解决方法4. Demo1. 问题所示 此类问题来自私信,本着探究问题的缘由,理性分析了下,让大家也学会分析Bug解决Bug 问题如下所示: Error creating bean with name xxx defined in class截图如下所示: 2. 原理分析 通用的原理进行分析 出现…

【C语言初阶】数组

&#x1f31f;博主主页&#xff1a;我是一只海绵派大星 &#x1f4da;专栏分类&#xff1a;C语言 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、一维数组的创建和初始化 1、数组的创建 1.1数组的创建方式 1.2数组创建的实例 2、数组的初始化 二、一维数组的使用…

vue.js+node.js+mysql在线聊天室源码

vue.jsnode.jsmysql在线聊天室源码 技术栈&#xff1a;vue.jsElement UInode.jssocket.iomysql vue.jsnode.jsmysql在线聊天室源码

word怎么单页横向设置(页码不连续版)

打开word&#xff0c;将光标放在第一页的最后位置。 然后点击布局下的分隔符&#xff0c;选择下一页。 将光标放在第二页的开头&#xff0c;点击布局下的纸张方向&#xff0c;选择横向即可。 效果展示。 PS&#xff1a;如果那一页夹在两页中间&#xff0c;那么在…

基于C#开发web网页管理系统模板流程-主界面密码维护功能完善

点击返回目录-> 基于C#开发web网页管理系统模板流程-总集篇-CSDN博客 前言 紧接上篇->基于C#开发web网页管理系统模板流程-主界面统计功能完善-CSDN博客 一个合格的管理系统&#xff0c;至少一定存在一个功能——用户能够自己修改密码&#xff0c;理论上来说密码只能有用…

上位机图像处理和嵌入式模块部署(h750 mcu串口命令处理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面学习103和407的时候&#xff0c;当时学过串口的收发。不过当时使用的主要是阻塞的方式。这一次&#xff0c;我们看下应该怎么利用中断的形式进…

互联网时代:挑战与机遇并存

随着科技的飞速发展和互联网的广泛普及&#xff0c;我们已然踏入了一个以信息为主导的互联网时代。这个时代以其鲜明的特点&#xff0c;正在深刻地改变着我们的生活方式、工作节奏以及社会交往模式。而如此深刻的社会变革&#xff0c;也引发了人们对于互联网时代所带来的挑战与…

计算机毕业三年的我,辞职两次后找不到工作回家,此时是真的羡慕有手艺在手的人

栀子花香&#xff0c;弥漫在空气中&#xff0c;却掩盖不了内心的苦涩。 半年&#xff0c;两份工作&#xff0c;两次裸辞&#xff0c;我&#xff0c;又成了一个身无分文的“废人”。 曾经&#xff0c;我也是人人羡慕的互联网人&#xff0c;月薪6K&#xff0c;过着“955”的“神…

【DevOps】Nginx配置文件详解与实战部署PHP站点

目录 引言 Nginx配置文件概述 基本结构 关键指令 Nginx配置文件实战 全局指令配置 HTTP指令配置 服务器指令配置 位置指令配置 实战部署PHP站点 步骤1&#xff1a;安装Nginx和PHP 步骤2&#xff1a;创建网站目录和文件 步骤3&#xff1a;配置Nginx服务器块 步骤4…

2024年金融、贸易与创意产业国际会议(ICFTCI 2024)

2024 International Conference on Financial Trade and Creative Industries 【1】大会信息 会议简称&#xff1a;ICFTCI 2024 大会地点&#xff1a;中国西安 投稿邮箱&#xff1a;icftcisub-paper.com 【2】会议简介 2024年金融贸易与创意产业国际会议即将召开&#xff…

果园预售系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;果树管理&#xff0c;果园管理&#xff0c;果园预约管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;论坛&#xff0c;公告&a…

王炸! Suno史诗级更新,随便哼哼就能出一首好听的歌曲?

suno史诗级更新&#xff0c;随便哼哼就能出一首好听的歌曲&#xff1f; 就在今天&#xff0c;suno迎来史诗级更新&#xff01; 先看截图&#xff01; 来不及解释&#xff0c;我先试了一下&#xff0c;简直太牛了&#xff0c;先看看看效果&#xff0c;点开链接听歌&#xff01; …

明星百科大全PHP网站源码

源码介绍 明星百科大全网站源码&#xff0c;国内外明星娱乐音乐、新闻八卦、写真照片、相关影视作品等等的明星百科网站源码。 源码截图 源码下载 明星百科大全PHP网站源码

day36| 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆

文章目录 前言860.柠檬水找零思路方法一 406.根据身高重建队列思路方法一 452. 用最少数量的箭引爆气球思路方法一 总结 前言 860.柠檬水找零 思路 很简单&#xff0c;贪心只有一个&#xff0c;如果20优先用105找零&#xff0c;因为5更加万能一些 方法一 class Solution(ob…

Python版本管理器-Miniconda

随着Python的版本更新&#xff0c;我们在开发Python软件的时候&#xff0c;对Python的版本选择越来越重要&#xff0c;但同时又要兼容已经开发好了的Python软件&#xff0c;因此选择一款合适的Python版本管理器对提高开发效率也越来越重要&#xff0c;今天就推荐一款Python的版…

登录/注册- 滑动拼图验证码(IOS/Swift)

本章介绍如何使用ios开发出滑动拼图验证码&#xff0c;分别OC代码和swift代码调用 1.导入项目model文件OC代码&#xff08;下载完整Demo&#xff09; 2.放入你需要显示的图片 一&#xff1a;OC调用 #import "ViewController.h" #import "CodeView.h"…