在自定义数据集上微调Alpaca和LLaMA

本文将介绍使用LoRa在本地机器上微调Alpaca和LLaMA,我们将介绍在特定数据集上对Alpaca LoRa进行微调的整个过程,本文将涵盖数据处理、模型训练和使用流行的自然语言处理库(如Transformers和hugs Face)进行评估。此外还将介绍如何使用grado应用程序部署和测试模型。

配置

首先,alpaca-lora1 GitHub存储库提供了一个脚本(finetune.py)来训练模型。在本文中,我们将利用这些代码并使其在Google Colab环境中无缝地工作。

首先安装必要的依赖:

 !pip install -U pip
 !pip install accelerate==0.18.0
 !pip install appdirs==1.4.4
 !pip install bitsandbytes==0.37.2
 !pip install datasets==2.10.1
 !pip install fire==0.5.0
 !pip install git+https://github.com/huggingface/peft.git
 !pip install git+https://github.com/huggingface/transformers.git
 !pip install torch==2.0.0
 !pip install sentencepiece==0.1.97
 !pip install tensorboardX==2.6
 !pip install gradio==3.23.0

安装完依赖项后,继续导入所有必要的库,并为matplotlib绘图配置设置:

 import transformers
 import textwrap
 from transformers import LlamaTokenizer, LlamaForCausalLM
 import os
 import sys
 from typing import List
 
 from peft import (
     LoraConfig,
     get_peft_model,
     get_peft_model_state_dict,
     prepare_model_for_int8_training,
 )
 
 import fire
 import torch
 from datasets import load_dataset
 import pandas as pd
 
 import matplotlib.pyplot as plt
 import matplotlib as mpl
 import seaborn as sns
 from pylab import rcParams
 
 %matplotlib inline
 sns.set(rc={'figure.figsize':(10, 7)})
 sns.set(rc={'figure.dpi':100})
 sns.set(style='white', palette='muted', font_scale=1.2)
 
 DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
 DEVICE

数据

我们这里使用BTC Tweets Sentiment dataset4,该数据可在Kaggle上获得,包含大约50,000条与比特币相关的tweet。为了清理数据,删除了所有以“转发”开头或包含链接的推文。

使用Pandas来加载CSV:

 df = pd.read_csv("bitcoin-sentiment-tweets.csv")
 df.head()

通过清理的数据集有大约1900条推文。

情绪标签用数字表示,其中-1表示消极情绪,0表示中性情绪,1表示积极情绪。让我们看看它们的分布:

 df.sentiment.value_counts()
 
 
 # 0.0    860
 # 1.0    779
 # -1.0    258
 # Name: sentiment, dtype: int64

数据量差不多,虽然负面评论较少,但是可以简单的当成平衡数据来对待:

 df.sentiment.value_counts().plot(kind='bar');

构建JSON数据集

原始Alpaca存储库中的dataset5格式由一个JSON文件组成,该文件具有具有指令、输入和输出字符串的对象列表。

让我们将Pandas的DF转换为一个JSON文件,该文件遵循原始Alpaca存储库中的格式:

 def sentiment_score_to_name(score: float):
     if score > 0:
         return "Positive"
     elif score < 0:
         return "Negative"
     return "Neutral"
 
 dataset_data = [
     {
         "instruction": "Detect the sentiment of the tweet.",
         "input": row_dict["tweet"],
         "output": sentiment_score_to_name(row_dict["sentiment"])
     }
     for row_dict in df.to_dict(orient="records")
 ]
 
 dataset_data[0]

结果如下:

 {
   "instruction": "Detect the sentiment of the tweet.",
   "input": "@p0nd3ea Bitcoin wasn't built to live on exchanges.",
   "output": "Positive"
 }

然后就是保存生成的JSON文件,以便稍后使用它来训练模型:

 import json
 with open("alpaca-bitcoin-sentiment-dataset.json", "w") as f:
    json.dump(dataset_data, f)

模型权重

虽然原始的Llama模型权重不可用,但它们被泄露并随后被改编用于HuggingFace Transformers库。我们将使用decapoda-research6:

 BASE_MODEL = "decapoda-research/llama-7b-hf"
 
 model = LlamaForCausalLM.from_pretrained(
     BASE_MODEL,
     load_in_8bit=True,
     torch_dtype=torch.float16,
     device_map="auto",
 )
 
 tokenizer = LlamaTokenizer.from_pretrained(BASE_MODEL)
 
 tokenizer.pad_token_id = (
     0  # unk. we want this to be different from the eos token
 )
 tokenizer.padding_side = "left"

这段代码使用来自Transformers库的LlamaForCausalLM类加载预训练的Llama 模型。load_in_8bit=True参数使用8位量化加载模型,以减少内存使用并提高推理速度。

代码还使用LlamaTokenizer类为同一个Llama模型加载标记器,并为填充标记设置一些附加属性。具体来说,它将pad_token_id设置为0以表示未知的令牌,并将padding_side设置为“left”以填充左侧的序列。

数据集加载

现在我们已经加载了模型和标记器,下一步就是加载之前保存的JSON文件,使用HuggingFace数据集库中的load_dataset()函数:

 data = load_dataset("json", data_files="alpaca-bitcoin-sentiment-dataset.json")
 data["train"]

结果如下:

 Dataset({
     features: ['instruction', 'input', 'output'],
     num_rows: 1897
 })

接下来,我们需要从加载的数据集中创建提示并标记它们:

 def generate_prompt(data_point):
     return f"""Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.  # noqa: E501
 ### Instruction:
 {data_point["instruction"]}
 ### Input:
 {data_point["input"]}
 ### Response:
 {data_point["output"]}"""
 
 
 def tokenize(prompt, add_eos_token=True):
     result = tokenizer(
         prompt,
         truncation=True,
         max_length=CUTOFF_LEN,
         padding=False,
         return_tensors=None,
     )
     if (
         result["input_ids"][-1] != tokenizer.eos_token_id
         and len(result["input_ids"]) < CUTOFF_LEN
         and add_eos_token
     ):
         result["input_ids"].append(tokenizer.eos_token_id)
         result["attention_mask"].append(1)
 
     result["labels"] = result["input_ids"].copy()
 
     return result
 
 def generate_and_tokenize_prompt(data_point):
     full_prompt = generate_prompt(data_point)
     tokenized_full_prompt = tokenize(full_prompt)
     return tokenized_full_prompt

第一个函数generate_prompt从数据集中获取一个数据点,并通过组合指令、输入和输出值来生成提示。第二个函数tokenize接收生成的提示,并使用前面定义的标记器对其进行标记。它还向输入序列添加序列结束标记,并将标签设置为与输入序列相同。第三个函数generate_and_tokenize_prompt结合了前两个函数,生成并标记提示。

数据准备的最后一步是将数据集分成单独的训练集和验证集:

 train_val = data["train"].train_test_split(
     test_size=200, shuffle=True, seed=42
 )
 train_data = (
     train_val["train"].map(generate_and_tokenize_prompt)
 )
 val_data = (
     train_val["test"].map(generate_and_tokenize_prompt)
 )

我们还需要数据进行打乱,并且获取200个样本作为验证集。generate_and_tokenize_prompt()函数应用于训练和验证集中的每个示例,生成标记化的提示。

训练

训练过程需要几个参数,这些参数主要来自原始存储库中的微调脚本:

 LORA_R = 8
 LORA_ALPHA = 16
 LORA_DROPOUT= 0.05
 LORA_TARGET_MODULES = [
     "q_proj",
     "v_proj",
 ]
 
 BATCH_SIZE = 128
 MICRO_BATCH_SIZE = 4
 GRADIENT_ACCUMULATION_STEPS = BATCH_SIZE // MICRO_BATCH_SIZE
 LEARNING_RATE = 3e-4
 TRAIN_STEPS = 300
 OUTPUT_DIR = "experiments"

下面就可以为训练准备模型了:

 model = prepare_model_for_int8_training(model)
 config = LoraConfig(
     r=LORA_R,
     lora_alpha=LORA_ALPHA,
     target_modules=LORA_TARGET_MODULES,
     lora_dropout=LORA_DROPOUT,
     bias="none",
     task_type="CAUSAL_LM",
 )
 model = get_peft_model(model, config)
 model.print_trainable_parameters()
 
 #trainable params: 4194304 || all params: 6742609920 || trainable%: 0.06220594176090199

我们使用LORA算法初始化并准备模型进行训练,通过量化可以减少模型大小和内存使用,而不会显着降低准确性。

LoraConfig7是一个为LORA算法指定超参数的类,例如正则化强度(lora_alpha)、dropout概率(lora_dropout)和要压缩的目标模块(target_modules)。

然后就可以直接使用Transformers库进行训练:

 training_arguments = transformers.TrainingArguments(
     per_device_train_batch_size=MICRO_BATCH_SIZE,
     gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,
     warmup_steps=100,
     max_steps=TRAIN_STEPS,
     learning_rate=LEARNING_RATE,
     fp16=True,
     logging_steps=10,
     optim="adamw_torch",
     evaluation_strategy="steps",
     save_strategy="steps",
     eval_steps=50,
     save_steps=50,
     output_dir=OUTPUT_DIR,
     save_total_limit=3,
     load_best_model_at_end=True,
     report_to="tensorboard"
 )

这段代码创建了一个TrainingArguments对象,该对象指定用于训练模型的各种设置和超参数。这些包括:

  • gradient_accumulation_steps:在执行向后/更新之前累积梯度的更新步数。
  • warmup_steps:优化器的预热步数。
  • max_steps:要执行的训练总数。
  • learning_rate:学习率。
  • fp16:使用16位精度进行训练。

DataCollatorForSeq2Seq是transformer库中的一个类,它为序列到序列(seq2seq)模型创建一批输入/输出序列。在这段代码中,DataCollatorForSeq2Seq对象用以下参数实例化:

 data_collator = transformers.DataCollatorForSeq2Seq(
     tokenizer, pad_to_multiple_of=8, return_tensors="pt", padding=True
 )

pad_to_multiple_of:表示最大序列长度的整数,四舍五入到最接近该值的倍数。

padding:一个布尔值,指示是否将序列填充到指定的最大长度。

以上就是训练的所有代码准备,下面就是训练了

 trainer = transformers.Trainer(
     model=model,
     train_dataset=train_data,
     eval_dataset=val_data,
     args=training_arguments,
     data_collator=data_collator
 )
 model.config.use_cache = False
 old_state_dict = model.state_dict
 model.state_dict = (
     lambda self, *_, **__: get_peft_model_state_dict(
         self, old_state_dict()
     )
 ).__get__(model, type(model))
 
 model = torch.compile(model)
 
 trainer.train()
 model.save_pretrained(OUTPUT_DIR)

在实例化训练器之后,代码在模型的配置中将use_cache设置为False,并使用get_peft_model_state_dict()函数为模型创建一个state_dict,该函数为使用低精度算法进行训练的模型做准备。

然后在模型上调用torch.compile()函数,该函数编译模型的计算图并准备使用PyTorch 2进行训练。

训练过程在A100上持续了大约2个小时。我们看一下Tensorboard上的结果:

训练损失和评估损失呈稳步下降趋势。看来我们的微调是有效的。

如果你想将模型上传到Hugging Face上,可以使用下面代码,

 from huggingface_hub import notebook_login
 
 notebook_login()
 model.push_to_hub("curiousily/alpaca-bitcoin-tweets-sentiment", use_auth_token=True)

推理

我们可以使用generate.py脚本来测试模型:

 !git clone https://github.com/tloen/alpaca-lora.git
 %cd alpaca-lora
 !git checkout a48d947

我们的脚本启动的gradio应用程序

 !python generate.py \
     --load_8bit \
     --base_model 'decapoda-research/llama-7b-hf' \
     --lora_weights 'curiousily/alpaca-bitcoin-tweets-sentiment' \
     --share_gradio

简单的界面如下:

总结

我们已经成功地使用LoRa方法对Llama 模型进行了微调,还演示了如何在Gradio应用程序中使用它。

如果你对本文感兴趣,请看原文:

https://avoid.overfit.cn/post/34b6eaf7097a4929b9aab7809f3cfeaa

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

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

相关文章

STM32MP157驱动开发——LED驱动(设备树)

文章目录 设备树驱动模型如何使用设备树写驱动程序设备树节点要与 platform_driver 能匹配设备树节点指定资源&#xff0c;platform_driver 获得资源 LED 模板驱动程序的改造&#xff1a;设备树驱动模型修改设备树&#xff0c;添加 led 设备节点修改 platform_driver 的源码编译…

设计模式再探——状态模式

目录 一、背景介绍二、思路&方案三、过程1.状态模式简介2.状态模式的类图3.状态模式代码4.状态模式还可以优化的地方5.状态模式的项目实战&#xff0c;优化后 四、总结五、升华 一、背景介绍 最近产品中有这样的业务需求&#xff0c;不同时间(这里不是活动的执行时间&…

前端学习——Vue (Day1)

Vue 快速上手 Vue 是什么 创建 Vue 实例 Vue2官网&#xff1a;https://v2.cn.vuejs.org/ <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge…

基于单片机的语音识别智能垃圾桶垃圾分类的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;液晶显示当前信息和状态&#xff1b;通过语音识别模块对当前垃圾种类进行语音识别&#xff1b; 通过蜂鸣器进行声光报警提醒垃圾桶已满&#xff1b;采用舵机控制垃圾桶打开关闭&#xff1b;超声波检测当前垃圾桶满溢程度&#xff1…

【目标跟踪】2、FairMOT | 平衡多目标跟踪中的目标检测和 Re-ID 任务 | IJCV2021

文章目录 一、背景二、方法2.1 Backbone2.2 检测分支2.3 Re-ID 分支2.4 训练 FairMOT2.5 Online Inference 三、效果3.1 数据集3.2 实现细节3.3 消融实验3.4 最终效果 论文&#xff1a;FairMOT: On the Fairness of Detection and Re-Identification in Multiple Object Tracki…

大模型开发(十):Chat Completion Models API 详解

全文共8000余字&#xff0c;预计阅读时间约18~28分钟 | 满满干货(附代码案例)&#xff0c;建议收藏&#xff01; 本文目标&#xff1a;详解Chat Completion Models的参数及应用实例&#xff0c;并基于该API实现一个本地知识库的多轮对话智能助理 代码&文件下载点这里 一、…

【前端|CSS系列第4篇】CSS布局之网格布局

前言 最近在做的一个项目前台首页有一个展示词条的功能&#xff0c;每一个词条都以一个固定大小的词条卡片进行展示&#xff0c;要将所有的词条卡片展示出来&#xff0c;大概是下面这种布局 每一行的卡片数目会随着屏幕大小自动变化&#xff0c;并且希望整个卡片区域周围不要…

ChatGPT 4.0 —— Code Interpreter

&#x1f4ce;产品销售数据集.csv 选取以上的数据集作为输入&#xff0c;对Code Interpreter 进行测试 1.输入指定数据集&#xff0c;要求给出该数据集的概貌 2.请分析销售的总金额和其他变量的关系 Python Script: # Import required libraries import matplotlib.pyplot a…

java项目之网络视频播放器(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的网络视频播放器。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&a…

vs2015 工程组织与动态加载

10.Visual Studio动态加载_哔哩哔哩_bilibili 1.工程组织 ① researcher.cpp #include "nn/nn.h"#include "nn/factory.h" #include "nn/factory_impl/factory_impl.h"#include <iostream>int main() {int ret 0;factory_i* fct new f…

Java实现获取客户端真实IP方法小结

Java实现获取客户端真实IP方法小结 在jsP里&#xff0c;获取客户端的IP地址的方法是&#xff1a;request.getRemoteAddr()&#xff0c;这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。如果使用了反向代理软件&am…

【数据挖掘】bytewax 与 ydata工具可实时了解您的数据

一、说明 在这篇博文中&#xff0c;我们将介绍如何将开源流式处理解决方案 bytewax 与 ydata 分析相结合并加以利用&#xff0c;以提高流式处理流的质量。 STream 处理支持在传输中和存储之前对数据进行实时分析&#xff0c;并且可以是有状态的&#xff0c;也可以是无状态的。 …

双向循环链表的基本操作(创建节点,头插,头删,尾插,尾删)

头定义&#xff1a; typedef char datatype[20];//datatypechar[20] typedef struct Node {//数据域 数据元素datatype data;//指针域 下一个节点地址struct Node* next;//指针域 上一个节点地址struct Node* prev; }*DoubleLink; 创建链表节点&#xff1a; DoubleLink crea…

轻量级Web报表工具ActiveReportsJS全新发布v4.0,支持集成更多前端框架!

ActiveReportsJS 是一款基于 JavaScript 和 HTML5 的轻量级Web报表工具&#xff0c;采用拖拽式设计模式&#xff0c;不需任何服务器和组件支持&#xff0c;即可在 Mac、Linux 和 Windows 操作系统中&#xff0c;设计多种类型的报表。ActiveReportsJS 同时提供跨平台报表设计、纯…

第五章 编程之免交互

免交互&#xff1a;不需要人为控制就可以完成的自动化操作&#xff08;自动化运维&#xff09; shell脚本和面交互是一个概念&#xff0c;但是两种写法 shell&#xff1a;默认解释器是bash 使用i/o&#xff08;输入/输出&#xff09;重定向的方式&#xff0c;将命令的列表提供…

Flask 定制日志并输出到文件

Flask 定制日志并输出到文件 定制日志器flask缺省日志器配置自定义日志器 定制日志器 flask缺省日志器配置 flask自带的日志系统&#xff0c;缺省配置dictConfig()&#xff0c;但必须在Flask()应用之前使用 # flask缺省配置 from logging.config import dictConfig dictConfig…

文心千帆大模型测评分享,效果超出预期

一、前言 现如今&#xff0c;随着ChatGPT的爆火越来越多的人开始关注人工智能领域了&#xff0c;大家都在尝试使用它来帮助自己在工作上提高效率亦或是解决一些问题。但ChatGPT是有一定的使用门槛的&#xff1a;首先需要我们“科学上网”才能访问&#xff0c;其次GPT4的价格相…

C语言库函数 — 错误信息报告函数

前言 本文介绍错误信息报告函数 错误信息报告函数的作用&#xff1a; 帮助程序员快速定位代码中的错误&#xff0c;以便更快地进行调试和修复问题。 文章目录 前言一、错误信息报告函数什么是错误信息报告函数错误信息报告函数的作用strerror函数介绍strerror函数使用错误码对应…

Data Structure, Algorithm,and Applications in C++

在学习这本书进阶内容之前&#xff0c;我们可以跟着它的第一章部分再巩固和复习。本书由Sartaj Sahni撰写&#xff0c;由王立柱和刘志红翻译。全书通俗易懂&#xff0c;内容丰富&#xff0c;是巩固C内容的不二选择。希望本文对各位有所帮助。 目录 1.函数与参数 1.1.传值参数…

C++的类型转换

文章目录 一. C语言的类型转换二. C的四种类型转换1. static_cast2. reinterpret_cast3. const_cast4. dynamic_cast 三. RTTI结束语 一. C语言的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类…