应用QLoRA对Llama 2进行微调是咱们罕用的一个办法,然而在微调时会遇到各种各样的问题,所以在本文中,将尝试以具体正文的形式给出一些常见问题的答案。这些问题是特定于代码的,大多数正文都是针对所波及的开源库以及所应用的办法和类的问题。

导入库

对于大模型,第一件事是又多了一些不相熟的Python库。

 !pip install -q peft==0.4.0 bitsandbytes==0.40.2 transformers==4.31.0 trl==0.4.7

咱们必须首先装置accelerate, peft, bitsandbytes, transformers和trl。除了transformers,其余的库都很生疏

transformers是这里最古老的库,PyPI上最早的版本(2.0.0)能够追溯到2019年。它是huggingface公布的库,能够快速访问文本,图像和音频(从hugs的API下载)的机器学习模型。它还提供训练和微调模型的性能,并能够HuggingFace模型核心共享这些模型。库没有像Pytorch或Tensorflow那样从头开始构建神经网络的形象层和模块,它提供了专门针对模型进行优化的训练和推理api。transformer是用于LLM微调的要害Python库之一,因为目前大部分的LLM都是能够通过它来加载应用。

bitsandbytes是一个绝对较新的库,PyPI上最早的版本时2021年公布的。它是CUDA自定义函数的轻量级包装,专门为8位优化器、矩阵乘法和量化而设计。它次要提供了优化和量化模型的性能,特地是对于llm和transformers模型。它还提供了8位Adam/AdamW、 SGD momentum、LARS、LAMB等函数。bitsandbytes的指标是通过8位操作实现高效的计算和内存应用从而使llm更易于拜访。通过利用8位优化和量化技术能够进步模型的性能和效率。在较小尺寸的消费类gpu(如RTX 3090)上运行llm存在内存瓶颈。所以人们始终对试图缩小运行llm的内存需要的权重量化技术进行钻研。bitsandbytes的想法是量化模型权重的浮点精度,从较大的精度点(如FP32)到较小的精度点(如Int8) (4x4 Float16)。有一些技术能够将FP32量化为Int8,包含abmax和零点量化,但因为这些技术的局限性,bitsandbytes库的创建者独特撰写了LLM.int8()论文以及8位优化器,为llm提供无效的量化办法。所以因为bitsandbytes库提供的量化技术,这在很大水平上让咱们在生产级的GPU上能够微调更大的模型。

Peft容许咱们缩小将LLM(或其局部)加载到工作内存中以进行微调的内存需要。与应用较小深度学习模型的迁徙学习技术不同,在迁徙学习技术中,咱们须要解冻像AlexNet这样的神经网络的较低层,而后在新工作上对分类层进行齐全微调,而应用llm进行这种微调的老本是微小的。Parameter Efficient Fine-Tuning(PEFT)办法是一组使llm适应上游工作的办法,例如在内存受限的设施(如T4GPU 提供16GB VRAM)上进行摘要或问答。通过Peft对LLM的局部进行微调,依然能够取得与齐全微调相比的后果。如LoRA和Prefix Tuning是相当胜利的。peft库是一个HuggingFace库,它提供了这些微调办法,这是一个能够追溯到2023年1月的新库。在本文中咱们将应用QLoRA,这是一种用于量化llm的低秩自适应或微调技术。

trl是另一个HuggingFace库,trl其实是自2021年公布的,然而在2023年1月才被人们热传。TRL是Transformer Reinforcement Learning的缩写也就是Transformer 强化学习。它提供了在训练和微调LLM的各个步骤中的不同算法的实现。包含监督微调步骤(SFT),处分建模步骤(RM)和近端策略优化(PPO)步骤。trl也将peft作为一个依赖项,所以能够应用带有peft办法(例如LoRA)的SFT训练器。

dataset尽管没有蕴含在咱们之前的安装包列表中(这是因为它是transformers的一个依赖项),但dataset库是huggingface生态系统中的另一个重要局部。它能够不便的拜访HuggingFace托管的许多公共数据集,也就是说省去了咱们本人写dataset和dataloader的工夫。

下面这些库对于LLM的任何工作都是至关重要的。这里做了一个简略的图片来总结这些库是如何组合在一起的。

上面让咱们看一下导入

 import os import torch from datasets import load_dataset from transformers import (     AutoModelForCausalLM,     AutoTokenizer,     BitsAndBytesConfig,     TrainingArguments,     pipeline,     logging, ) from peft import LoraConfig, PeftModel from trl import SFTTrainer

咱们持续剖析导入

torch是咱们很相熟的深度学习库,这里咱们不须要torch的那些低级性能,然而它是transformers和trl的依赖,在这里咱们须要应用torch来获取dtypes(数据类型),比方torch.Float16以及查看GPU的工具函数。

load_dataset所做的就是加载数据集,然而它从HuggingFace数据集中心下载到本地。所以这是一个在线加载程序,但它既高效又简略,只须要一行代码。

 dataset = load_dataset(dataset_name, split="train")

因为模型很多所以transformer库提供了一组称为Auto classes的类,这些类给出了预训练模型的名称/门路,它能够主动推断出正确的构造并检索相干模型。这个AutoModelForCausalLM是一个通用的Auto类,用于加载用于因果语言建模的模型。

对于transformers,HuggingFace提供了两种类型的语言建模,因果和掩码掩蔽。因果语言模型包含;GPT-3和Llama,这些模型预测标记序列中的下一个标记,以生成与输出数据语义类似的文本。AutoModelForCausalLM类将从模型核心检索因果模型,并加载模型权重,从而初始化模型。from_pretrained()办法为咱们实现了这项工作。

 model_name = "NousResearch/Llama-2-7b-chat-hf" model = AutoModelForCausalLM.from_pretrained(     model_name,     device_map=device_map )

AutoTokenizer是对文本数据进行标记化。它提供了一种无需显式指定标记器类就能够初始化和应用不同模型的标记器的不便的办法。它也是一个通用的Auto类,所以它能够依据提供的模型名称或门路主动抉择适当的标记器。标记器将输出文本转换为标记,这些标记是NLP模型应用的根本文本单位。它还提供了额定的性能,如填充、截断和注意力掩码等。AutoTokenizer简化了为NLP工作对文本数据进行标记的过程。咱们能够看到在上面初始化AutoTokenizer,前面咱们会应用SFTTrainer将初始化的AutoTokenizer作为参数。

 model_name = "NousResearch/Llama-2-7b-chat-hf" # Load LLaMA tokenizer tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)

BitsAndBytesConfig,后面曾经说了咱们应用bitsandbytes进行量化。transformer库最近增加了对bitsandbytes的全面反对,因而应用BitsandBytesConfig能够配置bitsandbytes提供的任何量化办法,例如LLM.int8、FP4和NF4。将量化配置传递给AutoModelForCausalLM初始化器,这样在加载模型权重时就会间接应用量化的办法。

 #bits and byte config bnb_config = BitsAndBytesConfig(     load_in_4bit=use_4bit,     bnb_4bit_quant_type=bnb_4bit_quant_type,     bnb_4bit_compute_dtype=compute_dtype,     bnb_4bit_use_double_quant=use_nested_quant, )  model = AutoModelForCausalLM.from_pretrained(     model_name,     quantization_config=bnb_config, #pass to AutoModelForCausalLM     device_map=device_map )

TrainingArguments非常简单。它用于存储SFTTrainer的所有训练参数。SFFTrainer承受不同类型的参数,TrainingArguments帮忙咱们将所有相干的训练参数组织到一个数据类中放弃代码的整洁和有组织。

还有一些很好的工具类能够与TrainingArguments一起应用,比方HfArgumentParser能够为TrainingArguments创立一个参数解析器,这对CLI应用程序很有用。

 #TrainingArguments training_arguments = TrainingArguments(     output_dir=output_dir,     num_train_epochs=num_train_epochs,     per_device_train_batch_size=per_device_train_batch_size,     gradient_accumulation_steps=gradient_accumulation_steps,     optim=optim,     save_steps=save_steps,     logging_steps=logging_steps,     learning_rate=learning_rate,     weight_decay=weight_decay,     fp16=fp16,     bf16=bf16,     max_grad_norm=max_grad_norm,     max_steps=max_steps,     warmup_ratio=warmup_ratio,     group_by_length=group_by_length,     lr_scheduler_type=lr_scheduler_type,     report_to="tensorboard" )

在实现微调之后,咱们将应用pipeline进行推理。能够抉择各种管道工作的列表,像“图像分类”,“文本摘要”等。还能够为工作抉择要应用的模型。为了定制也能够增加一个参数来进行某种模式的预处理,如标记化或特征提取。

 pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)

从transformer导入的最初一个内容是logging。这是一个日志零碎,这在调试代码时十分有用。

 logging.set_verbosity(logging.CRITICAL)

从peft库中导入的LoraConfig数据类是一个配置类,它次要存储初始化LoraModel所需的配置,LoraModel是PeftTuner的一个实例。咱们将此配置传递给SFTTrainer,它将应用该配置初始化适当的tuner。

 # Load LoRA configuration peft_config = LoraConfig(     lora_alpha=lora_alpha,     lora_dropout=lora_dropout,     r=lora_r,     bias="none",     task_type="CAUSAL_LM", )

PeftModel,一旦咱们应用一种peft办法(如LoRA)进行微调,就须要将LoRA适配器权重保留到磁盘并在应用时将它们加载回内存。PEFT模块微调的权重,与根本模型权重是离开。应用PeftModel,还能够抉择将将base_model权重与新微调的适配器权重合并(调整),这样就失去了一个残缺的新模型。PeftModel.from_pretrained()从内存中加载适配器权重,merge_and_unload()办法将它们与base_model合并。

 # Reload base_model in FP16 and merge it with LoRA weights base_model = AutoModelForCausalLM.from_pretrained(     model_name,     low_cpu_mem_usage=True,     return_dict=True,     torch_dtype=torch.float16,     device_map=device_map, ) model = PeftModel.from_pretrained(base_model, new_model) model = model.merge_and_unload()

最初一个导入是SFTTrainer。SFTTrainer是transformer Trainer类的子类。Trainer是一个功模型训练的泛化API。SFTTrainer在此基础上减少了对参数微调的反对。有监督的微调步骤是训练因果语言模型(如Llama)用于上游工作(如指令遵循)的关键步骤。

SFTTrainer反对PEFT,因而咱们将与LoRA一起应用SFTTrainer。而后,SFTTrainer将应用LoRA执行监督微调。而后咱们能够运行训练器(train())并保留权重(save_pretrained())。

 #Initialize the SFTTrainer object trainer = SFTTrainer(     model=model,     train_dataset=dataset,     peft_config=peft_config,     dataset_text_field="text",     max_seq_length=max_seq_length,     tokenizer=tokenizer,     args=training_arguments,     packing=packing, ) # Train model trainer.train()  # Save trained model trainer.model.save_pretrained(new_model)

对于援用,咱们也总结了一张图片

训练参数

当初咱们晓得了须要哪些库来调优Llama 2(或任何LLM),也晓得了这些库中须要的类,并且理解了这些类的性能。上面就是对后面导入的参数的介绍

模型和数据集名称:

 # The model that you want to train from the Hugging Face hub model_name = "NousResearch/Llama-2-7b-chat-hf"  # The instruction dataset to use dataset_name = "mlabonne/guanaco-llama2-1k"  # Fine-tuned model name new_model = "llama-2-7b-miniguanaco"

model_name、dataset_name和new_model。这些名称遵循HuggingFace模型及其hub上的数据集名称的格局。

birushuo 给一个名字“NousResearch/ Llama-2-7b-chat-hf”这个名字的第一局部NousResearch是一个钻研机构,也就是它HuggingFace账户的名称,第二局部是模型名称lama-2 - 7b-chat-hf。模型命名的倡议是给模型提供描述性的名称,包含有用的信息,如独特的模型名称(lama-2),要害参数信息(7b),以及一些对于模型如何工作的其余有用信息(chat-hf)。咱们在new_model名称llama-2-7b-miniguanaco中看到了同样的规定,这是咱们调配给微调模型的名称。这里附加了在miniguanaco上进行微调的数据集的名称。

QLoRA 参数:

 # LoRA attention dimension lora_r = 64  # Alpha parameter for LoRA scaling lora_alpha = 16  # Dropout probability for LoRA layers lora_dropout = 0.1

咱们将应用的参数是r (lora_r)、lora_alpha和lora_dropout。这些参数对于LoRA来说是最重要的,要了解其中的起因,必须深刻理解LoRA的论文,咱们只做简略的总结:

在神经网络中,反向流传算法计算期望值和理论值之间的误差,而后用这个误差来计算delta,这是神经网络中权重对e的奉献。如果你有一个神经网络的初始权值W0那么对于误差e,咱们计算delta_W0 =∆W。而后应用∆W来更新权重W0 +∆W,以减小误差e。LoRA提出将∆W合成为两组低秩矩阵A和B,使W0 +∆W = W0 + BA。而不是应用残缺的∆W更新,咱们应用较小的低秩更新矩阵BA,这就是咱们如何实现雷同效率和更低的计算需要。如果∆W的大小为(d × k) (W0的大小),则咱们将∆W合成为两个矩阵:B和A,维度别离为(d × r)和(r × k),其中r为秩。

LoraConfig中的参数r (lora_r)是决定更新矩阵BA形态的秩。依据论文能够设置一个小的秩,并且失去很好的后果。当咱们更新W0时,能够通过应用缩放因子来管制BA的影响,这个缩放因子作为学习率。比例因子是咱们的第二个参数(lora_alpha)。最初设置lora_dropput,这是正则化的典型dropput。

BitsandBytes参数:

 # Activate 4-bit precision base model loading use_4bit = True  # Compute dtype for 4-bit base models bnb_4bit_compute_dtype = "float16"  # Quantization type (fp4 or nf4) bnb_4bit_quant_type = "nf4"  # Activate nested quantization for 4-bit base models (double quantization) use_nested_quant = False

咱们正在应用一种称为QLoRA的量化版本的LoRA,这意味着咱们心愿在LoRA微调中应用量化,将量化利用于咱们后面提到的更新权重(以及其余能够量化的操作)。

参数use_4bit(第6行)设置为True,以应用高保真的4位微调,这是起初在QLoRA论文中引入的,以实现比LLM.int8论文中引入的8位量化更低的内存要求。

设置bnb_4bit_compute_dtype(第9行),这是执行计算的数据类型(float16)。也就是说尽管将权重通过4位量化存储,但计算还是产生在16位或32位。

应用bnb_4bit_quant_type(第12行),nf4,依据QLoRA论文,nf4显示了更好的实践和教训性能。

参数use_nested_quant设置为False,并将其传递给bnb_4bit_use_double_quant。模型在第一次量化之后启用第二次量化,从而为每个参数额定节俭0.4位。

下面一些参数都是QLoRA的论文提供,如果想深刻理解,请查看论文或咱们以前的文章

在本文中咱们抉择NF4量化FP16 (float16)精度进行计算后,咱们应该对Colab T4 GPU (16 GB VRAM)没有内存限度。咱们做个简略的计算:如果应用Llama-2-7B(70亿params)和FP16(没有量化),咱们失去7B × 2字节= 14 GB(所需的VRAM)。应用4位量化,咱们失去7B × 0.5字节= ~ 4gb(所需的VRAM)。

训练参数:

 # Output directory where the model predictions and checkpoints will be stored output_dir = "./results"  # Number of training epochs num_train_epochs = 1  # Enable fp16/bf16 training (set bf16 to True with an A100) fp16 = False bf16 = False  # Batch size per GPU for training per_device_train_batch_size = 4  # Batch size per GPU for evaluation per_device_eval_batch_size = 4  # Number of update steps to accumulate the gradients for gradient_accumulation_steps = 1  # Maximum gradient normal (gradient clipping) max_grad_norm = 0.3  # Initial learning rate (AdamW optimizer) learning_rate = 2e-4  # Weight decay to apply to all layers except bias/LayerNorm weights weight_decay = 0.001  # Optimizer to use optim = "paged_adamw_32bit"  # Learning rate schedule (constant a bit better than cosine) lr_scheduler_type = "constant"  # Ratio of steps for a linear warmup (from 0 to learning rate) warmup_ratio = 0.03  # Group sequences into batches with same length # Saves memory and speeds up training considerably group_by_length = True  # Save checkpoint every X updates steps save_steps = 25  # Log every X updates steps logging_steps = 25

Output_dir(第6行):这是设置存储模型预测和检查点的地位,还包含日志

num_train_epochs(第9行):训练的轮次

fp16和bf16(第12行和第13行):咱们将它们都设置为false,因为咱们不会应用混合精度训练,因为曾经有QLoRA了。

per_device_train_batch_size和per_device_eval_batch_size(第16行和第19行):将它们都设置为4。有足够的内存,能够设置更高的批处理大小(>8),这将放慢训练速度。

Gradient_accumulation_steps(第22行):“梯度累积”指的是在理论更新模型权重之前执行的向前和向后传递的次数(更新步骤)。在每一次向前和向后传递期间,梯度被计算并累积在一批数据上。在累积指定步数的梯度之后,而后执行反向传递,计算这些步骤的均匀梯度并相应地更新模型权重。这种办法有助于无效地模仿更少量大小,它缩小了每次向前和向后传递的内存需要。

max_gradient_norm(第25行):如果梯度的范数(幅度)超过某个阈值(由max_grad_norm参数指定),则梯度裁剪放大梯度。如果梯度范数大于max_grad_norm,则梯度将按比例放大,如果梯度标准曾经低于max_grad_norm,则不利用缩放。倡议从max_grad_norm的较高值开始,而后在多个训练迭代中缓缓放大它。

learning_rate(第28行):AdamW的学习率。AdamW是风行的Adam优化器的一个变体。它联合了Adam优化器和权重衰减正则化的技术。

weight_decay(第31行):权重衰减,也称为L2正则化或权重正则化,是机器学习和深度学习中罕用的一种正则化技术,用于避免模型对训练数据的过拟合。它的工作原理是在损失函数中增加一个惩办项。咱们应用AdamW和权重衰减是有意义的,因为权重衰减在微调期间特地有用,因为它有助于避免过拟合,并确保模型适应新工作,同时保留预训练中的一些常识。

optim(第34行):应用AdamW优化器,“paged_adamw_32bit”仿佛是AdamW优化器的一个特定实现或变体,咱们找到任何对于他的信息,所以如果你有对于这方面的信息,请在评论中留下,谢谢!

lr_scheduler_type(第37行):通常咱们在深度学习模型的训练期间应用学习率调度器,以随工夫调整学习率。

warmup_ratio(第40行):这里咱们将“warmup_ratio”设置为0.03。因为每个epoch有250个训练步骤,热身阶段将继续到前8步(250的3%),在此期间,学习率将从0线性减少到指定的初始值2e-4。热身阶段通常用于稳固训练,避免梯度爆炸,并容许模型开始无效地学习。

group_by_length(第44行):这个参数设置为True,会放慢了训练速度。当group_by_length设置为True时,它将训练数据集中大致相同长度的样本分组到同一批中。这意味着具备类似长度的序列被分组在一起,缩小了所需的填充。也就是说批将具备更类似长度的序列,这将最小化所利用的填充量。当批处理具备统一的大小时GPU解决通常更无效,从而缩短训练工夫,这是从LSTM时代就开始的一个减速技巧。

save_steps和logging_steps(第47行和第50行):这里将两个参数都设置为25,以管制记录训练信息和保留检查点的距离步骤。

SFTTrainer参数:

 max_seq_length = None  # Pack multiple short examples in the same input sequence to increase efficiency packing = False

最初参数是特定于SFTTrainer的。

max_seq_length:将max_seq_length设置为None容许咱们不施加最大序列长度限度,咱们不想截断或填充它们到固定长度,因而将max_seq_length设置为None容许咱们应用数据中存在的全副序列长度。

packing:依据文档,ConstantLengthDataset应用这个参数来打包数据集的序列。在ConstantLengthDataset上下文中将packing设置为False能够在解决多个简短示例时提高效率,咱们的数据集就是这种状况。通过将packing设置为False,容许ConstantLengthDataset将多个短示例打包到单个输出序列中,无效地组合它们。这缩小了对大量填充的需要,并进步了内存应用和计算的效率。

加载数据集、根本模型和标记器

 device_map = {"": 0}  # Load dataset (you can process it here) dataset = load_dataset(dataset_name, split="train")  # Load tokenizer and model with QLoRA configuration compute_dtype = getattr(torch, bnb_4bit_compute_dtype)  bnb_config = BitsAndBytesConfig(     load_in_4bit=use_4bit,     bnb_4bit_quant_type=bnb_4bit_quant_type,     bnb_4bit_compute_dtype=compute_dtype,     bnb_4bit_use_double_quant=use_nested_quant, )  # Check GPU compatibility with bfloat16 if compute_dtype == torch.float16 and use_4bit:     major, _ = torch.cuda.get_device_capability()     if major >= 8:         print("=" * 80)         print("Your GPU supports bfloat16: accelerate training with bf16=True")         print("=" * 80)  # Load base model model = AutoModelForCausalLM.from_pretrained(     model_name,     quantization_config=bnb_config,     device_map=device_map ) model.config.use_cache = False model.config.pretraining_tp = 1  # Load LLaMA tokenizer tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) tokenizer.add_special_tokens({'pad_token': '[PAD]'}) tokenizer.pad_token = tokenizer.eos_token tokenizer.padding_side = "right"  # Load LoRA configuration peft_config = LoraConfig(     lora_alpha=lora_alpha,     lora_dropout=lora_dropout,     r=lora_r,     bias="none",     task_type="CAUSAL_LM", )

第5行加载数据集。而后在第9行应用gettr函数将compute_dtype设置为torch.float16。在第10行,初始化BitsandBytesConfig。

在第17行,咱们应用torch.cuda.get_device_capability()函数查看GPU与bfloat16的兼容性。该函数返回反对cuda的GPU设施的计算能力。计算能力示意GPU反对的版本和个性。该函数返回一个由两个整数组成的元组,(major, minor),示意GPU的次要和主要计算能力版本。次要版本示意该计算能力的次要版本,主要版本示意该计算能力的主要版本。例如,如果函数返回(8,0),则示意GPU的计算能力为8.0版本,主要是0。如果GPU是bfloat16兼容的,那么咱们将compute_dtype设置为torch.Bfloat16,因为Bfloat16比float16更好的精度

而后就是应用AutoModelForCausalLM.from_pretrained加载根本模型,在第31行设置了model.config。use_cache为False,当启用缓存时能够缩小变量。禁用缓存则在执行计算的程序方面引入了肯定水平的随机性,这在微调时十分有用。

在第32行设置了model.config.pretraining_tp = 1这里的tp代表张量并行性,依据这里的Llama 2的提醒:

设置model.config. pretraining_tp = 1不等于1的值将激活更精确但更慢的线性层计算,这应该更好地匹配原始概率。

而后就是应用model_name加载Llama标记器。如果你看一下NousResearch/ lama-2的文件,你会留神到有一个tokenizer. model文件。应用model_name, AutoTokenizer能够下载该标记器。

在第36行,调用add_special_tokens({' pad_token ': ' [PAD] '})这是另一个重要代码,因为咱们数据集中的文本长度能够变动,批处理中的序列可能具备不同的长度。为了确保批处理中的所有序列具备雷同的长度,须要将填充令牌增加到较短的序列中。这些填充标记通常是没有任何含意的标记,例如<pad>。

在第37行,咱们设置tokenizer. pad_token = tokenizer. eos_token。将pad令牌与EOS令牌对齐,并使咱们的令牌器配置更加统一。两个令牌(pad_token和eos_token)都有批示序列完结的作用。设置成一个简化了标记化和填充逻辑。

在第38行,设置填充边,将填充边设置为右能够修复溢出问题。

最初在第41行,咱们初始化了LoraConfig

训练

 # Set training parameters training_arguments = TrainingArguments(     output_dir=output_dir,     num_train_epochs=num_train_epochs,     per_device_train_batch_size=per_device_train_batch_size,     gradient_accumulation_steps=gradient_accumulation_steps,     optim=optim,     save_steps=save_steps,     logging_steps=logging_steps,     learning_rate=learning_rate,     weight_decay=weight_decay,     fp16=fp16,     bf16=bf16,     max_grad_norm=max_grad_norm,     max_steps=max_steps,     warmup_ratio=warmup_ratio,     group_by_length=group_by_length,     lr_scheduler_type=lr_scheduler_type,     report_to="tensorboard" )  # Set supervised fine-tuning parameters trainer = SFTTrainer(     model=model,     train_dataset=dataset,     peft_config=peft_config,     dataset_text_field="text",     max_seq_length=max_seq_length,     tokenizer=tokenizer,     args=training_arguments,     packing=packing, )  # Train model trainer.train()  # Save trained model trainer.model.save_pretrained(new_model)

在第2行应用后面具体探讨过的形参初始化TrainingArguments。而后将TrainingArguments与探讨的其余相干参数一起传递到第30行上的SFTTrainer中。

这里新加的一个参数是第27行的dataset_text_field= " text "。dataset_text_field参数用于批示数据集中哪个字段蕴含作为模型输出的文本数据。它使datasets 库可能基于该字段中的文本数据主动创立ConstantLengthDataset,简化数据筹备过程。

HuggingFace生态系统是一个紧密结合的库生态系统,它在后盾为你自动化了很多工作。

推理

 logging.set_verbosity(logging.CRITICAL)  # Run text generation pipeline with our next model prompt = "What is a large language model?" pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200) result = pipe(f"<s>[INST] {prompt} [/INST]") print(result[0]['generated_text'])

第6行,管道初始化。而后在第7行应用管道,传递应用第5行提示符结构的输出文本。咱们应用<s>来批示序列的开始,而增加[INST]和[/INST]作为管制令牌来批示用户音讯的开始和完结。

用适配器权重从新加载根本模型

 # Reload model in FP16 and merge it with LoRA weights base_model = AutoModelForCausalLM.from_pretrained(     model_name,     low_cpu_mem_usage=True,     return_dict=True,     torch_dtype=torch.float16,     device_map=device_map, ) model = PeftModel.from_pretrained(base_model, new_model) model = model.merge_and_unload()  # Reload tokenizer to save it tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) tokenizer.add_special_tokens({'pad_token': '[PAD]'}) tokenizer.pad_token = tokenizer.eos_token tokenizer.padding_side = "right"

在第2行应用AutoModelForCausalLM.from_pretrained来(从新)加载根本模型。咱们将在没有任何量化配置的状况下执行此操作,因为咱们不须要对其进行微调,只是想将其与适配器合并。还在第13行从新加载标记器,并进行与之前在第13 - 14行中所做的雷同的批改。

保留

最初咱们将刚刚通过微调的模型及其标记器保留到本地或者上传到HuggingFace。

 model.push_to_hub(new_model, use_temp_dir=False) tokenizer.push_to_hub(new_model, use_temp_dir=False)

总结

peft,tramsformers等库简化了咱们对于大模型开发的工作流程,并且不须要很多的专业知识也能够对大模型进行微调。然而要失去一个好的模型是一个漫长的过程,就像咱们下面的代码一样,看似简略实则简单,不仅要理解办法的原理,还要通过查看论文理解每一个参数的含意。

本文是一个良好的开始,因为能够把咱们在这里学到的大部分货色利用到微调任何LLM的工作中。对于微调Llama 2,咱们的流程曾经介绍结束了,然而咱们如何能力正确地评估咱们的微调性能?是否在不破费太多的状况下调整更大的模型(70B) ?应用更大的数据集?模型怎么部署呢?咱们会在后续的文章中进行介绍。

https://avoid.overfit.cn/post/903a50f5e8ec469f890a1e8854d64716

作者:Ogban Ugot