微调LLaMA 7B
一 . self-instruct 方式
方法简介:
Stanford Alpaca 是斯坦福团队提出的一种结合中英文语料,通过 Self-Instruct 方式微调 LLaMA 7B 大模型的方法。该方法通过收集和构建高质量的指令-响应数据集,使微调后的 LLaMA 7B 在单轮对话任务上表现优于 GPT-3.5(text-davinci-003)。
数据集构建流程
- 数据来源:主要基于斯坦福团队发布的52K条英文指令数据(Alpaca数据集),并对部分数据进行了中文翻译和表达方式优化。
- 数据格式:每条数据为一个字典,包含以下字段:
- instruction:任务描述,指明模型应执行的操作(唯一)。
- input:任务上下文或输入内容(可选)。
- output:由GPT-3.5 API(text-davinci-003)生成的标准答案。
- 数据集地址:
https://raw.githubusercontent.com/tatsu-lab/stanford_alpaca/main/alpaca_data.json
具体实现流程:
1. ⼈⼯设计 175 个任务,每个任务都有对应的 { 指令 输⼊ 输出 / 实例 } 或 { 指令 输出 / 实例 } ,将这 175 个任务数据作为种⼦集;
2. 调用模型API或者本地模型生成指令,使用种子集作为上下文示例申城更多的指令;
3. 定义该模型生成的指令判断是都分类任务;
4. 使用模型生成实例;
5. 对上述模型申城的数据{指令 输入 输出/实例}过滤低质量或相似度高的;
6.讲经过过滤和后处理的数据添加到种子池中
重复以上2-6直到种子池有更多的数据;
主要生成数据的程序如下:
"""
batch_selfinstruct_generate.pyrun:
python -m generate_instruction generate_instruction_following_data \--output_dir ./ \--num_instructions_to_generate 10 \--model_name="text-davinci-003" \
"""
import time
import json
import os
import random
import re
import string
from functools import partial # 引入偏函数模块
from multiprocessing import Pool # 引入多进程模块import numpy as np
import tqdm
from rouge_score import rouge_scorer # 引入rouge评分器,用于文本相似度计算
import utilsimport fire #用于命令行参数解析# 将多个提示指令编码成单⼀字符串的函数
def encode_prompt(prompt_instructions):"""Encode multiple prompt instructions into a single string."""prompt = open("./prompt.txt").read() + "\n"for idx, task_dict in enumerate(prompt_instructions):(instruction, input, output) = task_dict["instruction"], task_dict["input"], task_dict["output"]instruction = re.sub(r"\s+", " ", instruction).strip().rstrip(":")input = "<noinput>" if input.lower() == "" else inputprompt += f"###\n"prompt += f"{idx + 1}. Instruction: {instruction}\n"prompt += f"{idx + 1}. Input:\n{input}\n"prompt += f"{idx + 1}. Output:\n{output}\n"prompt += f"###\n"prompt += f"{idx + 2}. Instruction:"return prompt# 对GPT-3响应进⾏后处理的函数,抽取⽣成的新指令
def post_process_gpt3_response(num_prompt_instructions, response):if response is None:return []raw_instructions = f"{num_prompt_instructions+1}. Instruction:" + response["text"]raw_instructions = re.split("###", raw_instructions)instructions = []for idx, inst in enumerate(raw_instructions):# if the decoding stops due to length, the last example is likely truncated so we discard itif idx == len(raw_instructions) - 1 and response["finish_reason"] == "length":continueidx += num_prompt_instructions + 1splitted_data = re.split(f"{idx}\.\s+(Instruction|Input|Output):", in