近日,Sebastian Raschka 又共享了一篇长文jav 巨乳,主题为《从新动手构建一个 GPT 作风的 LLM 分类器》。
著作展示了怎样将预磨真金不怕火的大型言语模子(LLM)转换为高大的文天职类器。机器之心对著作实验进行了不改变痛快的编译、整理:
为什么要存眷分类呢?着手,针对分类任务,对预磨真金不怕火模子进行微调是一个浅显灵验的 LLM 常识初学模式。其次,文天职类有很多营业期骗场景,比如:垃圾邮件检测、情怀分析、客户响应分类、主题分类等等。
阅读完本文,你将找到以下 7 个问题的谜底:
1. 需要磨真金不怕火总计层吗?
2. 为什么微调临了一个 token,而不是第一个 token?
3. BERT 与 GPT 在性能上有何比较?
4. 应该禁用因果掩码吗?
5. 扩大模子边界会有什么影响?
6. LoRA 不错带来什么蜕变?
7. Padding 也曾不 Padding?
无缺代码不错从 GitHub 找到:https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/ch06.ipynb
Different categories of finetuning
微调的不同种类
指示微结伙分类微调是最常见的言语模子微调步调。指示微调是用特定任务磨真金不怕火模子,晋升它融会和实践当然言语教唆中所姿色任务的才智,如下图 1 所示。
图 1:指示微调的两种场景。上方:模子的任务是判断文本是否为垃圾邮件;下方:模子的任务是将英词句子翻译成德语。
在分类微调中,模子被磨真金不怕火用于识别特定的类别标签,比如「垃圾邮件」和「非垃圾邮件」。分类任务还包括从图像中识别不同的植物、给新闻按体育、政事或科技等主题分类,从医学影像中远隔良性和恶性肿瘤等等。
不外历程分类微调的模子只可判断类别,不行对输入的文本作出其他判断。
快乐风男 勾引图 2:一个使用 LLM 进行垃圾邮件分类的示例。针对垃圾邮件分类微调的模子在输入时不需要稀奇的指示,探讨词,与指示微调模子比较,它的回复只但是「垃圾邮件」和「非垃圾邮件」。
指示微调的模子往往或者实践更泛泛的任务。咱们不错将分类微调的模子视为是高度专科化的模子jav 巨乳,一般来说,开导一个专用模子比开导一个在各式任务上推崇邃密的通用模子更容易。
使用预磨真金不怕火权重启动化模子
下图中展示了将通用预磨真金不怕火 LLM 蜕变为专诚用于分类任务的 LLM 需要作念的修改:
图 3:在此跳过尺度 1-5,径直参加尺度 6(将不才一节动手)。
在作念修改之前,让咱们先浅显了解一下正在使用的预磨真金不怕火 LLM。为便捷起见,假定咱们开导了如下代码来加载该模子:
model = GPTModel (BASE_CONFIG) load_weights_into_gpt (model, params) model.eval ()
在将模子权重加载到 GPT 后,使用下列文本生成的函数库,确保模子生成连贯的文本:
from chapter04 import generate_text_simple from chapter05 import text_to_token_ids, token_ids_to_text text_1 = "Every effort moves you" token_ids = generate_text_simple ( model=model, idx=text_to_token_ids (text_1, tokenizer), max_new_tokens=15, context_size=BASE_CONFIG ["context_length"] ) print (token_ids_to_text (token_ids, tokenizer))
字据以下输出,咱们不错看到模子生成了连贯的文本,这标明模子权重已正确加载:
Every effort moves you forward. The first step is to understand the importance of your work
让咱们先望望模子是否不错通过指示微调完成垃圾邮件的分类:
text_2 = ( "Is the following text'spam'? Answer with 'yes' or 'no':" "'You are a winner you have been specially" "selected to receive $1000 cash or a $2000 award.'" ) token_ids = generate_text_simple ( model=model, idx=text_to_token_ids (text_2, tokenizer), max_new_tokens=23, context_size=BASE_CONFIG ["context_length"] ) print (token_ids_to_text (token_ids, tokenizer))
模子的输出如下所示:
Is the following text'spam'? Answer with 'yes' or 'no': 'You are a winner you have been specially selected to receive $1000 cash or a $2000 award.' The following text'spam'? Answer with 'yes' or 'no': 'You are a winner
不错较着看出模子在准确撤职指示方面碰到了一些挑战。这是不错料念念的,因为它仅历程了预磨真金不怕火,空泛指示微调。
加入分类头
咱们将原始输出层(这层的功能是将模子里面生成的荫藏示意调解为一个包含 50,257 个 tokens 的词表)替换为一个较小的输出层,该层映射到两个类别:0(非垃圾邮件)和 1(垃圾邮件),如下图 4 所示。
图 4:此图展示了怎样通过改变架构将 GPT 模子适配为垃圾邮件分类。着手,模子的线性输出层将 768 个荫藏单位映射到一个包含 50,257 个 tokens 的词汇表。为了进行垃圾邮件检测,这一层被替换为一个新的输出层,该层将疏浚的 768 个荫藏单位映射到两个类别,分别示意「垃圾邮件」和「非垃圾邮件」。
输出层节点
从时代上讲,因为这是一个二元分类任务,不错只用一个输出节点。探讨词,这将需要修改亏本函数。因此,咱们选拔一种更通用的步调,匹配输出节点与分类的数目。举例,关于一个分三类的问题,如将新闻著作分类为「科技」、「体育」或「政事」,使用三个输出节点,以此类推。
在尝试进行图 4 中所示的修改之前,先通过 print (model) 输出模子架构:
GPTModel ( (tok_emb): Embedding (50257, 768) (pos_emb): Embedding (1024, 768) (drop_emb): Dropout (p=0.0, inplace=False) (trf_blocks): Sequential ( ... (11): TransformerBlock ( (att): MultiHeadAttention ( (W_query): Linear (in_features=768, out_features=768, bias=True) (W_key): Linear (in_features=768, out_features=768, bias=True) (W_value): Linear (in_features=768, out_features=768, bias=True) (out_proj): Linear (in_features=768, out_features=768, bias=True) (dropout): Dropout (p=0.0, inplace=False) ) (ff): FeedForward ( (layers): Sequential ( (0): Linear (in_features=768, out_features=3072, bias=True) (1): GELU () (2): Linear (in_features=3072, out_features=768, bias=True) ) ) (norm1): LayerNorm () (norm2): LayerNorm () (drop_resid): Dropout (p=0.0, inplace=False) ) ) (final_norm): LayerNorm () (out_head): Linear (in_features=768, out_features=50257, bias=False) )
如上所示,GPTModel 由镶嵌层和 12 个疏浚的 transformer 块构成,为粗略起见,仅判辨临了一个块,然后是最终的 LayerNorm 和输出层 out_head。
接下来,咱们将 out_head 替换为一个新的输出层,如图 4 所示,咱们将对这一层进行微调。
选拔微调特定层与微调总计层
咱们无须对模子每一层进行微调,因为神经收罗的较低层捕捉到的基本的言语结构和语义是通用的,不错在很多不同的任务和数据齐集阐扬作用。
因此,咱们仅微调临了几层(集结输出的层)就够了,这些层更具体于隐微的言语模式和任务特征。这种步调在计较上也将愈加高效。
为了准备进行分类微调,着手咱们冻结模子,行将总计层开导为不可磨真金不怕火:
for param in model.parameters (): param.requires_grad = False
然后,如图 4 所示,咱们修改输出层 model.out_head :
torch.manual_seed (123) num_classes = 2 model.out_head = torch.nn.Linear ( in_features=BASE_CONFIG ["emb_dim"], out_features=num_classes )
贵重,在上述代码中,咱们使用了 BASE_CONFIG ["emb_dim"],它的值在 “gpt2-small(124M)” 模子中为 768。这么作念的目的是为了让后续的代码愈加通用,疏浚的代码也能管理其他型号的 GPT-2 模子。
新的 model.out_head 输出层的 requires_grad 属性默许开导为 True,这意味着这是模子中独一会在磨真金不怕火时分更新的层。
从时代上讲,只磨真金不怕火刚刚添加的输出层就富余了。探讨词,我在实验中发现,微调稀奇的层,不错显耀晋升微调模子的瞻望性能。
此外,咱们将临了一个 transformer 块以及流畅该块与输出层的 LayerNorm 模块开导为可磨真金不怕火,如图 5 所示。
图 5:用我的尺度开导的 GPT 模子包含 12 个重迭的 transformer 块。除了输出层,咱们将临了的 LayerNorm 和临了一个 transformer 块开导为可磨真金不怕火,而其余 11 个 transformer 块和镶嵌层保执为不可磨真金不怕火。
为了作念到这点,咱们将它们各自的 requires_grad 开导为 True:
for param in model.trf_blocks [-1].parameters (): param.requires_grad = True for param in model.final_norm.parameters (): param.requires_grad = True
尽管咱们添加了一个新的输出层,并将某些层开导为不可磨真金不怕火,咱们仍然不错使用这个模子。举例,咱们不错像之前那样输入一段示例文本:
inputs = tokenizer.encode ("Do you have time") inputs = torch.tensor (inputs).unsqueeze (0) print ("Inputs:jav 巨乳