lora微调模版

lora微调模版

1、版一:使用peft包的lora微调

感谢:github:LLM-Tuning ,该项目集成了internLM、百川、chinese-llama-alpaca-2、chatglm的lora微调。

from transformers.integrations import TensorBoardCallback
from torch.utils.tensorboard import SummaryWriter
from transformers import TrainingArguments
from transformers import Trainer, HfArgumentParser
from transformers import AutoTokenizer, AutoModel, AutoConfig, DataCollatorForLanguageModeling
from accelerate import init_empty_weights
import torch
import torch.nn as nn
from peft import get_peft_model, LoraConfig, TaskType, PeftModel
from dataclasses import dataclass, field
import datasets
import os
from pprint import pprint as print

(1)设置超参

方式一:代码中设置(便于debug)

@dataclass
class FinetuneArguments:
    model_version: str = field(default="chat-7b")
    tokenized_dataset: str = field(default=" ")  # todo tokenized之后的数据集文件夹。每个模型是不一样的,不可混用!
    # tokenized_train_dataset: str = field(default=" ") # tokenized之后的数据集文件夹
    # tokenized_eval_dataset: str = field(default=" ") # tokenized之后的数据集文件夹
    train_size: int = field(default=1000)  # train size
    eval_size: int = field(default=1000)  # train size
    model_path: str = field(default=" ")
    lora_rank: int = field(default=8)
    previous_lora_weights: str = field(default=None)  # 如果要在前面的 LoRA 上继续训练,就设置一下之前的地址
    no_prompt_loss: int = field(default=0)  # 默认 prompt 参与loss计算

training_args = TrainingArguments(
        per_device_train_batch_size=10,
        gradient_accumulation_steps=1,
        warmup_steps=10,  # number of warmup steps for learning rate scheduler
        max_steps=60000,
        save_steps=200,
        save_total_limit=3,
        learning_rate=float(1e-4),
        remove_unused_columns=False,
        logging_steps=50,
        weight_decay=0.01,  # strength of weight decay
        # output_dir='weights/chatglm2-lora-tuning'
        output_dir='weights/chatglm2-lora-tuning-test'
    )
finetune_args = FinetuneArguments(tokenized_dataset="simple_math_4op_chatglm3", lora_rank=8)

方式二: .sh文件指定

如果喜欢用.sh文件启动,以上参数也可以不用在代码中配置,直接写在xx.sh文件:

CUDA_VISIBLE_DEVICES=2,3 python your_main.py
–tokenized_dataset simple_math_4op
–lora_rank 8
–per_device_train_batch_size 10
–gradient_accumulation_steps 1
–max_steps 100000
–save_steps 200
–save_total_limit 2
–learning_rate 1e-4
–fp16
–remove_unused_columns false
–logging_steps 50
–output_dir weights/simple_math_4op
对应代码:

finetune_args, training_args = HfArgumentParser((FinetuneArguments, TrainingArguments)).parse_args_into_dataclasses()

(2)加载数据集

# load dataset
# 加载数据集
dataset = datasets.load_from_disk('data/tokenized_data/' + finetune_args.tokenized_dataset)
# dataset = dataset.select(range(10000))
print(f"\n{len(dataset)=}\n")

# 训练、评估集各取N条
train_dataset = dataset.select(range(finetune_args.train_size)) if  finetune_args.train_size else dataset   # 取前 N 条训练
eval_dataset = dataset.select(list(range(len(dataset)))[-finetune_args.eval_size:])  if  finetune_args.eval_size else dataset   # 取后 N 条验证
# print(train_dataset[0])
# print(eval_dataset[0])

说明:datasets.load_from_disk( tokenized_data_path)加载的是已经tokenized后的数据。执行tokenize_dataset_rows.py即可完成原始数据到tokenized_data转变。

I、对应的.jsonl或json文件, 原始格式为:

{
“instruction”: "Instruction: What are the three primary colors?\nAnswer: ",
“output”: “The three primary colors are red, blue, and yellow.”
}

{
“instruction”: “Instruction: Identify the odd one out from the following array of words.”,
“input”: Fever, shiver, wrinkle\nAnswer: ",
“output”: “Wrinkle is the odd one out since it is the only word that does not describe a physical sensation.”
}

II、tokenize需要的文件格式:

{“context”: "Instruction: What are the three primary colors?\nAnswer: ", “target”: “The three primary colors are red, blue, and yellow.”}

{"context": "Instruction: Identify the odd one out from the following array of words.\nInput: Fever, shiver, wrinkle\nAnswer: ", “target”: “Wrinkle is the odd one out since it is the only word that does not describe a physical sensation.”}

tokenize_dataset_rows.py

import argparse
import json
from tqdm import tqdm
import datasets
import transformers
from transformers import AutoTokenizer, LlamaTokenizer

# 基础模型地址
# model_path = "D:\\openmodel1\\chatglm3-6b"
model_path = "D:\\openmodel1\\internlm-chat-7b"  

parser = argparse.ArgumentParser()
parser.add_argument("--data_path", type=str, help="原始数据地址")
parser.add_argument("--model_checkpoint", type=str, help="checkpoint, like `THUDM/chatglm-6b`", default=model_path)
parser.add_argument("--input_file", type=str, help="tokenize需要的数据文件地址,文件中每一行都是json格式,包含一个输出和一个输出",
                    default="alpaca_data-cf.jsonl")
parser.add_argument("--prompt_key", type=str, default=f"context", help="你的jsonl文件里,Instruction 的输入字段是什么")
parser.add_argument("--target_key", type=str, default=f"target", help="你的jsonl文件里,Instruction 的输出字段是什么")
parser.add_argument("--save_name", type=str, default=f"simple_math_4op_internlm", help="经过tokenize之后的数据集的存放位置")
parser.add_argument("--max_seq_length", type=int, default=2000)
parser.add_argument("--skip_overlength", type=bool, default=False)
args = parser.parse_args()
model_checkpoint = args.model_checkpoint


def preprocess(tokenizer, config, example, max_seq_length, prompt_key, target_key):
    prompt = example[prompt_key]
    target = example[target_key]
    prompt_ids = tokenizer.encode(prompt, max_length=max_seq_length, truncation=True)
    target_ids = tokenizer.encode(target, max_length=max_seq_length, truncation=True, add_special_tokens=False)
    # 最终还是将instruction的输入输出都拼在一起,使用经典的causal-LM的next word prediction方式来训练
    input_ids = prompt_ids + target_ids + [config.eos_token_id]
    return {"input_ids": input_ids, "seq_len": len(prompt_ids)}

def read_jsonl(path, max_seq_length, prompt_key, target_key, skip_overlength=False):
    if 'llama' in model_checkpoint.lower() or 'alpaca' in model_checkpoint.lower():
        tokenizer = LlamaTokenizer.from_pretrained(
            model_checkpoint, trust_remote_code=True)
    else:
        tokenizer = AutoTokenizer.from_pretrained(
            model_checkpoint, trust_remote_code=True)
    config = transformers.AutoConfig.from_pretrained(
        model_checkpoint, trust_remote_code=True, device_map='auto')
    with open(path, "r") as f:
        for line in tqdm(f.readlines()):
            example = json.loads(line)
            feature = preprocess(tokenizer, config, example, max_seq_length, prompt_key, target_key)
            if skip_overlength and len(feature["input_ids"]) > max_seq_length:
                continue
            feature["input_ids"] = feature["input_ids"][:max_seq_length]
            yield feature

def format_example(example: dict) -> dict:
    context = f"Instruction: {example['instruction']}\n"
    if example.get("input"):
        context += f"Input: {example['input']}\n"
    context += "Answer: "
    target = example["output"]
    return {"context": context, "target": target}

with open(args.data_path) as f:
     examples = json.load(f)

with open(args.input_file, 'w') as f:
    for example in tqdm(examples, desc="formatting.."):
        f.write(json.dumps(format_example(example)) + '\n')

# 输出文件统一放在 data/tokenized_data 文件夹下
input_file_path = f'data/{args.input_file}'
save_path = f"data/tokenized_data/{args.save_name}"
dataset = datasets.Dataset.from_generator(
    lambda: read_jsonl(input_file_path, args.max_seq_length, args.prompt_key, args.target_key, args.skip_overlength)
)

dataset.save_to_disk(save_path)

执行成功后生成的文件目录:
在这里插入图片描述

(3)加载基础模型

  • print(model):model打印出来,以便 (1)查看模型结构;(2)后续设置lora微调层(常作用在attention相关的模块)
  • load_in_8bit=False:是否使用8bit量化:如果加载时内存溢出,可尝试设置为True
print('loading init model...')
model = AutoModel.from_pretrained(
     model_path, trust_remote_code=True,
     load_in_8bit=False,  # 量化:如果加载时内存溢出,可尝试设置为True
     device_map="auto"  # 模型不同层会被自动分配到不同GPU上进行计算
     # device_map={'':torch.cuda.current_device()}
 )
print(model.hf_device_map)
print(f'memory_allocated {torch.cuda.memory_allocated()}')
print(model)    # 把model打印出来,以便:(1)查看模型结构;(2)后续设置lora微调层(常作用在attention相关的模块)

如果多卡训练出现loss计算报错:

设置了 device_map=“auto” 之后:

  • chatglm 1.0 的时候,lm_head会跟input_layer自动分配到同个 device,
  • chatglm 2.0 的时候,没有了 lm_head,有一个 output_layer,这个时候可能会分配到两个device,导致计算loss的时候报错显示 RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:2 and cuda:0!

(1) 一个解决办法是设置device_map={‘’:torch.cuda.current_device()},进行数据并行,但是这样batchsize只能设置非常小,而且很占显存
(2)另一个解决办法是: 手动把 output_layer 设置为跟 input 一样的 device。
然后这里会加载两次模型,可以先加载,调整device_map之后,再把旧模型删掉:https://github.com/pytorch/pytorch/issues/37250#issuecomment-1622972872

if torch.cuda.device_count() > 1:
	 model.hf_device_map['transformer.output_layer'] = model.hf_device_map['transformer.embedding']
	 new_hf_device_map = model.hf_device_map
	 model.cpu()
	 del model
	 torch.cuda.empty_cache()
	 print(f'memory_allocated {torch.cuda.memory_allocated()}')
	 print('loading real model...')
	 model = AutoModel.from_pretrained(model_path, trust_remote_code=True, device_map=new_hf_device_map)
	 print(model.hf_device_map)

(4)内存优化、梯度计算设置

"""
.gradient_checkpointing_enable()
.enable_input_require_grads()
.is_parallelizable
这三个都是 transformers 模型的函数/参数(见 transformers/modeling_utils.py 文件)
"""

model.gradient_checkpointing_enable()
# note: use gradient checkpointing to save memory at the expense of slower backward pass.

model.enable_input_require_grads()
# note: Enables the gradients for the input embeddings. This is useful for fine-tuning adapter weights while keeping the model weights fixed. 
# See https://github.com/huggingface/transformers/blob/ee88ae59940fd4b2c8fc119373143d7a1175c651/src/transformers/modeling_utils.py#L1190

(5)加载loraConfig,设置peft模型

# setup peft
if finetune_args.previous_lora_weights == None:
    peft_config = LoraConfig(
        task_type=TaskType.CAUSAL_LM,
        inference_mode=False,
        r=finetune_args.lora_rank,
        lora_alpha=32,
        lora_dropout=0.1,
        target_modules=["q_proj", "k_proj", "v_proj"]  # 把model打印出来,找跟attention相关的模块
    )
    model = get_peft_model(model, peft_config)
else:
    # 当设置了 previous_lora_weights 说明要继续训练之前的 lora weights
    model = PeftModel.from_pretrained(model, finetune_args.previous_lora_weights)
    
    # see: https://github.com/huggingface/peft/issues/184
    for name, param in model.named_parameters():
        if 'lora' in name or 'Lora' in name:
            param.requires_grad = True

(6)模型训练

# 定义数据加载器,可以根据需要自定义
if finetune_args.no_prompt_loss:
    print("*** If you see this message, ***")
    print("*** it means: Prompt is not calculated in loss. ***")
    data_collator = my_data_collator
else:
    data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
 
 # 开始训练   
trainer = ModifiedTrainer(    # 这里也可以直接使用Trainer类 
    model=model,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    args=training_args,
    callbacks=[TensorBoardCallback(writer)],
    data_collator=data_collator,  
)
trainer.train()

备注1:以上代码中的 ModifiedTrainer只是简化了Trainer的代码实现,并没有改变代码逻辑,所以该类可要可不要。

class ModifiedTrainer(Trainer):
    def compute_loss(self, model, inputs, return_outputs=False):
        outputs = model(
            input_ids=inputs["input_ids"],
            labels=inputs["labels"],
        )
        loss = outputs.loss
        return (loss, outputs) if return_outputs else loss

    def save_model(self, output_dir=None, _internal_call=False):
        # 因为交给Trainer的model实际上是PeftModel类型,所以这里的 save_pretrained 会直接使用PeftModel的保存方法
        # 从而只保存 LoRA weights
        self.model.save_pretrained(output_dir)

备注2my_data_collator数据加载器:根据需要自定义功能

# 这里的 collator 主要参考了 https://github.com/mymusise/ChatGLM-Tuning/blob/master/finetune.py 中的写法
# 将 prompt 的部分的label也设置为了 -100,从而在训练时不纳入loss的计算
# 对比之下,也可以直接使用 DataCollatorForLanguageModeling,会将prompt 也纳入了计算。
# 这两种方式孰优孰劣尚不得而知,欢迎在issue或discussion中讨论。
def my_data_collator(features: list) -> dict:
	"""
	    这个 collator 会把 prompt 的部分给mask掉,使得只有 output 部分参与计算 loss
    """
    len_ids = [len(feature["input_ids"]) for feature in features]
    longest = max(len_ids)
    input_ids = []
    labels_list = []
    for ids_l, feature in sorted(zip(len_ids, features), key=lambda x: -x[0]):
        ids = feature["input_ids"]   # ids= prompt + target, 总长度是max_seq_length
        seq_len = feature["seq_len"]   # prompt length
        labels = (
                [-100] * (seq_len - 1) + ids[(seq_len - 1):] + [-100] * (longest - ids_l)
        )
        ids = ids + [tokenizer.pad_token_id] * (longest - ids_l)
        _ids = torch.LongTensor(ids)
        labels_list.append(torch.LongTensor(labels))
        input_ids.append(_ids)
    input_ids = torch.stack(input_ids)
    labels = torch.stack(labels_list)
    return {
        "input_ids": input_ids,
        "labels": labels,
    }

(7)模型保存

# save model
model.save_pretrained(training_args.output_dir)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kafka简单汇总

Kafka的结构图 多个Parttion共同组成这个topic的所有消息。每个consumer都属于一个consumer group,每条消息只能被consumer group中的一个Consumer消费, 但可以被多个consumer group消费。即组间数据是共享的,组内数据是竞争的。二、消费模型…

PO设计模式详解(Python+selenium+unittest)

一、什么是PO设计模式(Page Object Model) 1、Page Object是一种设计模式,它主要体现在对界面交互细节的封装上,使测试用例更专注于业务的操作,从而提高测试用例的可维护性。 2、一般PO设计模式有三层 第一层&#…

【紫光同创国产FPGA教程】【PGC1/2KG第六章】密码锁实验例程

本原创教程由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处 适用于板卡型号: 紫光同创PGC1/2KG开发平台(盘古1K/2K) 一:盘古1K/2K开发板(紫光同创PGC…

Git图形化界面GUI的使用SSH协议及idea集成Git

前言 图形化界面(GUI,Graphical User Interface)是一种用户与计算机程序或操作系统交互的方式,通过图形元素,如图标、按钮、窗口等,而不是通过命令行来完成操作。GUI的设计旨在让用户通过直观的图形界面进行…

MAC地址注册的原理和应用

MAC地址注册是指在网络设备中,将设备的物理地址(即MAC地址)与设备的IP地址进行关联和注册的过程。MAC地址是以太网卡硬件上的独特标识符,用于在局域网中标识网络设备。 MAC地址注册在网络管理中起到重要作用,它可以帮助…

vue3配置环境变量,小白简单易学

环境变量的意义就是防止我们更新打包的时候写错变量,合并代码这些一系列问题 首先看看效果 左边是本地测试环境,右边是打包后的生产环境,写这个环境变量的好处就是,你在本地开发的时候变量随便改,不会影响生产环境&am…

ChIP在植物领域中的应用

01 什么是ChIP? 染色质免疫共沉淀技术(Chromatin Immunoprecipitation assay,ChIP)是研究体内DNA与蛋白质相互作用的方法。其基本原理是在细胞生理状态下固定蛋白质-DNA复合物,将其随机打断为一定长度范围内的染色质小…

阿里云容器镜像服务的运维总结

一、背景 容器镜像服务,作为一个可选付费产品,主要作用是存储docker的镜像仓库,供k8s拉取到Pod节点里。 你可以自己搭建一个harbor镜像仓库,在公司的开发环境下,将image推送到仓库;然后在生产k8s从仓库拉取…

基于JAX-WS实现RESTful形式的web服务端点(endpoint)

RESTful形式的web服务使用XML/HTTP绑定,实现jakarta.xml.ws.Provider。 服务端的实现类用jakarta.xml.ws.WebServiceProvider和BindingType(valueHTTPBinding.HTTP_BINDING)注释。其中HTTPBinding.HTTP_BINDING表示使用XML/HTTP绑定。 例如: WebServic…

Cesium 点线面实体

1.点 const point viewer.entities.add({ id: point, position: Cesium.Cartesian3.fromDegrees(113, 30), point: { pixelSize: 20, //像素 color: Cesium.Color.DEEPPINK, outlineColor: Cesium.Color.fromCssColorString(#fff), outlineWidth: 2, // 像素 }, }); 2.图标标注…

10 # 手写 every 方法

every 使用 every() 方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值。 ele&#xff1a;表示数组中的每一个元素index&#xff1a;表示数据中元素的索引array&#xff1a;表示数组 <script>var arr [1, 3, 5, 7, 8];var result arr.ever…

EDA实验-----3-8译码器设计(QuartusII)

目录 一. 实验目的 二. 实验仪器 三. 实验原理及内容 1.实验原理 2.实验内容 四&#xff0e;实验步骤 五. 实验报告 六. 注意事项 七. 实验过程 1.创建Verilog文件&#xff0c;写代码 ​编辑 2.波形仿真 3.连接电路图 4.烧录操作 一. 实验目的 学会Verilog HDL的…

金融帝国实验室(Capitalism Lab)V10版本即将推出全新公司徽标(2023-11-13)

>〔在即将推出的V10版本中&#xff0c;我们将告别旧的公司徽标&#xff0c;采用全新光鲜亮丽、富有现代气息的设计&#xff0c;与金融帝国实验室&#xff08;Capitalism Lab&#xff09;的沉浸式体验完美互补&#xff01;〕 ————————————— >〔《公司详细信…

了解 SwiftUI 中 StoreKit 2 新功能

文章目录 前言配置项目构建支付功能总结 前言 StoreKit 为我们提供了通过应用程序获得收入的机会。它允许我们设置应用内购买和订阅的购买流程。StoreKit 2 引入了一种基于现代 Swift 的 API&#xff0c;用于构建类型安全的应用内购买。下面我们将开始关于 StoreKit 2 的系列文…

三、机器学习基础知识:Python常用机器学习库(中文文本分析相关库)

文章目录 1、Jieba库1.1 主要函数1.2 词性标注1.3 关键词提取 2、WordCloud库2.1 常见参数2.2 词云绘制 文本分析是指对文本的表示及其特征的提取&#xff0c;它把从文本中提取出来的特征词进行量化来表示文本信息&#xff0c;经常被应用到文本挖掘以及信息检索的过程当中。 1、…

毕业等于失业?那就早点做职业规划

大学生已经不再是稀罕物种了...最佳调侃就是&#xff1a;毕业等于失业....人艰.... 这个只是玩笑&#xff0c;却道破了实质...说到底&#xff0c;找工作依然是竞争关系&#xff0c;跟当年的高考没有什么本质区别....岗位就这么多&#xff0c;毕业生却年年量产.... 哪些找到好…

项目笔记记录

一、node下载版本报错&#xff1a;npm install --legacy-peer-deps 二、Scheduled: 任务自动化调度 Scheduled 标记要调度的方法的注解&#xff0c;必须指定 cron&#xff0c;fixedDelay或fixedRate属性之一 fixedDelay&#xff1a;固定延迟 延迟执行任务&#xff0c;任务在…

Linux ____03、文件类型、属性、修改文件属性(更改文件权限)(命令)

文件类型、属性、修改文件属性 一、文件类型二、文件属性三、修改文件属性1、chgrp&#xff1a;更改文件属组2、chown&#xff1a;更改文件属主&#xff0c;也可以同时更改文件属组3、chmod&#xff1a;更改文件9个属性————————如觉不错&#xff0c;随手点赞&#xff…

想要检测TikTok网络是否安全?这五个网站请收好

Tiktok目前在海外大火&#xff0c;越来越多的人想要进入TikTok的海外市场并捞一桶金。然而&#xff0c;成功并非易事。想要在TikTok中立足&#xff0c;我们必须保证我们的设备、网络环境和网络节点完全符合官方的要求&#xff0c;并且没有任何异常或风险。那么我们该如何设置、…

晶圆代工产能利用率下降,降价大战一触即发 | 百能云芯

晶圆代工行业正面临产能利用率的重大挑战&#xff0c;据悉&#xff0c;联电、世界先进和力积电等主要代工厂纷纷降低明年首季的报价&#xff0c;幅度高达两位数百分比&#xff0c;项目客户降幅更高达15%至20%&#xff0c;各大晶圆代工厂深陷产能利用率六成保卫战。 晶圆代工降价…