使用PEFT优化性能:深入探讨即时调整

2023年11月29日 由 alex 发表 330 0

3


介绍


PEFT通过优化预训练模型和结构化提示来革新NLP,以提升特定任务的性能,从而消除了对大量标注数据的需求。


其创新的即时调整功能能够有效地对特定任务进行微调,即使是在标注数据有限的情况下也同样适用,这解决了数据集稀缺或高成本的问题。


4


目前对带有PEFT的逐步探索深入研究了它在自然语言处理(NLP)领域的应用、方法论和益处。


即时调整


即时调整是一种用于优化语言模型性能的技术,特别是在自然语言处理(NLP)系统的背景下。它包括对给定模型的输入提示进行精炼和调整,以引出更准确、更相关或更期望的响应。即时调整的目标是通过反复试验不同提示表达的方式来增强模型的输出。


5


它是如何工作的?


  • 理解模型:在开始即时调整之前,理解所使用的语言模型至关重要。了解模型的架构、优势和局限有助于制定有效的提示语。
  • 初始提示设计:过程通常从为特定任务或查询创建一个初始提示开始。这个提示作为输入提供给语言模型,然后分析生成的输出的相关性和准确性。
  • 参数微调:一些语言模型允许用户调整参数,如温度或采样技巧。这些参数影响模型回应的多样性和创造性。微调这些参数可以是即时调整过程的一部分。
  • 监控和评估:在整个即时调整过程中,建立一个强大的监控和评估系统非常重要。这涉及系统地评估生成输出的质量,识别错误模式,并使用这些信息指导对提示的进一步调整。
  • 结合人类反馈:人类反馈在即时调整中扮演着至关重要的角色。用户可以评估模型的响应,收集最终用户的反馈,并使用这些反馈随时间优化和改进提示。这种人在循环内的方法有助于模型性能的持续提升。


参数高效的微调


参数高效的微调(PEFT)是由Hugging Face引入的一种创新方法,旨在解决与基于变换器架构的大型语言模型(LLM)的训练和部署相关的挑战。该方法具体解决了在下游任务中对这些庞大模型进行微调时的计算和存储成本问题。


6


主要特点与概念


  • 减少参数微调:PEFT专注于只对一小部分额外的模型参数进行微调,同时冻结预训练大型语言模型(LLMs)的大多数参数。这种选择性微调显著减少了计算需求。


  • 克服灾难性遗忘:通过PEFT缓解了在完全微调LLMs时观察到的灾难性遗忘现象。这种方法确保模型在适应特定下游任务的同时,保留其预训练状态的知识。


  • 跨模态应用:PEFT具有多功能性,并将其应用范围扩展到传统自然语言处理任务之外。它已经成功应用于不同的模态,包括计算机视觉(例如,稳定扩散(Stable Diffusion)、布局LM(LayoutLM))和音频(例如,耳语(Whisper)、XLS-R)。


  • 支持的PEFT方法:该库支持各种PEFT方法,包括低秩适应(LoRA)、前缀调整(Prefix Tuning)和即时调整(Prompt Tuning)。每种方法都旨在满足特定的微调需求和场景。


7


使用案例和示例


  • 消费级硬件调优:PEFT已应用于如bigscience/T0_3B这样具有30亿参数的大型LLM(大型语言模型),它可以在RAM有限的消费级硬件上进行调优。这使得在像Nvidia GeForce RTX 2080 Ti和Nvidia GeForce RTX 3080这样的GPU上进行调优成为可能。
  • Google Colab中的INT8调优:PEFT扩展了其至INT8(8位整数)调优的能力,展示了在Google Colab中对具有67亿参数的OPT-6.7b模型的微调过程。
  • Stable Diffusion Dreambooth:PEFT被用于在具有11GB RAM的消费级硬件上训练Stable Diffusion Dreambooth,如Nvidia GeForce RTX 2080 Ti和Nvidia GeForce RTX 3080。


使用PEFT进行训练


训练过程涉及创建一个对应所选PEFT方法的配置,使用PEFT库包装基础的Transformers模型,并使用修改后的配置照常训练模型。


8


得到的模型可以保存用于推理,只包含训练过的增量PEFT权重。


使用带有PEFT的即时调整


首先,我们将安装所有重要的库。


!pip install -q peft==0.4.0
!pip install -q transformers
!pip install -q datasets


然后,我们将导入在此代码实现中需要的模块。


# Importing classes and functions from the transformers library
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForLanguageModeling
# Importing the load_dataset function from the datasets library
from datasets import load_dataset
# Importing specific classes and functions from the peft library
from peft import get_peft_model, PromptTuningConfig, TaskType, PromptTuningInit, PeftModel, PeftConfig
# Importing the notebook_login function from the huggingface_hub library
from huggingface_hub import notebook_login
# Importing the os and time modules
import os
import time


我们将使用bloomz模型作为我们生成文本的基础因果语言模型。这个模型是在多语言数据集上训练的。


# Specify the pre-trained model name you want to use
model_name = "bigscience/bloomz-560m"
# Load the tokenizer associated with the pre-trained model
tokenizer = AutoTokenizer.from_pretrained(model_name)
# Load the pre-trained causal language model using the specified model name
foundation_model = AutoModelForCausalLM.from_pretrained(model_name)


在进行任何微调之前,我们会要求模型针对以下输入句子生成一个新短语。


# Tokenize the input text using the specified tokenizer
input1 = tokenizer("Two things are infinite: ", return_tensors="pt", padding=True)
# Generate text using the pre-trained foundation model based on the provided input_ids and attention_mask.
foundation_outputs = foundation_model.generate(
    input_ids=input1["input_ids"],
    attention_mask=input1["attention_mask"],
    max_new_tokens=7,
    eos_token_id=tokenizer.eos_token_id
)
# Decode the generated token IDs into human-readable text.
decoded_output = tokenizer.batch_decode(foundation_outputs, skip_special_tokens=True)
# Print the decoded output, which represents the generated text.
print(decoded_output)


输出结果还不错。然而,BLOOMZ预训练的数据集并没有包含任何关于励志英文名言的内容。因此,我们将在一个名为Abirate/english_quotes的数据集上对bloom-560m进行微调,该数据集专门包含励志英文名言。我们希望建立经过微调的版本,以后用来生成更多的名言!


# Load the "english_quotes" dataset using the load_dataset function from the datasets library
data = load_dataset("Abirate/english_quotes")
# Tokenize the quotes in the dataset using the specified tokenizer
data = data.map(lambda samples: tokenizer(samples["quote"]), batched=True)
# Select a subset of the training samples (first 50 samples in this case)
train_sample = data["train"].select(range(50))
# Display the selected subset of training samples
display(train_sample)


Prompt tuning 允许对软提示(也称为虚拟令牌)进行随机和初始化。现在,我们将从随机初始化开始,在这里我们所提供的仅仅是虚拟提示的长度。


# Create a configuration for prompt tuning using the PromptTuningConfig class
peft_config = PromptTuningConfig(
    task_type=TaskType.CAUSAL_LM,
    prompt_tuning_init=PromptTuningInit.RANDOM,
    num_virtual_tokens=4,
    tokenizer_name_or_path=model_name
)
# Get a PeftModel using the specified foundation_model and prompt tuning configuration
peft_model = get_peft_model(foundation_model, peft_config)
# Print the trainable parameters of the PeftModel
print(peft_model.print_trainable_parameters())


我们将创建一个目录,用于存放我们的输出。


%mkdir /content/working_dir


PEFT使我们能够大幅减少可训练参数的数量。现在,我们可以继续使用TrainingArguments来定义我们的微调配置。


# Define the output directory for storing Peft model outputs
output_directory = os.path.join("/content/working_dir", "peft_outputs")
# Create the working directory if it doesn't exist
if not os.path.exists("/content/working_dir"):
    os.mkdir("/content/working_dir")
# Create the output directory if it doesn't exist
if not os.path.exists(output_directory):
    os.mkdir(output_directory)
# Define training arguments for the Peft model
training_args = TrainingArguments(
    output_dir=output_directory,  # Where the model predictions and checkpoints will be written
    no_cuda=True,  # This is necessary for CPU clusters.
    auto_find_batch_size=True,  # Find a suitable batch size that will fit into memory automatically
    learning_rate=3e-2,  # Higher learning rate than full fine-tuning
    num_train_epochs=5  # Number of passes to go through the entire fine-tuning dataset
)


我们也将使用DataCollator来帮助我们形成批量输入,以便传入模型进行训练。


具体来说,我们将使用DataCollatorForLanguageModeling,它会额外地将输入填充到一个批次中最大长度,因为输入可能具有不同的长度。


# Enable gradient checkpointing in the Peft model's configuration
peft_model.config.gradient_checkpointing = True
# Create a Trainer instance for training the Peft model
trainer = Trainer(
    model=peft_model,  # We pass in the PEFT version of the foundation model, bloomz-560M
    args=training_args,  # Training arguments specifying output directory, GPU usage, batch size, etc.
    train_dataset=train_sample,  # Training dataset
    data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False)  # mlm=False indicates not to use masked language modeling
)
# Start the training process
trainer.train()


现在,我们将保存模型。


# Record the current time for creating a unique Peft model path
time_now = time.time()
# Create a path for saving the Peft model using the output directory and timestamp
peft_model_path = os.path.join(output_directory, f"peft_model_{time_now}")
# Save the trained Peft model to the specified path
trainer.model.save_pretrained(peft_model_path)


你可以从之前保存的路径中加载模型,并请求模型根据我们之前的输入生成文本!


# Load the trained Peft model from the specified path using the PeftModel class
loaded_model = PeftModel.from_pretrained(
    foundation_model,  # The base model to be used for prompt tuning
    peft_model_path,   # The path where the trained Peft model is saved
    is_trainable=False  # Indicates that the loaded model should not be trainable
)


让我们生成已加载模型的输出。


# Generate text using the loaded Peft model based on the provided input_ids and attention_mask.
loaded_model_outputs = loaded_model.generate(
    input_ids=input1["input_ids"],
    attention_mask=input1["attention_mask"],
    max_new_tokens=7,
    eos_token_id=tokenizer.eos_token_id
)
# Decode the generated token IDs into human-readable text.
decoded_output = tokenizer.batch_decode(loaded_model_outputs, skip_special_tokens=True)
# Print the decoded output, which represents the generated text.
print(decoded_output)


让我们比较一下我们精调过的随机初始化模型和文本初始化方法。


请注意,我们唯一改变的是 prompt_tuning_init 设置,并且我们还提供了一个简洁的文本提示。


# Create a configuration for text-based prompt tuning using the PromptTuningConfig class
text_peft_config = PromptTuningConfig(
    task_type=TaskType.CAUSAL_LM,
    prompt_tuning_init=PromptTuningInit.TEXT,
    prompt_tuning_init_text="Generate inspirational quotes",  # Provides a starter for the model to begin searching for the best embeddings
    num_virtual_tokens=3,  # This doesn't have to match the length of the text above
    tokenizer_name_or_path=model_name
)
# Get a PeftModel using the specified foundation_model and text-based prompt tuning configuration
text_peft_model = get_peft_model(foundation_model, text_peft_config)
# Print the trainable parameters of the Text-based PeftModel
print(text_peft_model.print_trainable_parameters())


现在,我们将训练模型。


# Create a Trainer instance for training the Text-based Peft model
text_trainer = Trainer(
    model=text_peft_model,  # We pass in the Text-based PEFT version of the foundation model
    args=training_args,  # Training arguments specifying output directory, GPU usage, batch size, etc.
    train_dataset=train_sample,  # Training dataset
    data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False)  # mlm=False indicates not to use masked language modeling
)
# Start the training process for the Text-based Peft model
text_trainer.train()


然后我们将执行与我们为比较所做的相同的操作,即保存、加载并从文本初始化模型生成输出。


# Save the model
time_now = time.time()
text_peft_model_path = os.path.join(output_directory, f"text_peft_model_{time_now}")
text_trainer.model.save_pretrained(text_peft_model_path)
# Load model
loaded_text_model = PeftModel.from_pretrained(
    foundation_model,
    text_peft_model_path,
    is_trainable=False
)
# Generate output
text_outputs = text_peft_model.generate(
    input_ids=input1["input_ids"],
    attention_mask=input1["attention_mask"],
    max_new_tokens=7,
    eos_token_id=tokenizer.eos_token_id
)
print(tokenizer.batch_decode(text_outputs, skip_special_tokens=True))


登录到你的hugging face账户以便将你的模型推送到hugging face中心。


notebook_login()
# Login
hf_username = <FILL_IN_WITH_YOUR_HUGGINGFACE_USERNAME>
peft_model_id = f"{hf_username}/bloom_prompt_tuning_{time_now}"
trainer.model.push_to_hub(peft_model_id, use_auth_token=True)


现在,从模型的预训练版本设置Peft模型的配置。


# Load the configuration for the Peft model from a pre-trained version
peft_config = PeftConfig.from_pretrained(peft_model_id)
# Load the base causal language model using the configuration.
foundation_model = AutoModelForCausalLM.from_pretrained(peft_config.base_model_name_or_path)
# Construct the Peft model using the pre-trained foundation model and the Peft model ID.
peft_random_model = PeftModel.from_pretrained(foundation_model, peft_model_id)


根据提供的input_ids和attention_mask,使用Peft模型生成文本。


# The `generate` method is used to generate text from the model.
# max_new_tokens specifies the maximum number of new tokens to generate.
# eos_token_id is the ID of the end-of-sequence token, indicating the end of generated text.
online_model_outputs = peft_random_model.generate(
    input_ids=input1["input_ids"],
    attention_mask=input1["attention_mask"],
    max_new_tokens=7,
    eos_token_id=tokenizer.eos_token_id
)
# Decode the generated token IDs into human-readable text.
# The `batch_decode` method of the tokenizer is used for decoding.
# skip_special_tokens=True removes any special tokens (e.g., padding, EOS) from the decoded output.
decoded_output = tokenizer.batch_decode(online_model_outputs, skip_special_tokens=True)
# Print the decoded output, which represents the generated text.
print(decoded_output)


最终,你将得到解码后的输出。


['Two things are infinite:  the number of people and the number']'Two things are infinite:  the number of people and the number']


结论


总之,Prompt Tuning,尤其是 PEFT(Prompt-based Efficient Fine-tuning),提供了一个强大的框架,通过对特定任务或提示进行定制来优化语言模型的性能。


9


文章来源:https://medium.com/international-school-of-ai-data-science/optimizing-performance-with-peft-a-deep-dive-into-prompt-tuning-2b9a17bc9851
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消