0%

随着各大语言模型的开源,很多研究在没有计算资源的情况下,唯一可想的办法就是在各大开源模型上利用垂直领域的数据集来finetune开源大模型,充分利用pretrained模型的能力,而又能让它解决特定的任务。 斯坦福的羊驼alpaca模型的发布掀起了instruction tuning的一阵狂潮,国内很多工作也在模仿Stanford这个工作方法做自己领域的大模型,其实在接触这些工作的时候我一直有一个疑问,就是什么时候我们该finetune?手里有多少数据的时候你可以finetune。

如果我们要开展微调,数据以及如何组织数据形式和微调的方式是两个主要问题。

微调的方式

现有的LLM规模太大,因此完全微调模型已并非易事。因此无论学界还是业界都需要一种高效的方法在下游任务数据上训练,这就为参数高效微调(Parameter-efficient fine-tuning,PEFT)带来了研究空间。PEFT的目的是只训练一小部分参数(可以是大模型自身的,也可以是额外引入的)就能提升模型在下游任务的效果。

Scaling Down to Scale Up: A Guide to Parameter-Efficient Fine-Tuning 一文总结了现有peft的主要方法,并做了分类:

PEFT methods分类

可以看到lora也就是我们现在经常用到的微调手段被分配到了reparametrization-based里面。并且在additive这个分类里,又分了两个子类:adapter-like和soft prompts。对于每一个分类的解释可以看paper或者参考这篇知乎博客

我这里只做简单的对比:

  • prefix tuning,prompt tuning根本就是为了解决人工为每一个任务构造prompt太过于随机性,而且构造的模板有时候是离散化的;另外一个痛点就是如果对模型在下游任务上进行全参数调整,每一个任务得保存一份参数副本,对存储和训练都是考验。所以这一类方法就是让模型通过学习来自动寻找最合适的prompt,称之为soft prompt.LLM那一部分的参数不做调整,只调整添加的这一部分参数。之后清华大学提出的ptuning和ptuning v2版本,可以简单的将P-Tuning认为是针对Prompt Tuning的改进,P-Tuning v2认为是针对Prefix Tuning的改进。
  • lora这一类方法(AdaLoRA,Qlora)基于的理论是:将LLM在下游任务进行微调时发现改变的参数都是哪些低秩矩阵,所以这些方法重构了一种低秩矩阵运算,这些矩阵里面的参数就可以代表下游任务的知识,这样将LLM的预训练参数和这部分参数进行合并之后就可以适配下游任务了。

微调实践Applications

这一章节主要介绍一些值得关注的微调实践工作,可以给我们在实际工作中提供一些微调的思路,比如看看别人数据集是如何组织的,有多少的数据量,针对什么任务有了performance的提高,还有做evaluation是咋做的。

Stanford Alpaca

这是开创instruction tuning工作的鼻祖,而且斯坦福的代码写的很优秀,特别是用GPT3生成instruction-input-output那一部分,把代码通读一遍可以加深self-instruct方法的理解。而且斯坦福的这个数据集只有52k条,但是有意思的是它在组织这52k条数据的时候是需要充分保持task的多样性的,毕竟我们知道instruction tuning当时在 Finetuned Language Models Are Zero-Shot Learners 文中被提出的时候,其实是为了提高模型在unseen task上的zero-shot能力,它有一个重要的前提是finetune的task要多样,这个非常重要!

现在有一些国内的工作就是直接弄了一些数据就开始finetune,然后叫自己是instruction tuning,我觉得不太合理。

最近出了一个工作: LIMA: Less Is More for Alignment,在LLaMa-65B基础上用1000条instruction数据训练的模型,在43%的情况下,LIMA可以超过或者和GPT4平齐,这真的很厉害了,毕竟只用了1000条数据,而且作者也用斯坦福的方法复刻了52k微调llama-65B的大羊驼,发现还是LIMA优秀一点,作者猜测是因为数据集质量,这1000条数据是精心策划的。

Chatglm-6B p-tuning

基于chatglm-6B的微调项目超级多,chatglm有天然的中文优势,所以国内好多语言模型都是基于清华的这个语言模型做的工作。chatglm-6B给出的官方github repo中包含了p-tuning v2的代码, p tuning v2的原理就是将应该人工写的那一部分prompt用参数来学习,LLM预训练好的那一部分参数固定住,只更新添加的这部分参数。参考chatglm-6B自己给出的再ADGEN(广告生成的数据集)上finetuneg chatglm6B的代码: https://github.com/THUDM/ChatGLM-6B/tree/main/ptuning, 这部分代码的数据组织部分蛮有意思的,数据集长这样:

1
2
3
4
{
"content": "类型#上衣*版型#宽松*版型#显瘦*图案#线条*衣样式#衬衫*衣袖型#泡泡袖*衣款式#抽绳",
"summary": "这件衬衫的款式非常的宽松,利落的线条可以很好的隐藏身材上的小缺点,穿在身上有着很好的显瘦效果。领口装饰了一个可爱的抽绳,漂亮的绳结展现出了十足的个性,配合时尚的泡泡袖型,尽显女性甜美可爱的气息。"
}

也就是不像alpaca数据集有instruction了,只是一个映射关系,而且在main.py训练代码里也没有见到处理数据sample时要给每一个数据前加instruction,唯一加的就是在content前加了一个“问:”,在summary前加了一个“答:”。

Gorilla

这是一个微调LLaMa-7B让LLM实现用语言方式让LLM返回API调用代码的工作。

参考:

image-20230608133459274

产生数据集的方式跟alpaca如出一辙,利用了self-instruct方式,让GPT-4来产生instruction-API的训练数据。而且它分了两种模式来训练,一种是有retriever的模式,在instruction中添加了数据库里关于这个API的帮助信息,一种就是instruction-API的格式。因为repo里并没有开源这部分的训练数据,所以我们也只能看论文来猜测数据是长这样的,等作者公布了数据可以再补充这部分数据到底长什么样子。

我们在使用这个model进行推理时,输入给他的就是一串我呢本,告诉它你想获得一个怎么样的API,比如“I would like to identify the objects in an image”或者更模糊一点:“I am going to the zoo, and would like to track animals”。在zero-shot模式下这个instruction会直接给到gorilla,模型会给你返回一串API调用的代码,像这样:

image-20230608134439167

总体来说这个项目想法蛮有意思的,就是很多东西暂时还没开源,我们拭目以待吧,现在就用用就行。

让LLM适配specific的下游任务,两条线:1. 在prompt engineering上下功夫 2. Fine-tune LLM. 其实这两条线并不分家,中间也有一些技术是有overlap的。prompt engineering并不只是手动设计prompt让LLM返回更好的结果,使得其在下游任务中得以使用,一些研究并不想自己手动设计prompt,那就产生了很多自动产生prompt的方式。刘鹏飞博士的review文章Pre-train, Prompt, and Predict: A Systematic Survey of Prompting Methods in Natural Language Processing将这些技术统一到一个体系里来,分类方式也比较清晰:

characteristics of different tuning strategies

Full Fine-tune(Promptless Finetune)

Bert就是一个典型的应用,将模型在一个很大的语料库上pretrain之后,再在一些任务的数据集上对模型参数进行调整。注意这里模型的所有参数都会进行调整。

image-20230519142832464

对所有模型参数调整就带来很多问题:

  • 要维护每一个task上的模型,有一些模型的参数量都是亿级别的,这对存储是一个考验
  • finetune所有参数就需要数据集达到一定的数量级,这在特定领域不一定是可以达到的;如果没有很多数据,有可能finetune完之后还会引起perfomance的下降或者过拟合。
  • 计算资源的限制

More Efficient Ways of Tuning

或许有更合适的tuning方式,less overfitting and more efficient finetuning and inference

Prefix-Tuning

Prefix-Tuning: Optimizing Continuous Prompts for Generation

prefix Tuning

一开始理解prefix tuning其实是从“如果不调整所有参数,那么是不是可以调整部分参数”来思考这个模型的。但是看了原文之后会发现作者的思考路径其实有点不太一样。paper中说

Prefix-tuning draws inspiration from prompting, allowing subsequent tokens to attend to this prefix as if it were “virtual tokens”

lilian的博客对于这个也解释的蛮有意思:

Prompt is a sequence of prefix tokens that increase the probability of getting desired output given input. Therefore we can treat them as trainable parameters and optimize them directly on the embedding space via gradient descent, such as AutoPrompt (Shin et al., 2020, Prefix-Tuning (Li & Liang (2021)), P-tuning (Liu et al. 2021) and Prompt-Tuning (Lester et al. 2021). This section in my “Controllable Neural Text Generation” post has a good coverage of them. The trend from AutoPrompt to Prompt-Tuning is that the setup gets gradually simplified.

也就是既然我们发现in-context learning是可以促进大语言模型解决特定问题(因为我们让LLM以更高的概率输出我们想要的结果了),那么是不是可以可以把这一部分信息编码进模型参数里,从而在特定地数据集上单独训练这些参数。

所以研究者也想了一些办法如何以最小的成本为特定的任务增加一些参数,fix住预训练模型的大部分参数,而去finetune给每一个任务增加的那一部分参数。其中adapter-tuning就是一种。

在LLM兴起之后,很多工作都在如果更好的设计prompt的形式上下了很多苦功夫,设计提示词的这个学问就是prompt engineering。我之前一直觉得这是一个静态的过程,建议刚接触的同学先学习吴恩达和openai合作制作的prompt engineering的知道课程,另外也有中国热心的网友也翻译了自己的中文版本,还加入了一些自己的思考,推荐骆驼

我是从斯坦福的羊驼模型开始接触instruction tuning的,instruction tuning提供给了用户一种在特定数据集上低成本finetune模型的可能性,后来又接触到了斯坦福新出的paper:Demonstrate-Search-Predict: Composing retrieval and language models for knowledge-intensive NLP,这是一篇用信息抽取技术retrieval models来扩充query,从而使得LM能够得到更多context的技术,这才让我了解到其实除了最基础的我们知道的那些prompting的方式,比如zero-shot,few-shot,chain-of-thought方式,还有一些方式在这些方式上进行了创新。

lilian weng的博客在chiin-of-thought章节之后就介绍了自动prompt design和augmented language models。这些对于我来说都是新东西,新技术发展的很快,我学习的过程其实也是在织自己知识结构中的这个网,从接触GPT以来写了好几篇博客,零零散散的,很多博客都是只局限于其中的技术,时不时我需要停下里思考这些技术之间的关联,从而把整个逻辑理顺。技术的发展或者一个模型一个方法的出现都是有路径可循的,我希望能把这些路径穿起来,摸清楚发展脉络。

Augmented Language Models

本节参考review,我之前理解augmented llm有点狭隘,最基本的方法是从一个知识库或者搜索引擎中搜索query相关的内容,将这些内容加到prompt里,从而一定程度上解决大模型的幻觉问题,这种思路的典型应用见Internet-augmented language models through few-shot prompting for open-domain question answering. 但上面提到的这篇review把问题更细化一点,从更高的维度去分析现在的这些方法,第一个就是reasoning,也就是把复杂问题如何细化成LLM可以解决的简单问题,第二个是Tools,也就是我们上面介绍的应用的场景,tool帮我们抽取相关信息(document retriever)。关于更具体地解释可以阅读review地1.2节。

Useful Links