/ NLP, DEEPLEARNING

大语言模型的应用及训练

一. 大语言模型LLM

1.1 LLM的发展史

LLM(Large Language Model大语言模型)的发展起源应该是从Transformer开始,在chatGPT出现后热度达到顶峰。

整个发展的过程可以概括为三个阶段:

  • 第一阶段:真对某些领域数据单独微调,出现大量的预训练模型

  • 第二阶段:扩大模型参数及训练语料的规模,模型架构偏向于生成式模型,Prompt在微调阶段开始展现。

  • 第三阶段:模型参数和数据的规模急剧扩大,注重模型和人之间的交互。AI的安全性、可靠性更加收到关注。

1.2 开源可用的中文LLM

目前公认较好的中文开源大语言模型如下:

  • Meta AI发布的Llama系列模型,目前已经到Llama2了,推荐一个中文的Llama2仓库

  • 清华大学的chatGLM系列模型,目前已经到chatGLM2了,推荐官方的chatGLM2仓库

1.3 LLM应用的NLP任务

现在LLM基本都是生成式模型,因此一般可应用的NLP任务:

  • 翻译

  • 文本摘要

  • 阅读理解

  • 知识问答

二. LLM的训练

大语言模型训练面临最大的挑战主要有以下2方面:

  • 模型太大,一个GPU放不下

  • 数据量太大,一个GPU训练时长太长

2.1 主流的训练加速方式

目前主流的LLM训练的加速方式有以下三种:

  • 数据并行DataParallel:N个GPU上放置同一个模型(模型复制N份),将数据切分成N份。每台GPU都独立地执行前向计算过程(获得损失loss)和后向传播过程(计算梯度),之后对所有GPU上的梯度同步后进行参数更新(或直接同步更新后的参数)。

  • 流水线并行PipelineParallal:N个GPU上放置一个模型的不同layer,同一份数据(数据复制N份)。每个GPU只负责其中一部分layer的训练,数据在不同卡上流转的时候,都需要自动将数据放到对应的卡上。

  • 张量并行TensorParallel:可以理解为数据并行+流水线并行(强力推荐)。N个GPU上放置一个模型的不同layer,同时将数据切分成N份,即每个GPU上对应模型的一份layer和一份数据。

那么为什么要推荐使用张量并行的方式来进行加速呢?

无论是数据并行还是流水线并行,当模型足够大时,在前向和后向传播时,GPU之间的所需要传递的信息(包括模型的参数/梯度/优化器状态)就会很大,那么GPU之间通信所需的时间就会很长,而这段时间中其他的GPU其实是处于空置状态,很浪费资源。

2.2 DeepSpeed的ZeRO

DeepSpeed是微软的分布式框架,而它的核心就是ZeRO(Zero Redundancy Optimizer),《ZeRO: Memory Optimizations Toward Training Trillion Parameter Models》的论文地址

DeepSpeed的优势如下:

  • 支持更大参数量级的模型

  • 训练速度更快

  • 开销更少

  • 代码使用更方便,更改更少

ZeRO的三种主要优化方式:

  • 优化器状态拆分:4倍显存使用的减少,不会带来额外的通信时间。

  • 优化器状态+梯度拆分:8倍显存使用的减少,这种需要额外的通信时间来同步梯度信息。

  • 优化器状态+梯度+模型参数拆分:显存减少的量级随着GPU的个数成正相关(比如有64张卡,那么就会有64倍的显存减少),但这种也会存在最大的通信开销。

ZeRO第三种方式整体过程:

  • 前向传播(蓝色部分)

    • 将数据切分为4份 $D_0,D_1,D_2,D_3$,模型切分成4份

    • 前向传播时候,对于$D_0$的数据经过$GPU_0$后得到其模型参数$M_0$,然后将模型参数也复制到其他三张GPU上。每张GPU上针对自己的数据都会跑$M_0$的模型参数,一旦$M_0$结束,其他三张GPU删除$M_0$的参数。

    • 同上,每份数据和模型都经过上面的流程。前向过程全部结束后,针对每张GPU所代表的每份数据都要计算其loss。

  • 后向传播(橙色部分)

    • 对于$GPU_0,GPU_1,GPU_2$ 而言,在经过各自对应的数据时(这里注意所有的GPU都会存放$GPU_3$的模型参数),会短暂的保持住$M_3$的梯度信息。

    • $GPU_0,GPU_1,GPU_2$ 都会把计算得到的梯度进行累积传递到$GPU_3$上,之后会把模型参数和梯度信息都删除。

    • 同上,依次经过$GPU_2,GPU_1,GPU_0$。在梯度累加的过程中,使用优化器的参数进行更新

2.3 LLM微调

对于一般的模型进行预训练时,基本都会选择基于预训练模型对下游任务进行微调。但是面对大模型和海量数据,全参数微调明显不现实,所以就需要引入高效的微调方法PEFT(Parameter-Efficient Fine-Tuning)。然后推荐以下几种高效微调技术,都是集成在accelerate中,方便调用。

  • Adapter:Parameter-Efficient Transfer Learning for NLP,是最早发布的参数高效微调技术之一,在 Transformer 架构中添加更多层,并且只对它们进行微调,而不是对整个模型进行微调。

  • LoRA: LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS,其工作原理是修改神经网络中可更新参数的训练和更新方式。预训练神经网络的权重矩阵是满秩的,这意味着每个权重都是唯一的,不能通过组合其他权重来制作。当将预训练的语言模型调整为新任务时,权重具有较低的“内在维度”。这意味着权重可以用较小的矩阵表示,或者它具有较低的秩。这又意味着在反向传播期间,权重更新矩阵具有较低的秩,因为预训练过程已经捕获了大部分必要的信息,并且在微调期间仅进行特定于任务的调整。

  • Prompt Tuning: The Power of Scale for Parameter-Efficient Prompt Tuning,这是第一篇基于仅使用软提示进行微调的想法的论文之一。P-Tuning和Prefix Tuning的思想来自于这篇论文。

  • P-Tuning: GPT Understands, Too,方法旨在优化传递给模型的提示的表示。根据prompt来创建一个小型编码器网络,因此,在使用时候,应该创建一个prompt的提示模版。

  • Prefix TuningP-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks,P-Tuning的第二版,将可学习参数添加到所有层当中,确保了模型本身能够更多地了解正在对其进行微调的任务。与 P-Tuning 的区别在于,没有完全修改prompt嵌入,而是在Transformer的每一层提示的开头添加很少的可学习参数。它效果很好的一个重要原因是可训练参数的数量不仅限于输入序列。每一层都添加了可学习的参数,使模型更加灵活。