Let's build GPT: from scratch, in code, spelled out.
如何理解ChatGPT的工作原理
ChatGPT简介
- 介绍了ChatGPT作为一个与AI互动的系统,能够执行基于文本的任务,例如创作关于AI重要性的俳句。
- 演示了ChatGPT生成不同结果的能力,显示其为概率性系统,可以对同一提示产生多种回答。
ChatGPT的语言模型特性
- 强调了ChatGPT是一个语言模型,通过建模单词或字符序列来完成给定的文本序列。
- 提供了一些有趣的提示示例,展示用户如何利用ChatGPT进行幽默和创造性的写作。
Transformer架构的重要性
- 讨论了支撑ChatGPT运作的神经网络及其基础——2017年的《Attention is All You Need》论文,该论文提出了Transformer架构。
- 阐述了Transformer在机器翻译中的应用,以及它如何在接下来的五年内影响整个AI领域。
构建简化版语言模型
- 表达了希望构建类似于ChatGPT但更简单版本的愿望,并指出训练过程复杂,需要大量互联网数据。
- 提出了使用“Tiny Shakespeare”数据集进行训练,以便更好地理解字符级别语言模型。
模型训练与生成文本
- 描述了如何通过分析角色之间的关系来预测下一个字符,从而生成类似莎士比亚风格的文本。
- 展示了经过训练后生成无限莎士比亚风格文本的方法,并解释该过程与ChatGPT相似,但以字符为单位进行预测。
Nano GPT项目概述
- 介绍Nano GPT,这是一个用于训练Transformer的小型GitHub项目,包含两份300行代码文件,用于定义和训练模型。
如何从零开始构建一个Transformer模型
训练与数据集
- 使用开放的Web文本数据集进行训练,这是一个相当大的网页数据集,成功重现了GPT-2的性能。GPT-2是OpenAI在2017年发布的早期版本。
- 本次讲座将从头开始编写代码库,逐步定义Transformer,并使用小型莎士比亚数据集进行训练,以生成无限的莎士比亚文本。
理解ChatGPT的工作原理
- 目标是让观众理解和欣赏ChatGPT背后的工作原理,只需具备Python基础知识以及一些微积分和统计学知识即可。
- 创建新的Google Colab Jupyter笔记本,以便于后续共享开发的代码,方便观众跟随学习。
数据处理与字符编码
- 下载小型莎士比亚数据集,文件大小约为1MB,并读取文本内容,总字符数大约为100万。
- 打印出前1000个字符以确认读取正确,这些字符基本符合预期。
词汇表与标记化策略
- 利用Python中的set构造函数获取文本中所有出现过的字符,并创建有序列表,从而确定词汇表大小,共有65个可能字符,包括空格、特殊字符及大小写字母。
- 开发输入文本的标记化策略,将原始字符串转换为整数序列,以便于模型处理。采用基于字符级别的语言模型,将单个字符翻译成整数。
编码与解码过程
- 构建编码器和解码器,通过迭代所有字符创建查找表,实现字符串到整数列表及其反向映射。
- 提到多种可能的编码方式,例如Google使用句子片段(SentencePiece)作为子词单位级别标记器,而OpenAI则使用名为Tick Token的库来实现对话生成。
子词编码与实践应用
- 在实际应用中,通常采用子词编码方法,可以在较小词汇表下获得更长序列或在较大词汇表下获得短序列。
如何使用PyTorch处理莎士比亚文本数据
数据集准备与编码
- 使用PyTorch库中的
torch.tensor将莎士比亚的文本数据编码为整数序列,形成数据张量。
- 观察到前1000个字符被转换为一个庞大的整数序列,其中每个整数代表特定的字符,例如0可能表示换行符,1可能表示空格。
数据集划分
- 将数据集分为训练集和验证集,前90%作为训练数据,后10%作为验证数据,以评估模型是否过拟合。
- 验证数据用于确保神经网络生成类似莎士比亚风格的文本,而不是简单地记忆原始文本。
Transformer模型训练
- 在训练Transformer时,不会一次性输入整个文本,而是随机抽取小块进行训练,以降低计算成本。
- 每次训练时只处理固定长度的数据块(称为“块大小”),以提高效率并适应GPU的并行处理能力。
示例与上下文理解
- 以块大小8为例,从训练集中提取9个字符,这些字符中包含多个示例,每个位置都可以预测下一个字符。
- 在9个字符中,有8个独立示例,通过上下文来预测下一个字符,例如在“1847”之后预测“56”。
批量维度与效率
- 为了提高效率,在输入Transformer时,会将多个小块堆叠成一个张量进行批量处理,但这些小块之间是独立的。
如何在Transformer中处理输入数据
随机数生成与批处理大小
- 在随机数生成器中设置种子,以确保每次运行时看到的数字一致。
- 批处理大小决定了每次前向和反向传播过程中处理的独立序列数量,最大上下文长度用于预测。
数据分割与随机偏移
- 生成随机偏移量以从训练集中抓取数据块,这些偏移量是在0到数据长度减去块大小之间随机生成的。
- 输入X是从这些随机位置提取的字符块,而目标Y则是相应位置上加一后的字符。
张量构建与输入格式
- 将所有一维张量堆叠成一个四行八列的张量,形成一个包含32个独立示例的批次。
- 每个输入对应于目标数组中的正确答案,确保Transformer能够同时处理所有示例并进行预测。
简单神经网络实现
- 开始使用最简单的神经网络——二元语言模型,并直接实现PyTorch模块。
- 创建一个二元语言模型类,并传入输入和目标进行初始化。
嵌入层与预测逻辑
- 使用nn.embedding创建词嵌入表,每个整数索引对应于嵌入表中的一行。
- 通过时间和通道将嵌入结果排列为张量,以便进行下一个字符的预测。
损失函数评估
- 使用负对数似然损失(交叉熵)来评估预测质量,测量logits与目标之间的一致性。
如何处理PyTorch中的交叉熵损失
PyTorch交叉熵的输入要求
- 在调用PyTorch的交叉熵函数时,虽然我们希望直接使用其功能形式,但会遇到错误信息。
- PyTorch期望多维输入的通道维度为第二个维度,因此需要将形状从B x T x C调整为B x C x T。
重塑张量以符合要求
- 通过给维度命名并重塑logits,使其变为二维数组,以便更好地符合PyTorch对维度的期望。
- 将logits重塑为B x (T*C),这样可以保持通道维度作为第二个维度。
目标张量的处理
- 目标张量当前形状为B x T,需要将其转换为一维,即B*T。
- 使用负数来让PyTorch自动推断目标形状,这样在重塑后就能匹配交叉熵计算。
损失评估与模型生成
- 当前损失值为4.87,预期损失约为4.1217,表明初始预测不够分散,有一定的信息熵。
- 模型能够在某些数据上评估质量,并且接下来将进行文本生成。
文本生成过程
- 生成函数负责扩展输入,从B x T扩展到B x (T+1)+(T+2)+(T+3),以实现批次和时间维度上的生成。
- 预测结果会被连接到之前的idx上,形成新的idx,以便继续生成更多内容。
概率采样与索引更新
- 在生成过程中,仅关注最后一步的logits,将其转化为概率,然后使用torch.multinomial进行采样。
- 每个批次中只获取一个预测结果,最终形成一个新的p x (T+1)。
可选目标处理与模型测试
- 如果没有提供目标,则不会计算损失,而是仅返回logits,以便于模型测试和验证。
如何启动生成模型
生成模型的初步设置
- 在生成过程中,使用0作为序列的第一个字符,代表换行符,这样可以合理地开始生成。
- 由于生成是在批处理层面进行的,需要从零维数组中索引,以获取时间步长,并将其转换为简单的Python列表。
模型训练的重要性
- 当前生成结果是随机的,因此需要对模型进行训练以减少随机性。
- 尽管当前函数设计为通用,但在实际应用中只需关注最后一部分数据来进行预测。
优化器与训练过程
- 创建PyTorch优化对象,选择Adam优化器而非传统的随机梯度下降(SGD),因为Adam在许多情况下表现更好。
- 对于小型网络,可以使用较高的学习率,例如3E负3,而不是通常推荐的3E负4。
迭代与损失评估
- 在每次迭代中,采样新数据、评估损失并更新参数,通过典型训练循环实现模型优化。
- 初始损失约为4.7,通过迭代逐渐降低到大约3.6,显示出优化效果。
模型进展与改进方向
- 随着训练次数增加,损失进一步降低至2.5左右,表明模型正在取得进展。
- 当前模型仍然非常简单,仅依赖最后一个字符进行预测,需要使得各个token之间能够相互作用,以便更好地理解上下文。
脚本化与超参数设置
- 将Jupyter Notebook中的代码转换为脚本,以简化工作流程并集中于最终产品。
数据加载与模型创建
数据与设备的迁移
- 在加载数据时,需要确保将其移动到设备上,创建模型时也要将模型参数移动到设备。
- 例如,神经网络的嵌入表包含一个双重权重,用于存储查找表,这个表会被移动到GPU,以加速计算。
训练循环中的损失估计
- 在训练循环中,仅打印当前损失值是非常嘈杂的测量,因为每个批次的结果可能会有所不同。
- 通常需要使用估计损失函数来平均多个批次的损失,从而减少噪声。
模型评估与训练模式
- 设置模型为评估阶段后,再将其重置为训练阶段。当前模型在这两种模式下行为相同,因为没有Dropout层等。
- 理解神经网络处于何种模式是良好的实践,因为某些层在推理和训练时表现不同。
内存效率与反向传播
使用上下文管理器
- 使用
torch.no_grad上下文管理器可以告知PyTorch不进行反向传播,从而提高内存使用效率。
- 通过不存储中间变量,可以使得内存使用更加高效,这是一个良好的实践。
自注意力机制的数学技巧
自注意力块准备
- 脚本运行后输出了训练损失和验证损失,显示出大约2.5的结果,为接下来的自注意力块编写做好准备。
令牌之间的信息流动
- 创建一个形状为B x T x C(例如4 x 8 x 2)的张量,其中B、T和C分别表示批次、时间和通道信息。
- 希望令牌之间能够相互交流,但未来位置的令牌不能影响当前令牌的信息流动。
信息传递方式及其局限性
平均化历史信息
- 对于第五个位置的令牌,可以通过对之前所有元素进行平均来实现与过去的信息交流,这样形成一个特征向量以总结历史信息。
信息丢失问题
如何提高循环效率
循环与批处理维度
- 当前使用的for循环在处理批次维度时效率不高,正在独立迭代时间和之前的标记。
- 通过对零维度进行平均,得到一个一维向量X背景词,这个过程虽然简单,但并不高效。
平均计算的示例
- 在计算过程中,第一个位置的两个元素相等,因为只对一个标记取平均;后续位置则是多个标记的平均值。
- 最终结果是所有元素的垂直平均,尽管这个方法有效,但仍然存在效率问题。
矩阵乘法优化
- 引入矩阵乘法作为数学技巧,通过简单矩阵(全为1)与随机数矩阵相乘来展示如何提高效率。
- C矩阵中的数字是通过行与列的点积得出的,利用全为1的行简化了计算过程。
利用下三角矩阵
- 使用torch库中的triangular函数,可以提取下三角部分,从而忽略某些元素,提高计算效率。
- 通过这种方式,我们可以从B中提取特定行,而不是进行完整的点积运算。
动态求和与平均
- 根据当前权重(全为1或0),动态地对B中的行进行求和或平均,这样可以灵活调整所需的数据。
- 通过将A归一化,使其总和为1,从而实现对B中行的逐步平均,并最终得到所需结果。
向量化操作提升性能
- 为了进一步提高效率,将生成一个权重数组,用于控制每一行在求平均时的重要性。
矩阵乘法与加权聚合的应用
批量矩阵乘法的实现
- 介绍了批量矩阵乘法的概念,能够并行处理所有批次元素,并对每个批次元素进行 T x T 与 T x C 的相乘。
- 结果生成 B x T x C 的结构,Expo 和 Expo2 应该是相同的,通过 torch.allclose 验证这一点。
加权和的计算
- 使用批量矩阵乘法来实现加权和,这种加权和根据指定的 T x T 数组中的权重进行计算。
- 权重以三角形形式存在,确保在第 t 维度上的 token 仅能获取前面 tokens 的信息,这是所需的功能。
Softmax 的应用
- 引入第三种版本,使用 softmax 来处理数据。初始时 Trill 矩阵全为零,通过 masked fill 将其变为负无穷大。
- 对每一行执行 softmax 操作,实现归一化,从而得到相同的矩阵结构。
自注意力机制中的亲和力
- 权重从零开始,可以视为交互强度或亲和力,表示过去每个 token 在聚合时的重要性。
- 设置负无穷大以阻止未来 tokens 与过去 tokens 通信,从而影响聚合过程。
自注意力块的发展
- 利用下三角形式的矩阵乘法进行加权聚合,以便开发自注意力模块。
自注意力机制的实现
交互层与位置编码
- 在线性层中实现交互,当前运行结果看似不稳定,但将继续构建。
- 引入第二个位置嵌入表,每个位置从0到块大小减1都有自己的嵌入向量。
- 通过嵌入表生成一个形状为T x C的矩阵,将标记嵌入与位置嵌入相加,形成新的表示x。
自注意力机制的核心
- 当前模型对位置信息不敏感,因为它是平移不变的,但在自注意力模块中,位置信息将变得重要。
- 自注意力机制是视频中的关键部分,将实现单个自注意力头。
权重初始化与信息聚合
- 示例中通道数从2更改为32,使用4x8的标记排列,每个标记的信息为32维。
- 当前代码简单地对过去和当前标记进行平均处理,通过创建下三角结构来屏蔽权重矩阵。
- 初始化不同标记之间的亲和度为零,使每一行具有均匀数字,从而实现简单平均。
数据依赖的信息收集
- 不同标记会对其他标记产生不同程度的兴趣,自注意力解决了这一问题。
- 每个节点或标记在每个位置发出两个向量:查询(query)和键(key),分别表示“我在寻找什么”和“我包含什么”。
计算亲和度
- 通过查询向量与所有键向量进行点积计算亲和度,如果查询和键对齐,则会有较高的互动性。
- 实现单个自注意力头时,需要小心处理矩阵乘法,并转置K以适应批次维度。
- 初始化线性模块并生成键和值,通过前馈操作得到B x T x 16大小的数据结构。
最终亲和度计算
自注意力机制的工作原理
加权聚合的变化
- 介绍了加权聚合作为一种数据依赖的函数,强调每个批次元素将具有不同的权重,而不是之前统一的常数。
- 通过观察输入的第零行,展示了输出权重的不均匀性,特别是最后一行中的第八个标记如何根据其内容和位置生成查询。
查询与键之间的关系
- 第八个标记创建一个查询,寻找特定类型的信息(如元音和辅音),并通过节点发出键以建立高亲和度。
- 当查询与键进行点积时,如果它们之间有高亲和度,则会通过softmax聚合大量信息。
聚合过程中的细节
- 在没有掩蔽和softmax操作下,展示了点积输出的原始值范围,并解释了如何使用上三角掩蔽来限制节点间的信息交流。
- 通过指数化和归一化处理,使得信息聚合分布良好,不再出现负值,从而实现数据依赖的信息聚合。
值向量的重要性
- 在自注意力头中,引入“值”这一概念,通过线性变换计算得到,并在最终输出中乘以加权后的值向量。
- 强调X向量代表每个标记私有的信息,而V则是用于单头聚合的信息。
自注意力机制总结
- 自注意力机制被描述为一种通信机制,其中每个节点可以从指向它的所有节点中汇总信息,以数据依赖方式进行加权求和。
- 指出图结构与语言建模场景中的不同,以及自注意力可以应用于任意有向图形。
空间感知与位置编码
- 注意到自注意力没有空间概念,因此需要对节点进行位置编码,以便它们了解自身在空间中的位置。
空间的概念与独立处理
批处理维度的独立性
- 在计算相对位置编码时,需要特别添加空间的概念,这样才能将这些信息整合到向量中。
- 批处理中的元素是独立的示例,它们之间不会相互交流,采用并行方式进行矩阵乘法。
有向图结构与节点交互
- 在语言建模中,有向图的特定结构使得未来的标记不会与过去的标记通信,但在一般情况下,这并不是必须的约束。
- 例如,在情感分析中,所有节点可能需要完全交流,以便预测句子的情感。
编码器块与解码器块
- 使用自注意力机制时,编码器块允许所有节点完全交流,而解码器块则会保留三角形结构以防止未来节点影响过去节点。
- 解码器被称为“解码”,因为它具有自回归格式,通过三角矩阵掩蔽来确保未来的信息不泄露给过去。
自注意力与交叉注意力
自注意力机制
- 自注意力是指键、查询和值都来自同一来源(X),因此这些节点是在自我关注。
交叉注意力机制
- 交叉注意力允许查询来自一个源,而键和值来自另一个外部源,例如编码一些上下文信息。
- 当我们希望从其他节点提取信息时,会使用交叉注意力;而当仅需查看彼此时,则使用自注意力。
缩放注意力的重要性
注意力实现过程
- 在“Attention is All You Need”论文中,我们已经实现了基于查询、键和值的乘法和聚合操作,但缺少了对头大小平方根倒数的除法步骤。
缩放的重要性
- 缩放是重要的一步,因为如果输入为单位高斯分布,直接计算会导致方差过大,从而影响后续softmax操作。
初始化阶段控制方差
Softmax行为分析
- 如果权重值过于极端,softmax将收敛到单一热向量,这意味着每个节点只聚合来自单一其他节点的信息,这是不理想的情况。
控制初始化方差的方法
自注意力机制的实现与多头注意力
自注意力机制的基础
- 在节点上应用线性投影,创建一个名为 Trill 的变量,该变量不是模块的参数,而是一个缓冲区,需要通过注册缓冲区将其分配给模块。
- 输入 X 后,计算键(keys)、查询(queries)和归一化处理,使用缩放注意力机制,并确保特征不与过去通信,从而形成解码器块。
解码器语言模型构建
- 在构造函数中创建自注意力头(self attention head),保持头部大小与嵌入相同,将信息编码后输入自注意力头。
- 输出传递到解码器语言模型头以生成 logits,这是将自注意力组件插入网络的最简单方式。
训练过程中的调整
- 确保输入索引不超过块大小,以避免位置嵌入表超出范围,因此添加代码裁剪上下文。
- 降低学习率并增加迭代次数,因为自注意力无法容忍过高的学习率,训练结果从 2.5 改进至 2.4,但文本生成效果仍需提升。
多头注意力机制的实现
- 引入多头注意力概念,通过并行应用多个自注意力并连接结果来增强模型能力。
- 在 PyTorch 中创建多个自注意力头,并在通道维度上连接输出,实现多通道通信。
通信渠道与数据收集
- 使用四个独立的通信通道,每个通道收集八维向量,总体合并为原始嵌入大小,这类似于组卷积。
- 经过测试后,验证损失从 2.4 降至约 2.28,多通道有助于更好地捕捉不同类型的数据进行解码。
网络结构中的前馈部分
- 注意到网络中存在前馈部分,即简单的多层感知机(MLP),用于每个节点级别的计算。
模型架构与优化
前馈网络的实现
- 介绍了一个简单的前馈单层网络,该层由线性变换和相对非线性组成,称为前馈嵌入。
- 前馈网络在每个token级别独立应用,强调自注意力机制用于信息交流,而前馈则是对收集到的数据进行个体思考。
模型训练与性能改进
- 在训练过程中,验证损失从2.28下降至2.24,尽管输出仍不理想,但情况有所改善。
- 计划将通信与计算交替进行,这也是Transformer模型的特点,通过多头自注意力和前馈网络实现。
Transformer结构与参数设置
- 讨论了嵌入维度、头数及其在组卷积中的类似性,设定头数为4,并计算出每个头的大小为8,以确保通道一致性。
- 创建多个块以交替执行通信和前馈操作,从而提高模型的表达能力。
深度神经网络的优化问题
- 尝试运行模型时发现结果不佳,原因在于深度神经网络面临优化问题,需要借鉴Transformer论文中的两种优化方法。
残差连接的重要性
- 引入残差连接(skip connections),这种概念源于2015年的一篇论文,有助于缓解深度网络中的优化困难。
- 残差路径允许数据转化并通过加法从先前特征中跳过,使得梯度传播更加高效。
梯度传播与初始化策略
- 加法操作使得梯度均匀分布到两个分支,从而形成“梯度高速公路”,确保监督信号能够无阻碍地传递到输入层。
- 虚拟块在初始化时几乎不影响残差路径,但随着优化过程逐渐发挥作用,有助于提升整体性能。
实现残差连接与投影层
- 在块中实现残差连接,通过加法将自注意力和前馈结果合并回原始输入,以增强信息流动。
模型优化与层归一化的应用
输入输出维度与前馈网络
- 在重新审视论文时,发现输入和输出的维度均为512,而前馈网络中的内层维度为2048,这意味着通道大小需要乘以四。
- 通过将嵌入乘以四来增加计算量,并在残差块中扩展这一层,最终训练得到了2.08的验证损失,但开始出现轻微的过拟合现象。
生成效果与创新方法
- 尽管生成效果尚未达到理想状态,但文本开始接近英语形式,显示出模型逐渐改善。
- 引入了“层归一化”(Layer Norm),其实现方式类似于批量归一化(Batch Normalization),确保每个神经元在批次维度上具有单位高斯分布。
层归一化的实现细节
- 复制并粘贴了之前开发的1D批量归一化模块,以处理32个100维向量,确保每列数据均为零均值和单位标准差。
- 实现了层归一化后,行不再被默认规范化,而是对每个示例进行单独规范化,从而简化了计算过程。
Transformer中的层归一化应用
- 在Transformer中引入了预先规范化(pre-norm)形式,与原始论文略有不同,现在通常在变换之前应用层归一化。
- 需要两个层归一化模块,第一个用于输入特征,第二个则在进入自注意力和前馈网络之前进行处理。
模型扩展与改进
- 添加了可训练参数gamma和beta,使得最终输出可能不再是单位高斯分布,通过优化过程来调整这些参数。
- 在Transformer最后添加了一层归一化,以便更好地解码到词汇表中,从而使模型更加完整。
如何使用Dropout技术提高神经网络性能
Dropout的基本概念
- 在残差连接之前,可以在多头扩展的最后一层和计算相似度时随机丢弃一些节点,以防止节点之间的通信。
- Dropout源于2014年的一篇论文,它在每次前向和反向传播中随机关闭部分神经元,从而训练出一个子网络的集合。
- 由于每次前向和反向传播中被丢弃的神经元不同,最终形成了一个集成模型,这是一种正则化技术。
超参数调整与模型规模
- 为了应对过拟合,作者将批量大小增加到64,并将上下文块大小从8个字符增加到256个字符。
- 学习率降低至适应更大的神经网络,嵌入维度设置为384,每个头部为64维,共有六个头部和六层结构,同时Dropout比例设定为0.2。
模型训练效果
- 经过训练后,验证损失从2.07降至1.48,显示出显著改善。该模型在A100 GPU上训练约15分钟。
- 如果没有GPU,在CPU或Macbook上无法复现此结果,需要减少层数和嵌入维度。
输出结果分析
- 打印出的文本输出更加可识别,但仍然是无意义的字符串,与输入文本格式相似。
- 输入文本来自莎士比亚作品,生成的文本虽然形式上类似,但内容并不合理。
Transformer架构解析
- 本视频实现的是仅解码器Transformer,没有编码器部分,因此缺少交叉注意力模块,仅包含自注意力和前馈网络。
Transformer模型的编码与解码
编码过程
- 在编码过程中,法语句子的内容被读取并生成tokens,使用Transformer模型进行处理,没有三角形掩蔽,因此所有tokens可以相互交流。
解码过程
- 解码器在语言建模中增加了与编码器输出的连接,通过交叉注意力机制引入这些信息,使得查询仍然来自X,但键和值则来自编码器的输出。
交叉注意力机制
- 交叉注意力机制使得解码不仅依赖于当前解码的过去信息,还依赖于完整编码的法语提示,从而形成一个编码-解码模型。
Nano GPT概述
- Nano GPT包含两个主要文件:train.py和model.py。train.py负责训练网络,包括保存和加载检查点、预训练权重等复杂操作。
模型结构与实现
- model.py中的自回归自注意力块与之前所做的非常相似,生成查询、键和值,并进行点积运算和softmax处理,同时支持dropout。
如何训练ChatGPT?
训练阶段划分
- ChatGPT的训练分为两个阶段:预训练阶段和微调阶段。在预训练阶段,使用大量互联网数据来训练仅有解码器的Transformer,以生成文本。
参数与数据集规模对比
如何训练大型语言模型
预训练阶段的挑战
- 在预训练阶段,模型的规模通常超过一万亿参数,需要在大量互联网数据上进行训练。
- 训练这样的大型模型需要数千个GPU相互协作,这对基础设施提出了巨大的挑战。
- 完成预训练后,模型并不会直接回答问题,而是生成文档内容,表现为“文档补全器”。
- 模型可能会产生不确定的行为,例如用问题回应问题或忽略用户的问题。
微调阶段的重要性
- 微调阶段旨在将模型调整为助手角色,OpenAI的博客中提到这一过程分为三个步骤。
- 收集特定格式的数据(如问题和答案),以便微调模型,使其能够更好地理解用户提问。
- 第二步是让不同评审者对模型的响应进行评分,以此来建立奖励模型,从而优化输出质量。
强化学习与政策优化
- 使用PPO(策略梯度强化学习优化器)来微调采样策略,以提高生成答案的质量和相关性。
- 整个微调过程复杂且多步骤,将文档补全能力转变为有效的问题回答能力。
数据获取与复制难度
- 大部分用于微调的数据并未公开,因此复制这一阶段非常困难,仅限于OpenAI内部使用。
小型GPT与架构相似性
- 本次讨论还涉及到一个小型GPT项目,该项目基于2017年的论文《Attention is All You Need》进行开发,并在小型莎士比亚文本上取得了良好的结果。
- 虽然架构基本相同,但小型GPT的规模仅为大型GPT的一万分之一到百万分之一之间。