大模型微调---qwen实战

news2024/11/17 2:57:19

一、Qwen大模型的介绍

Qwen是阿里云开发的大语言模型,整个qwen系列的模型,由base模型、rm模型、chat模型、code模型、math模型等等。
[图片]

qwen采用chatml样式的格式来进行模型训练,chatml格式可以时模型有效区分各类信息,可以增强模型对复杂会话的处理分析能力。chatml的核心要素:

  • 消息(message):对话交互的基本单元,由角色和内容组成
  • 角色(Role):消息的发送方,可以是人(human)或者助手(assistant)
  • 内容(content):消息的具体内容,以markdown格式表示
  • 会话(conversation):由一系列消息构成的完整对话过程。
    在这里插入图片描述

大语言模型的训练过程包括:预训练阶段、监督训练阶段、RM奖励阶段、RL阶段。
预训练阶段
预训练数据集共3T,预训练权重数据主要涉及公共网络文档、百科全书、书籍、代码等,数据涉及多语言,以中文和英文为主。Qwen遵循自回归语言建模的标准方法(大模型的预训练阶段通常采用一种称为"自监督学习"的技术,例如掩码语言模型或者因果语言模型。掩码语言模型会将句子中某些词语遮挡住,然后让模型根据上下文预测这些被遮挡的词语;而因果语言模型则会让模型根据前面的词语预测下一个词语),通过前面Token的内容预测下一个Token。
预训练的目的是让模型学习通用的语言知识,使其成为一个优秀的语言编码器。然而,预训练模型通常缺乏针对特定任务或领域的知识。为了解决这个问题,我们需要进行下一步:微调。
SFT监督阶段
SFT是监督微调(Supervised Fine-Tun-ing)的缩写。相对于预训练的无监督微调,监督微调首先需要大量的标注数据用于目标任务的微调,如果标注数据不足,可能会导致微调后的模型表现不佳。其次,由于预训练模型的参数和结构对微调后的模型性能有很大的影响,因此,选择合适的预训练模型很重要。其中,微调方法中常见的是lora,本章也以lora微调方法作为实战演练。
RM奖励阶段
在大语言模型完成SFT监督微调后,下一阶段是构建一个奖励模型来对问答作出得分评价。奖励模型源于强化学习中的奖励函数,能对当前的状态刻画了一个分数,来说明这个状态产生的价值有多少。在大语言模型微调中的奖励模型是对输入的问题和答案计算出一个分数。输入的答案与问题匹配度越高,则奖励模型输出的分数也越高。
奖励模型(RM模型)讲SFT模型最后一层的softmax去掉,即最后一层不用softmax,改成一个线性层。RM模型的输入是问题和安安,输出是一个标量即分数。
奖励模型的训练数据是人工对问题的每个答案进行排名,如下图所示:
在这里插入图片描述

对于每个问题,给出若干答案,然后工人进行排序,而奖励模型就是利用排序的结果来进行反向传播。奖励模型的损失函数采用 Pairwise Ranking Loss(目标是使得排序高的答案yw对应的标量分数要高于排序低的答案y1对应的标量分数,且越高越好)
总之,奖励模型通过人类进行交互,获得对于生成响应质量的反馈信息,从而进一步提升大模型的生成能力和自然度。与监督模型不同的是,奖励模型通过打分的形式使得生成的文本更加自然逼真,让大模型的生成能力更进一步。
RL模型阶段
大语言模型完成奖励模型的训练后,下一个阶段是训练强化学习模型(RL模型),也是最后一个阶段。大语言模型微调中训练RL模型采用的优化算法是PPO(Proximal Policy Optimization,近端策略优化)算法,即对设定的目标函数通过随机梯度下降进行优化。近端策略优化是一种深度强化学习算法,用于训练智能体在复杂环境中学习和执行任务。通过智能体的训练,使得其在与环境的交互中能够最大化累积汇报,从而达成指定任务目标。这里的智能体在大模型中指的是就是RL模型
通过强化学习的训练方法,迭代式的更新奖励模型(RW 模型)以及策略模型(RL 模型),让奖励模型对模型输出质量的刻画愈加精确,策略模型的输出则愈能与初始模型拉开差距,使得输出文本变得越来越符合人的认知。这种训练方法也叫做 RLHF。

二、基于lora的qwen微调实战

1. 配置环境

本案例测试于modelscope1.14.0、transformers4.41.2、datasets2.18.0、peft0.11.1、accelerate0.30.1、swanlab0.3.11,配置环境的命令如下:

conda create --name Qwen2 python=3.8
conda activate Qwen2
pip install swanlab modelscope==1.14.0 transformers==4.41.2 datasets==2.18.0 peft==0.11.1 pandas accelerate==0.30.1
  1. 数据集下载
    本案例使用zh_cls_fudan-news数据集,该数据集主要被用于训练文本分类模型。
    zh_cls_fudan-news由几千条数据,每条数据包含text、category、output三列:
  • text 是训练语料,内容是书籍或新闻的文本内容
  • category 是text的多个备选类型组成的列表
  • output 则是text唯一真实的类型
    [图片]

数据集的下载网址:zh_cls_fudan-news,下载代码如下:

from modelscope import MsDataset
dataset = MsDataset.load('huangjintao/zh_cls_fudan-news', split='train')
test_dataset = MsDataset.load('huangjintao/zh_cls_fudan-news', subset_name='test', split='test')
print(dataset)
print(test_dataset)
  1. 完整的训练代码
import json
import pandas as pd
import torch
from datasets import Dataset
from modelscope import snapshot_download, AutoTokenizer
from swanlab.integration.huggingface import SwanLabCallback
from peft import LoraConfig, TaskType, get_peft_model
from transformers import AutoModelForCausalLM, TrainingArguments, Trainer, DataCollatorForSeq2Seq
import os
import swanlab

def dataset_jsonl_transfer(origin_path, new_path):
    """
    将原始数据集转换为大模型微调所需数据格式的新数据集
    """
    messages = []
    # 读取旧的JSONL文件
    with open(origin_path, "r") as file:
        for line in file:
            # 解析每一行的json数据
            data = json.loads(line)
            context = data["text"]
            catagory = data["category"]
            label = data["output"]
            message = {
                # "instruction": 用于告诉模型它将扮演的角色
                # "input": 用户输入的文本
                # "output": 模型输出的文本标签
                "instruction": "你是一个文本分类领域的专家,你会接收到一段文本和几个潜在的分类选项,请输出文本内容的正确类型",
                "input": f"文本:{context},类型选型:{catagory}",
                "output": label,
            }
            messages.append(message)

    # 保存重构后的JSONL文件
    with open(new_path, "w", encoding="utf-8") as file:
        for message in messages:
            file.write(json.dumps(message, ensure_ascii=False) + "\n")
            
            
def process_func(example):
    """
    将数据集进行预处理
    """
    # 设置最大序列长度:MAX_LENGTH = 384 限制了模型输入序列的最大长度
    MAX_LENGTH = 384 
    # 初始化ID列表:初始化三个列表input_ids, attention_mask, labels,分别用于存放模型所需的输入Token ID、注意力掩码以及标签(输出Token ID)。
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer(
        f"<|im_start|>system\n你是一个文本分类领域的专家,你会接收到一段文本和几个潜在的分类选项,请输出文本内容的正确类型<|im_end|>\n<|im_start|>user\n{example['input']}<|im_end|>\n<|im_start|>assistant\n",
        add_special_tokens=False,
    )
    response = tokenizer(f"{example['output']}", add_special_tokens=False)
    # input_ids: 将分词后的指令(instruction)和响应(response)的input_ids合并,并在末尾添加一个填充标记,以此构造完整的输入序列
    # attention_mask: 用来指示哪些tokens应当被模型关注(值为1的部分),哪些应当被忽略(值为0的部分)
    # 在自然语言处理领域,文本数据需要被转换成模型可以理解的数字形式---也就是数字序列。这些数字是词汇表中的索引。
    # 当一个文本处理器(如tokenizer)处理一段文本时,它会将文中的单词、字符或子词映射到一个唯一的数字ID,这个过程为"令牌化"。
    # 词汇表是模型训练之初,基于训练数据建立的,每个不同的词,标点符号、特殊字符等都有一个对应的ID。
    # input_ids数组或列表中的每一个数字代表原文本中的一个token(可能是词、子词或其他单位)在词汇表中的位置。这样做不仅使得文本可以被编码为神经网络可以运算的形式,还方便了模型理解和生成文本。

    # 至于attention_mask,它的作用在于帮助模型区分有效输入(即实际的文本内容)与填充内容(pad tokens)。模型在计算自注意力或交互时,会利用attention_mask来确定哪些部分需要关注(通常值为1),哪些部分(比如为了对齐长度而填充的tokens)应该被忽略(通常值为0)。
    input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
    attention_mask = (
        instruction["attention_mask"] + response["attention_mask"] + [1]
    )
    # 对于labels,则用-100标记源序列的token(因为这些不是预测的目标,而是已知的输入),然后跟上响应序列的真实token ID,最后也是填充标记。
    labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
    print(len(instruction["input_ids"]))
    # exit()
    #如果构建好的input_ids长度超过MAX_LENGTH,则会进行截断操作。
    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}   

def predict(messages, model, tokenizer):
    device = "cuda"
    text = tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True
    )
    model_inputs = tokenizer([text], return_tensors="pt").to(device)

    generated_ids = model.generate(
        model_inputs.input_ids,
        max_new_tokens=512
    )
    generated_ids = [
        output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
    ]
    
    response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
    
    print(response)
     
    return response
    

# 在modelscope上下载Qwen模型到本地目录下
model_dir = snapshot_download("qwen/Qwen2-1.5B-Instruct", cache_dir="./", revision="master")

# Transformers加载模型权重
tokenizer = AutoTokenizer.from_pretrained("./qwen/Qwen2-1___5B-Instruct/", use_fast=False, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained("./qwen/Qwen2-1___5B-Instruct/", device_map="auto", torch_dtype=torch.bfloat16)
model.enable_input_require_grads()  # 开启梯度检查点时,要执行该方法

# 加载、处理数据集和测试集
train_dataset_path = "zh_cls_fudan-news/train.jsonl"
test_dataset_path = "zh_cls_fudan-news/test.jsonl"

train_jsonl_new_path = "new_train.jsonl"
test_jsonl_new_path = "new_test.jsonl"

if not os.path.exists(train_jsonl_new_path):
    dataset_jsonl_transfer(train_dataset_path, train_jsonl_new_path)
if not os.path.exists(test_jsonl_new_path):
    dataset_jsonl_transfer(test_dataset_path, test_jsonl_new_path)

# 得到训练集
train_df = pd.read_json(train_jsonl_new_path, lines=True)
train_ds = Dataset.from_pandas(train_df)
train_dataset = train_ds.map(process_func, remove_columns=train_ds.column_names)

config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
    inference_mode=False,  # 训练模式
    r=8,  # Lora 秩
    lora_alpha=32,  # Lora alaph,具体作用参见 Lora 原理
    lora_dropout=0.1,  # Dropout 比例
)

model = get_peft_model(model, config)

args = TrainingArguments(
    output_dir="./output/Qwen2_0.5",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    logging_steps=10,
    num_train_epochs=20,
    save_steps=100,
    learning_rate=1e-4,
    save_on_each_node=True,
    gradient_checkpointing=True,
    report_to="none",
)

swanlab_callback = SwanLabCallback(
    project="Qwen2-fintune",
    experiment_name="Qwen2-0.5B-Instruct",
    description="使用通义千问Qwen2-0.5B-Instruct模型在zh_cls_fudan-news数据集上微调。",
    config={
        "model": "qwen/Qwen2-0.5B-Instruct",
        "dataset": "huangjintao/zh_cls_fudan-news",
    }
)

trainer = Trainer(
    model=model,
    args=args,
    train_dataset=train_dataset,
    data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
    callbacks=[swanlab_callback],
)

trainer.train()

# 用测试集的前10条,测试模型
test_df = pd.read_json(test_jsonl_new_path, lines=True)[:10]

test_text_list = []
for index, row in test_df.iterrows():
    instruction = row['instruction']
    input_value = row['input']
    
    messages = [
        {"role": "system", "content": f"{instruction}"},
        {"role": "user", "content": f"{input_value}"}
    ]

    response = predict(messages, model, tokenizer)
    messages.append({"role": "assistant", "content": f"{response}"})
    result_text = f"{messages[0]}\n\n{messages[1]}\n\n{messages[2]}"
    test_text_list.append(swanlab.Text(result_text, caption=response))
    
swanlab.log({"Prediction": test_text_list})
swanlab.finish()

当运行上面代码出现“段错误”,重新运行即可。
如果你是第一次使用SwanLab,那么还需要去swanlab.cn上注册一个账号,在用户设置页面复制你的API Key,然后在训练开始时粘贴进去即可

4.推理代码

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

def predict(messages, model, tokenizer):
    device = "cuda"

    text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
    model_inputs = tokenizer([text], return_tensors="pt").to(device)

    generated_ids = model.generate(model_inputs.input_ids, max_new_tokens=512)
    generated_ids = [output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)]
    response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]

    return response

# 加载原下载路径的tokenizer和model
tokenizer = AutoTokenizer.from_pretrained("./qwen/Qwen2-1___5B-Instruct/", use_fast=False, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained("./qwen/Qwen2-1___5B-Instruct/", device_map="auto", torch_dtype=torch.bfloat16)

# 加载训练好的Lora模型,将下面的checkpointXXX替换为实际的checkpoint文件名名称
model = PeftModel.from_pretrained(model, model_id="./output/Qwen2/checkpointXXX")

test_texts = {
    'instruction': "你是一个文本分类领域的专家,你会接收到一段文本和几个潜在的分类选项,请输出文本内容的正确类型",
    'input': "文本:航空动力学报JOURNAL OF AEROSPACE POWER1998年 第4期 No.4 1998科技期刊管路系统敷设的并行工程模型研究*陈志英* * 马 枚北京航空航天大学【摘要】 提出了一种应用于并行工程模型转换研究的标号法,该法是将现行串行设计过程(As-is)转换为并行设计过程(To-be)。本文应用该法将发动机外部管路系统敷设过程模型进行了串并行转换,应用并行工程过程重构的手段,得到了管路敷设并行过程模型。"
}

instruction = test_texts['instruction']
input_value = test_texts['input']

messages = [
    {"role": "system", "content": f"{instruction}"},
    {"role": "user", "content": f"{input_value}"}
]

response = predict(messages, model, tokenizer)
print(response)

参考链接:
https://zhuanlan.zhihu.com/p/644174810
https://zhuanlan.zhihu.com/p/642281542
https://blog.csdn.net/CSDN_224022/article/details/141193636

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

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

相关文章

blender插件库

插件安装教程&#xff1a;blender4.2中安装插件的方式-CSDN博客 blender官网插件库地址&#xff1a;Add-ons — Blender Extensions 1&#xff0c;ExtraObjects&#xff1a;提供更多网格形状&#xff0c; 链接:https://caiyun.139.com/m/i?2gov6Lw5RAib8 提取码:0ayj 复制内…

有向图的转置:算法分析与实现

有向图的转置:算法分析与实现 前言1. 邻接链表表示法2. 邻接矩阵表示法结论前言 在计算机科学中,图是一种非常重要的数据结构,用于表示对象之间的复杂关系。有向图(Directed Graph)是一种图,其边具有方向性。有向图的转置(Transpose)是一种基本操作,它将图中所有边的…

LLM面经(持续更新中)

Tokenizer Norm Batch Norm 好处 使得模型训练收敛的速度更快 每层的数据分布都不一样的话(解决Internal Covariance Shift)&#xff0c;将会导致网络非常难收敛和训练&#xff0c;而如果把每层的数据都在转换在均值为零&#xff0c;方差为1的状态下&#xff0c;这样每层数据…

第一个golang项目

第一个golang项目 开发环境安装golangVisual Studio Code安装golang语言插件初始化项目创建目录初始化golang配置 开始开发安装所需依赖创建main.go创建配置文件创建命令版本命令查看指定目录指定后缀文件并将指定内容替换为新内容 打包并运行 前因后果&#xff1a;因为工作需要…

不可错过的10款电脑监控软件推荐,电脑监控软件哪个好?宝藏安利

电脑监控软件已成为企业管理和家庭安全的重要工具。 无论是为了提升工作效率、保障信息安全&#xff0c;还是为了监督孩子的学习情况&#xff0c;一款优秀的电脑监控软件都能发挥巨大作用。 本文将为您推荐10款不可错过的电脑监控软件&#xff0c;并详细分析它们的优势与特点&…

Elastic Stack(三):Logstash介绍及安装

目录 1 Logstash介绍1.1 组件介绍1.2 Logstash 工作原理 2 Logstash安装2.1 logstash-源码包安装8.1.01、logstash安装2、创建配置文件3、启动4、配置快速启动文件 1 Logstash介绍 1.1 组件介绍 Logstash是一个开源数据收集引擎&#xff0c;具有实时管道功能。Logstash可以动…

财富趋势金融大模型已通过备案

财富趋势金融大模型已通过备案 8月28日晚&#xff0c;国内领先的证券软件与信息服务提供商——财富趋势&#xff0c;公布了其2024年上半年财务报告&#xff1a; 今年上半年&#xff0c;财富趋势营收1.48亿元&#xff0c;同比增长0.14%&#xff1b;实现归母净利润为1亿元&#x…

适用于 Windows 的文件恢复软件

我很遗憾我在 Windows中从 PC 中删除了数据并再次移动了它们。当我检查时&#xff0c;什么都没有。是否有任何 Windows 数据恢复软件&#xff0c;或者是否可以想象&#xff1f;我会看到任何援助的价值。 文档、图像、音频等数据文件可能会因意外删除、感染攻击、系统崩溃等不良…

mac os系统

各种各样的系统优缺点-CSDN博客 目录 一&#xff1a;mac os是什么系统&#xff1f;图形用户界面的革命性操作系统 二&#xff1a;mac os是什么系统&#xff1a;高性能和无缝衔接&#xff0c;功能丰富、安全可靠 三&#xff1a;mac os是什么系统&#xff1a;全新界面设计和卓…

Tomcat 环境配置及部署Web项目

一.环境 Java Tomcat 二.Java环境 1.下载安装JDK 2.修改及新建环境变量 3.查看Java 版本 三.Tomcat 环境 1.下载及解压Tomcat 2.配置环境变量 3.验证安装,运行startup.bat 访问&#xff1a;http://localhost:8080/ 三.Web项目 1.修改Tomcat配置文件 2.拷贝W…

Python将Latex公式插入到Word中

推荐一个库&#xff0c;可以使用python将Latex公式插入到Word中显示 使用pip进行安装: pip install latex2word 示例将如下公式插入到word 公式1&#xff1a; f(x) \int_{-\infty}^\infty \hat f(x)\xi\,e^{2 \pi i \xi x} \,\mathrm{d}\xi 公式2&#xff1a; \int x^{\mu}…

重生奇迹MU 小清新职业智弓MM

游戏中有一种令人迷醉的职业——智弓MM&#xff0c;她们以高超的射箭技能闻名于世。本文将为您介绍这个悠闲的小清新职业&#xff0c;在游戏中的特点以及如何成为一名出色的智弓MM。跟随我们一起探索这个奇妙而神秘的职业吧&#xff01; 悠闲的游戏节奏是游戏的初衷之一&#…

Dataease1.8.23 local本地安装

1、安装视频 手把手带你安装DataEase&#xff08;一&#xff09;Local模式部署 DataEase 免费开源BI工具 开源数据可视化分析工具 2、图文 安装模式 - DataEase 文档 注意点&#xff1a; 1、数据库&#xff1a;mysql 1&#xff09;my.cnf 新增配置&#xff1a; #忽略大小…

35岁以上程序员转行AI绘画领域:以Stablediffusion和Midjourney为舟,扬帆起航

前言 在技术浪潮的推动下&#xff0c;35岁的程序员面临职业转型的十字路口。AI绘画领域&#xff0c;以其独特的艺术创新和技术融合&#xff0c;为中年程序员提供了一个全新的舞台。利用AI工具如Stablediffusion和Midjourney&#xff0c;35岁以上的程序员可以在这个领域实现自我…

第二证券:三折折叠屏手机呼之欲出,14股业绩暴涨超200%

智能制作龙头大手笔投建机器人超级工厂 8月29日晚间&#xff0c;埃夫特发布公告称&#xff0c;公司拟运用自有或自筹资金在安徽省芜湖市经过购买土地用于出资制作埃夫特机器人超级工厂暨全球总部项目&#xff0c;根据初步测算&#xff0c;项目出资金额约人民币18.93亿元&#…

CAD二次开发IFoxCAD框架系列(25)- 自动加载和初始化的使用

自动加载&#xff0c;意思就是我们不需要每次重启都得要去输入netload加载软件&#xff0c;这个我们该怎么解决&#xff0c;CAD给我们提供了注册表的方式来进行加载&#xff0c;IFoxCAD给我们提供了非常便捷的操作注册表的方法。 namespace ifoxgse.Core.System;public static…

【算法】带你快速搞懂 二分查找算法问题(图解+练习)

目录 ❤️一&#xff1a;二分查找分析简介❤️ ❤️二&#xff1a;二分查找代码实现❤️ ​编辑 ❤️三&#xff1a;二分查找代码分析图解❤️ ❤️四&#xff1a;解决二分查找相关题型❤️ &#x1f495;4.1&#xff1a;二分查找题型一&#x1f495; &#x1f495;4.2&a…

java文件操作和IO流(详解)(๑•́ ₃ •̀๑)エー

目录 &#x1f604;一.认识文件 1.1文件的概念与组成&#xff1a; 1.2树形结构组织与目录&#xff1a; 1.3文件路径: &#x1f61a;二.文件系统操作 2.1File类概述&#xff1a; 2.2案例演示&#xff1a; 案例演示一&#xff1a; 演示案例二&#xff1a; &#x1f92a;…

【Python系列】signal信号处理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Unix 系统

各种各样的系统优缺点-CSDN博客 目录 █ 操作系统的诞生 █ UNIX的诞生 █ Linux的诞生 █ Linux和Unix的关系 █ Linux的发行版 说到操作系统&#xff0c;大家都不会陌生。我们天天都在接触操作系统——用台式机或笔记本电脑&#xff0c;使用的是windows和macOS系统&…