LLM微调:训练一个垃圾邮件分类器-大模型炼丹术(七)
截止到现在,我们已经完成了LLM的整体架构搭建,是时候使用它来做一些下游的任务了。
我们所构建的LLM是GPT2,官方开源了它的预训练权重。如果只是使用GPT2实现文本续写等功能,可以直接加载预训练模型并进行推理。
然而,在实际的任务中,往往需要使用领域数据对LLM进行微调,以适配特定的下游任务,比如垃圾短信分类、对话生成、情感分析等。
本文使用一个垃圾邮件分类的任务,来说明如何基于预训练的GPT2在邮件数据集上进行微调,我们的目标是打造一个垃圾邮件分类器,输入一份邮件的内容,模型给出该邮件是否为垃圾邮件的分类结果。
一、准备垃圾邮件分类数据集在https://archive.ics.uci.edu/static/public/228/sms+spam+collection.zip下载垃圾邮件分类数据集,如下:
每一行是一个样本,其中第一列是label,空格后面的是label对应的邮件内容,label总共有两个值,表示这封邮件是否为垃圾邮件。
为乐便于后续数据预处理,将其读取为pandas的数据框格式:
12data_file_path = "sms_spam_collect ...
剖析LLM的解码策略-大模型炼丹术(六)
在使用训练好的LLM进行自回归预测下一个token时,我们会选择预测序列中最后一个token对应的预测tensor,作为解码操作的对象。
1234567# 获取模型的预测结果with torch.no_grad(): # 关闭梯度计算,加速推理 logits = model(idx_cond) # (batch, n_tokens, vocab_size)# 只关注最后一个时间步的预测结果# (batch, n_tokens, vocab_size) 变为 (batch, vocab_size)logit = logits[:, -1, :]
此时的logit就是用于解码的tensor,batch中的每一个都对应词汇表长度大小vocab_size的一个向量。
如何对该向量进行解码,得到要预测的下一个单词呢?本文介绍几种不同的解码策略。
一、贪心解码我们之前的解码策略是直接给logit应用softmax函数,然后使用argmax取概率值最大的数值对应的索引作为预测的下一个token ID,最后根据token ID在词汇表中查找得到预测的下一个单词:
1next_token ...
LLM自回归预训练过程详解-大模型炼丹术(五)
在前面的4篇文章中,我们已经完成了整个数据流向所需的模块构建,包括tokinizer,embedding,注意力机制,并串联得到了GPT2这个LLM架构。
现在,是时候准备开始训练我们的LLM了。
相比于前面发布的4篇文章,本文将更加偏重于代码实战。
一、准备自回归预训练数据集在开始编写训练脚本之前,我们需要先构建训练所需数据集。这里使用the-verdict.txt,这是在本系列一开始就作为示例使用的一本书。
1234567891011121314import osimport urllib.requestfile_path = "the-verdict.txt"url = "https://raw.githubusercontent.com/rasbt/LLMs-from-scratch/main/ch02/01_main-chapter-code/the-verdict.txt"if not os.path.exists(file_path): with urllib.request.urlopen(url) as response: ...
动手搭建GPT2架构-大模型炼丹术(四)
在前面的3篇文章中,我们已经讲解了训练LLM所需的tokenizer,token/position编码,以及Transformer核心:注意力机制。现在是时候动手搭建GPT的网络架构了。
本文首先搭建GPT架构包含的🧍各个小组件,然后将这些组件串联起来,得到最终的GPT架构。
下图左侧是整个GPT2的架构图,中间是Transformer Block,右侧是我们之前实现的多头注意力层。
我们要搭建的是GPT-2,具有124M的参数量,相关的配置文件先放这儿:
123456789GPT_CONFIG_124M = { "vocab_size": 50257, # Vocabulary size "context_length": 1024, # Context length "emb_dim": 768, # Embedding dimension "n_heads": 12, # Number of attention heads ...
从单头到多头,深度解析大模型的注意力机制-大模型炼丹术(三)
在之前的两节内容中,我们已经将输入的句子通过tokenizer映射到了一个个的token ID,并进一步做了连续编码,得到了包含充分语义信息的embedding向量。
现在,让我们继续探索接下来的数据流向。
GPT模型的架构是一个类似Transformer解码器架构的网络,因此本文将从Transformer的核心组件“注意力机制”开始讲起。
一、 直观理解注意力这里通过一个例子展示来直观展现什么是注意力:使用前两节所讲的内容,假设已经将”Your journey starts with one step”这句话编码到embedding空间,embedding维度是3,如下:
12345678inputs = torch.tensor( [[0.43, 0.15, 0.89], # Your (x^1) [0.55, 0.87, 0.66], # journey (x^2) [0.57, 0.85, 0.64], # starts (x^3) [0.22, 0.58, 0.33], # with (x^4) [0.77, 0.25, 0.10], ...
从离散的token IDs到具有语义信息的embedding-大模型炼丹术(二)
在完成了tokenization之后,我们已经可以将一个个的单词映射到对应的数字,称之为token ID,这些数字已经可以被计算机处理。然而,若直接将这些数字应用于模型训练,仍存在一些问题:
缺乏语义信息: Token ID 只是一个索引,本身不包含任何语义信息。例如,“cat” 可能被映射为 ID 1254,而 “dog” 是 ID 3920,这两个 ID 之间的数值关系是无意义的。直接使用它们可能会导致模型误解 token 之间的关联性。
整数之间的数值关系会误导模型: 机器学习模型通常会学习数据之间的模式。如果直接输入 token ID,模型可能会误以为 ID 1254(”cat”)和 ID 3920(”dog”)之间存在某种数学关系(如加减乘除),但实际上 ID 只是索引,没有数值上的逻辑关系。
无法捕捉相似 token 的关系 语义相近的 token 在 embedding 空间中应该具有接近的表示。例如,”king” 和 “queen” 应该在高维空间中比较接近,而 “apple” 和 “computer” 应该相距较远。然而,单纯的 token ID 无法提供这种分 ...
从tokenizer说起,为LLM自回归预训练准备数据集-大模型炼丹术(一)
本文首先介绍了如何从头开始实现一个自定义tokenizer,用于将原始文本数据转化为模型能够理解的格式。通过这个例子,来直观理解什么是tokenize;接着,分析这种tokenizer的优缺点,引出更常用的BPE;最后,基于BPE构建的tokenizer,构建用于GPT预训练时的数据加载器。
在阅读完本文后,你将学会如何构建用于GPT自回归预训练阶段的数据加载器,这将是你向着LLM训练迈出的第一步!
一、先动手,编写自定义tokenizerstep1. 读取语料读取the-verdict.txt:
12345with open("the-verdict.txt", "r", encoding="utf-8") as f: raw_text = f.read() print("Total number of character:", len(raw_text))print(raw_text[:99])
输出:
12Total number of character: 20479I HAD alwa ...
把数据预处理搬到GPU-英伟达DALI加速数据预处理
在执行模型前向推理时,往往涉及到一些列数据预处理操作,比如Resize,Normalize等,这些操作通常在CPU上完成,然后CPU将预处理后的图片传送到GPU上执行推理。
由于GPU的运算速度远快于CPU,所以能不能将这些数据预处理操作放到GPU上执行从而加快数据加载的速度呢?
NVIDIA DALI 可以!
NVIDIA DALI (Data Loading Library) 是一个加速数据加载和预处理的库,专为深度学习任务设计。它能将图像和视频的复杂预处理操作(尤其是在模型训练阶段,通常涉及大量的数据增强预处理操作)从 CPU 转移到 GPU 上,从而减少数据加载瓶颈,提升 GPU 的利用率。DALI 支持多种格式(如 JPEG、PNG、TFRecord 等),并能与主流深度学习框架(如 PyTorch 和 TensorFlow)无缝集成,使得数据预处理和模型前向推理可以高效并行进行。
本文介绍DALI的使用方法,以及如何将PyTorch的数据加载器替换成DALI的数据加载器,并测试加速效果。
安装NVIDIA DALI对于CUDA 11.x,执行如下命令行:
1pip inst ...
无题
.anticon {
display: inline-block;
color: inherit;
font-style: normal;
line-height: 0;
text-align: center;
text-transform: none;
vertical-align: -0.125em;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.anticon > * {
line-height: 1;
}
.anticon svg {
display: inline-block;
}
.anticon::before {
display: none;
}
.anticon .anticon-icon {
display: block;
}
.anticon[tabindex] {
cursor: pointer;
}
.ant ...
万字长文入门扩散模型
扩散模型问世至今,因其训练过程的稳定性和生成样本的多样性,受到了广泛的关注和应用,相应的开源社区贡献的工具链也趋向于更易用,HuggingFace的diffusers库便是其中之一。
diffusers提供了非常简洁和直观的API接口,能够让研究人员和开发者快速实现扩散模型的训练和推理。即便是对扩散模型不太熟悉的用户,也能通过少量的代码实现高效的图像生成任务。
本文基于diffusers,包含如下内容:
1.通过一个简易demo来直观感受使用diffusers中的快速生图的方法
2.使用smithsonian_butterflies_subset数据集,通过diffusers来搭建一个完整的图像生成小项目,包括数据集准备、模型训练、模型推理等步骤
3.介绍如何基于已有的预训练权重,通过微调和引导技术,来控制生成图片整体的细节走向,如颜色偏好,内容偏好等
4.介绍火出圈的StableDiffusion
5.介绍DDIM反转,用于控制图像的局部区域生成细节走向,该技术极大地提高了扩散模型的可玩性
零. 准备工具函数首先,导入常用的库,并编写后续将被重复使用的工具函数,用于图像可视化。
12 ...