Jiahong 的个人博客

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

DL——深度学习并行技术总结


整体说明

  • 并行化技术一般在训练大型深度学习模型时使用
  • 并行化技术氛围三种:
    • 数据并行 (Data Parallelism)
    • 模型并行 (Model Parallelism)
    • 流水线并行 (Pipeline Parallelism),有的地方也翻译为管道并行

各种并行方法之间的关系总结

  • 整体可分为 模型并行 (Model Parallelism) 和 数据并行
    • 数据并行 :每个 GPU 都拥有一个完整的模型副本,但处理不同的数据批次
    • 模型并行 :每个 GPU 只负责模型的一部分,所有 GPU 共同处理一个完整的数据批次,包括 张量并行 和 流水线并行 两种具体实现
  • 模型并行的进一步介绍:当模型太大无法放入单个 GPU 时,就需要使用模型并行
    • 将模型的不同部分分配给不同的 GPU
    • 优点是可以训练显存无法容纳的巨大模型
    • 缺点是实现相对复杂,且由于不同 GPU 间的通信和等待,可能会导致 GPU 利用率不高
  • 实际应用中,为了充分利用资源并训练超大模型,通常会结合多种并行化技术,形成 混合并行 策略,例如同时使用数据并行、流水线并行和张量并行

数据并行 (Data Parallelism)

  • 最常见、也最容易理解的并行化方法
  • 数据并行的工作方式 :
    • 训练数据集被分成多个子集(例如,一个 128 张图片的批次被分成 4 个 32 张图片的子批次)
    • 每个 GPU 拥有一个完整的模型,并独立处理一个子批次的数据
  • 数据并行的训练过程 :
    • 1)每个 GPU 计算其子批次的前向传播和反向传播,得到各自的梯度
    • 2)通过 All-Reduce 这样的通信操作,将所有 GPU 的梯度进行汇总和平均
    • 3)每个 GPU 用这个平均后的梯度来更新自己的模型参数,从而确保所有模型副本保持同步
  • 优点是实现简单,对模型结构无特殊要求 ,比如使用 PyTorch 的 DP 类就可以实现
  • 缺点是每个 GPU 都需要存储完整的模型 ,当模型参数量非常大时,会超出单个 GPU 的显存限制 ,此时数据并行就无法使用

流水线并行 (Pipeline Parallelism)

  • 流水线并行将模型的不同“层”(或一组层)分配给不同的 GPU,形成一个“流水线”
    • 例如,GPU 1 负责模型的第 1-4 层,GPU 2 负责第 5-8 层,以此类推
  • 数据并行的训练过程 :
    • 一个数据批次被分解成更小的“微批次”(micro-batches)
    • GPU 1 处理第一个微批次,完成后将输出传给 GPU 2
    • 当 GPU 1 开始处理第二个微批次时,GPU 2 就可以同时处理第一个微批次
  • 优点是部分解决了模型过大的问题(单层过大仍然无法解决)
  • 缺点是存在 “流水线气泡”(pipeline bubble) 问题,即流水线开始和结束时,部分 GPU 会处于空闲等待状态,导致 GPU 利用率并非 100%
    • 注:通过流水线的方式(即错位并行处理不同微批次的方式),可以一定程度上重叠不同 GPU 的计算,提高整体效率

张量并行 (Tensor Parallelism)

  • 张量并行 不按层切分模型,而是将模型中某个操作内部的 张量(例如一个大型矩阵)切分到不同的 GPU 上
  • 举例来说:一个 \(A \times B\) 的矩阵乘法,可以把矩阵 B 按列切分,每个 GPU 分别计算,最后再通过通信操作将结果合并
  • 优点是:
    • 可以进一步解决单个层或单个操作的参数过大的问题,从根本上解决了模型过大的问题
    • 因为所有 GPU 都在同一时间处理同一个微批次,所以不会有流水线气泡问题 ,GPU 利用率通常更高
  • 缺点是
    • 对模型结构有要求,通常只能在某些特定操作(如矩阵乘法、线性层)中应用
    • 需要频繁的 GPU 间通信来同步切分后的张量,这要求非常高速的 GPU 互联(例如 NVLink)

DL——激活函数总结

  • 参考博客:
    • 一篇写得非常好的文章:深度学习激活函数的理解与总结
    • 激活函数总结-稀土掘金

ReLU

修正线性单元(Rectified Linear Unit)

  • 表达式:
    $$\text{ReLU}(x)=
    \begin{cases}
    0& \text{x<=0}\\
    x& \text{x>0}
    \end{cases}$$
  • 函数图像:

x 为 0 时的导数问题

  • 在实际场景中,x 为 0 的概率非常低
  • 实际场景中,当 x 为 0 时,原函数不可导,可以给此时的导数制定一个值,如0,或1
  • 神经元永久死亡问题:https://www.zhihu.com/question/67151971
    • 当对于任意的训练样本,某一个神经元输出都小于0时,该神经元的反向梯度为0,所以神经元上层与神经元相连接的所有节点梯度都为0(链式法则,梯度相乘),也就是对所有的训练样本,这些节点相关的参数都不会被更新(因为梯度为0),下一次正向计算到这些节点时值都不会变
    • 一个常见的疑问:如果当前神经元上层的神经元其他参数发生改变而导致当前神经元的输入数据发生改变呢?
    • 回答:可能有这种情况,一个神经元的反向梯度为0以后,所有只与该层该神经元相关的参数都不会变了,但与该层其他神经元相关的节点参数还是会变的!【需要进一步探讨这个问题】
    • 补充回答:可以确定的是,如果当前层的其他神经元不影响该神经元上层的相关参数,那么,这个神经元将永久性死亡
    • 所以正确的描述是:对于任意的输入(不管当前层输入为何值时,当前神经元的输出都等于0,也就是说,虽然上层的输入可能会变,但是当前节点的输出已经不会变化了!),都有当前神经元的输出等于0,此时反向梯度永远为0
    • 注意:这不是说神经元从开始就怎么样,而是神经元相关的参数偏向太多,导致当前神经元的值永远为0

ELU

Exponential Linear Units

  • 表达式:
    $$\text{ELU}(x)=
    \begin{cases}
    x, & \text{if } x > 0 \\
    \alpha(e^x - 1), & \text{otherwise}
    \end{cases}
    $$
  • 函数图像:

Leaky ReLU

Leaky ReLU

  • 表达式:
    $$\text{Leaky-ReLU}(x)=
    \begin{cases}
    \alpha \cdot x& \text{x<=0} \\
    x& \text{x>0}
    \end{cases}$$
  • 函数图像:
  • 函数实现
    1
    2
    3
    4
    5
    def leaky_relu(x, alpha=0.01):
    return np.where(x >= 0, x, alpha * x)

    def leaky_relu_derivative(x, alpha=0.01):
    return np.where(x >= 0, 1, alpha)

PReLU

Parametric ReLU(PReLU)

  • 表达式(虽然表达式与Leaky ReLU相同,但是其中的参数是可学习的):
    $$\text{PReLU}_{\alpha}(x)=
    \begin{cases}
    \alpha \cdot x& \text{x<=0} \\
    x& \text{x>0}
    \end{cases}$$
  • 函数图像:
  • 函数实现
    1
    2
    3
    4
    5
    def prelu(x, alpha):
    return np.where(x >= 0, x, alpha * x)

    def prelu_derivative(x, alpha):
    return np.where(x >= 0, 1, alpha)

Softplus

  • 表达式:
    $$ \text{Softplus}(x) = \ln(1+e^x) $$

  • 函数图像:

  • torch实现

    1
    x = F.softplus(x)

Sigmoid

  • 表达式:
    $$ \text{Sigmoid}(x) = \frac{1}{1+e^{-x}} $$
  • 函数图像:

Tanh

  • 表达式:
    $$
    \begin{align}
    \tanh (x)&=\frac{e^x-e^{-x}}{e^x+e^{-x}} \\
    \tanh (x)&=\frac{2}{1+e^{-2x}} - 1 \\
    \tanh (x)&=2\cdot \text{Sigmoid}(2x) - 1 \\
    \end{align}
    $$
  • 函数图像:

Mish

Mish: A Self Regularized Non-Monotonic Neural Activation Function

  • 表达式:
    $$ Mish(x) = x\cdot \text{tanh}(\ln(1+e^x))$$
  • 函数图像

DL——特征交叉算子总结


内积

  • 定义 :内积是一种常见的特征交叉方法,它通过计算两个向量对应元素的乘积之和来得到一个标量值,用于衡量两个向量的相似度或相关性
  • 公式 :对于两个向量\(\mathbf{x}=(x_1,x_2,\cdots,x_n)\)和\(\mathbf{y}=(y_1,y_2,\cdots,y_n)\),它们的内积表示为:
    $$\langle\mathbf{x},\mathbf{y}\rangle=\sum_{i = 1}^{n}x_iy_i$$

Hadamard积

  • 定义 :Hadamard积是两个相同维度的向量或矩阵对应元素相乘的运算,结果是与原向量或矩阵同维度的向量或矩阵,它在一些机器学习模型中用于特征的逐元素组合
  • 公式 :若\(\mathbf{x}=(x_1,x_2,\cdots,x_n)\)和\(\mathbf{y}=(y_1,y_2,\cdots,y_n)\),则它们的Hadamard积为:
    $$\mathbf{x}\odot\mathbf{y}=(x_1y_1,x_2y_2,\cdots,x_ny_n)$$

BilinearCross积

  • 定义 :BilinearCross积是一种双线性特征交叉方式,它通过一个矩阵来对两个向量进行交叉操作,能够捕捉到特征之间更复杂的交互关系
  • 公式 :设\(\mathbf{x}\in\mathbb{R}^m\),\(\mathbf{y}\in\mathbb{R}^n\),交叉矩阵为\(\mathbf{W}\in\mathbb{R}^{m\times n}\),则BilinearCross积表示为:
    $$\mathbf{x}^T\mathbf{W}\mathbf{y}=\sum_{i = 1}^{m}\sum_{j = 1}^{n}w_{ij}x_iy_j$$
  • 以上定义也称为BilinearCross内积 ,同理可以定义BilinearCross外积 :
    $$\mathbf{x}\odot(\mathbf{W}\mathbf{y})$$

NLP——LLM模型存储形式


整体说明

  • 当前主流的大模型存储格式可以按 “训练框架原生格式 -> 通用交换格式 -> 高效推理格式” 这条演进路线来理解
  • TLDR:“训练阶段用 .pth/.ckpt/.bin,跨框架交换用 ONNX,线上部署优先 Safetensors,如果对体积和 CPU 推理速度极端敏感就转 GGUF”

模型格式归纳

  • 训练框架原生格式
    • .pth / .pt:PyTorch 的 pickle 序列化结果,既可以是 state_dict,也可以是完整模型(含结构+权重)通用、易用,但体积大、加载慢,且存在反序列化安全风险
    • .ckpt:PyTorch Lightning 在 .pth 基础上扩展出的 Checkpoint 格式,额外保存优化器状态、epoch、超参等,用于断点续训
    • .bin:TensorFlow 早期常用的纯权重二进制文件,没有统一元数据,需配合 config.json 使用;在 Hugging Face 生态中仍大量出现
  • 通用交换格式
    • ONNX(.onnx):微软+Facebook 推出的开放标准,旨在跨框架(PyTorch/TF/ Paddle 等)部署;支持图优化、量化,但大模型时文件体积依旧可观
    • HDF5 / .h5:Keras/TensorFlow 传统格式,层次化存储网络结构和权重;对超大规模模型支持有限,已逐渐被 TF Checkpoint 或 SavedModel 取代
  • 高效推理格式
    • Safetensors(.safetensors):Hugging Face 推出的安全张量格式,只存权重、无代码、支持 zero-copy 与懒加载,加载速度 >pickle,且杜绝反序列化漏洞,已成为 HF Hub 的默认推荐
    • GGUF(GPT-Generated Unified Format):由 llama.cpp 作者 Georgi Gerganov 设计,用于取代旧版 GGML二进制紧凑、自带量化方案(Q2_K/Q4_0 等)、内存映射快速加载、元数据自包含,无需额外文件即可部署;Gemma、Qwen、Llama-3 等均官方提供 GGUF 版本
    • GGML(已弃用):早期 llama.cpp 使用的二进制格式,无版本控制、扩展困难,已全部迁移到 GGUF
  • 训练/数据级格式(辅助)
    • TFRecord / RecordIO:TensorFlow 训练数据管道常用,顺序、可压缩、高吞吐
    • Parquet / Arrow / LMDB:离线特征或中间结果列式存储,便于大规模并行读取

大模型常用框架相关的格式整体说明

  • 本文描述大模型的存储的形式和 转到 Hugging Face 的方式
  • Megatron / DeepSpeed / FSDP 都把 “一张完整的权重图” 切成很多片,文件名、目录结构、张量 key 名均与 HF 不一致;
  • 想进 HF 生态,必须 “合并分片 + 重命名 key + 生成 config.json”;
  • 合并脚本一般都已有各框架的官方提供,一般按照官方提供脚本转换即可

Hugging Face 原生格式

  • Hugging Face 上的开源模型通常以 “模型仓库(model repository)” 的形式托管,下载到本地后是一个目录,里面包含若干标准文件
  • 使用 Hugging Face 的接口加载模型时,该接口会大致进行以下流程:
    • 加载配置:读取 config.json 文件,用于构建模型的基本结构
    • 加载权重:读取模型权重文件(如 model.safetensors)中的参数值会被加载到定义好的模型结构中
    • 分词器初始化(处理输入):分词器文件(如 tokenizer.json, vocab.json)负责将原始文本转换为模型能够理解的 token ID 序列
    • 其他步骤:如果是文本生成任务,generation_config.json 会提供默认的生成参数
  • 推理最少三件套 :config.json + 权重文件 + 分词器文件
  • 微调再补 :tokenizer_config.json、special_tokens_map.json、generation_config.json 及优化器 checkpoint
  • 大模型 :使用 .safetensors 分片和 *.index.json 索引,断点续传更方便

必存在文件(推理/微调都少不了)

  • config.json
    • 主要包含模型超参与架构描述:隐藏层大小(hidden_size)、注意力头数(num_attention_heads)、层数(num_hidden_layers)、激活函数(hidden_act)等
    • 不同模型的内容不完全相同(是各家模型厂商自己自定义的),这个文件是会被当做超参数传递到模型的初始化文件中的
    • 还包含模型的 参数类型 (比如 "torch_dtype": "bfloat16") 作为加载时的统一转换类型
      • 注:同一个模型的不同参数可以存储为不同类型,这里的 "torch_dtype" 字段仅仅指定加载时的参数
  • 权重主文件(可以是 .bin, .h5, safetensors 等类型的文件,也可能是 gguf 等量化格式的文件)
    • pytorch_model.bin(PyTorch)
      • 分片(shard)文件 比如pytorch_model-00001-of-00008.bin 到 pytorch_model-00008-of-00008.bin,会伴随一个 pytorch_model.bin.index.json 索引文件来记录这些分片信息
    • tf_model.h5(TensorFlow)
    • flax_model.msgpack(Flax/JAX,不常见)
    • model.safetensors(新版统一二进制格式,零拷贝、更安全)
      • Hugging Face 推荐的安全格式 ,不包含可执行代码 ,避免了传统 PyTorch 格式因使用 pickle 序列化而可能存在的安全风险(如恶意代码执行)
      • 通常加载更快且更节省内存
      • 分片(shard)文件 比如model-00001-of-00008.safetensors 到 model-00008-of-00008.safetensors,会伴随一个 model.safetensors.index.json 索引文件来记录这些分片信息
    • gguf(量化后的 GGUF 格式)
      • CPU 或个人设备上进行本地推理 ,首选能提供更好的体验
      • 一般会按照不同的量化格式提供多个 gguf 文件,如 q4_k_m.gguf 等来说明量化形式
    • 注:加载过程中,根据不同的模型权重类型,Hugging Face 框架会使用不同的加载函数加载
  • tokenizer.json
    • 分词器核心配置:预处理器状态、编解码规则、特殊 token 映射
    • 词表内容一般也会在这格文件中,以 vocab 为 Key 存在,所以 tokenizer.json 一般会有几十 MB 大小
  • 补充:model.safetensors.index.json 索引文件示例,包含模型的每一层权重到权重分片的映射
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    "metadata": {
    "total_size": 144575840256
    },
    "weight_map": {
    "lm_head.weight": "model-00082-of-00082.safetensors",
    "transformer.h.0.attn.c_attn.bias": "model-00002-of-00082.safetensors",
    "transformer.h.0.attn.c_attn.weight": "model-00002-of-00082.safetensors",
    "transformer.h.0.attn.c_proj.weight": "model-00002-of-00082.safetensors",
    "..."
    }
    }

常见文件(大部分仓库可见)

  • 分词器相关文件:
    • tokenizer.json:分词器的完整定义,包括编码规则和词汇表映射(前面已经介绍过)
    • tokenizer_config.json:分词器的附加配置,如特殊标记(如[CLS]、[SEP]、[PAD])、填充方式、截断策略等
      • 部分模型会将聊天模版也放到这个文件中的 chat_template 字段(Qwen,Deepseek 等),部分模型则将聊天模板放到外面的 chat_template.jinja 文件(这样虽然不便于管理,但可读性会更高)
    • vocab.txt, vocab.json:模型的词汇表,存储 token 到 ID 的映射关
      • 注:目前许多模型已经不需要这个文件,因为该文件会以 "vocab" 字段的形式放到 tokenizer.json 中
    • merges.txt:适用于 BPE 等分词算法,定义了 token 的合并规则
      • 注:目前许多模型已经不需要这个文件,因为该文件会以 "merges" 字段的形式放到 tokenizer.json 中
    • special_tokens_map.json:统一声明 [PAD]、[CLS]、[SEP]、<|im_start|> 等特殊 token 的 ID 与字符串映射
      • 注:目前许多模型已经不需要这个文件,因为该文件会以 "additional_special_tokens" 字段的形式放到 tokenizer_config.json
    • added_tokens.json :用户或微调阶段追加的新 token
      • 注:目前许多模型已经不需要这个文件,因为该文件会以 "added_tokens" 字段的形式放到 tokenizer.json 中
  • generation_config.json : 文本生成默认策略:max_new_tokens、do_sample、temperature、top_p 等
  • .gitattributes : 用于配合 Git-LFS 把大文件托管到 LFS
    • gitattributes 是 Git 中用于定义特定文件(或文件类型)在 Git 操作中的处理规则的配置文件
    • 核心作用是 “为不同文件定制 Git 行为” ,告诉 Git:对于不同类型的文件,应该如何执行换行符转换、合并策略、文件属性标记、diff 对比方式等操作,从而在团队协作或跨平台开发中保持文件处理的一致性

附录:关于 generation_config.json 文件的使用

  • 在使用 Hugging Face 的 transformers 库加载模型时,会自动读取模型文件路径下的 generation_config.json 文件(如果存在的话)

  • generation_config.json 是用于存储模型生成相关配置的文件,包含了如最大生成长度(max_length)、采样温度(temperature)、top-k 采样等与文本生成任务相关的参数

  • 当使用 from_pretrained() 方法加载模型时,库会自动检查并加载该文件中的配置,这些配置会被存储在模型的 generation_config 属性中。例如:

    1
    2
    3
    4
    5
    6
    7
    from transformers import AutoModelForCausalLM, AutoTokenizer

    model = AutoModelForCausalLM.from_pretrained("model_path")
    tokenizer = AutoTokenizer.from_pretrained("model_path")

    # 查看加载的生成配置
    print(model.generation_config)
  • 如果模型路径中存在 generation_config.json,上述代码会自动加载其中的配置;如果该文件不存在,transformers 会使用默认的生成配置

  • 也可以通过 GenerationConfig 类手动加载或修改这些配置,并在生成文本时传入:

    1
    2
    3
    4
    5
    6
    7
    8
    from transformers import GenerationConfig

    # 手动加载生成配置
    gen_config = GenerationConfig.from_pretrained("model_path")
    # 修改配置
    gen_config.max_length = 100
    # 生成文本时使用
    outputs = model.generate(**inputs, generation_config=gen_config)

其他可选/场景文件

  • training_args.bin : 由 transformers.Trainer 自动保存,包含学习率、warmup step、batch_size 等训练超参
  • optimizer.bin / scheduler.bin : 断点续训时保存的优化器状态和 LR scheduler 状态
  • quantization/ 目录 : 低比特量化权重,如 F8_E4M3、INT4、GGML 等
  • README.md / LICENSE / *.md : 模型卡片、许可证、使用示例、局限性与伦理声明
  • preprocessor_config.json : 多模态模型(如 LLaVA、BLIP-2)中,图像预处理超参
  • adapter_config.json / adapter_model.bin : PEFT/LoRA 微调产生的轻量 adapter,仅含可训练增量参数
  • tokenizer.model 文件是 SentencePiece 分词器的核心文件,通常以二进制格式存储,包含分词规则、词汇表和预处理逻

关于 .bin 格式 和 .safetensors 格式的说明

  • .bin 是 Hugging Face 最早、最通用的格式(PyTorch 的格式),任何支持 from_pretrained() 的库都能直接加载

  • 如果同时包含一个同名的 .safetensors 和 .bin,HF 会优先用 .safetensors(更快、更安全)

  • 将 .bin 格式升级为 .safetensors 格式的接口如下:

    1
    2
    import safetensors
    safetensors.torch.save_file(state_dict, "model.safetensors")
  • 特别说明:.bin 和 .safetensors 中会包含权重文件的参数类型(fp16, fp32, bf16 等)

    • 而且,.bin 和 .safetensors 文件会为每个不同的参数张量存储各自的参数,所以理论上这些参数类型可以不用
    • 在加载模型时,会先按照权重文件中的真实类型读取,并转换成 config.json 中指定的文件格式(比如 "torch_dtype": "bfloat16" 指定 bf16 格式),存放到内存中

Megatron-LM 框架文件格式

  • 分片数量与分片参数(TP=N1、PP=N2、DP=N3)有关,下面是磁盘目录示例:

    1
    2
    3
    4
    5
    6
    7
    8
    iter_0001000/
    ├── model_optim_rng.pt # 传统同步格式(老版本)
    ├── __0_0.distcp # 新异步格式(v0.7+),每个文件只含本 rank 的分片
    ├── ...
    ├── __1_0.distcp
    ├── common.pt # 公共张量(embedding、lm_head 等)
    ├── metadata.json # 并行拓扑
    └── latest_checkpointed_iteration.txt
  • 注:部分 Megatron-LM 存储形式中, iter_0001000 下存储的是多个类似 mp_rank_xx_xx_cp_xx_dp_xx 目录的结构,每个结构存储部分模型参数

    • 这是 Megatron-LM 原生 checkpoint 的分布式存储结构

    • 命名规则:

      1
      mp_rank_{tensor_parallel_rank}_{checkpoint_partition}_{data_parallel_rank}
    • 含义:

      • mp_rank_xx_xx :Tensor Model Parallel rank(张量并行+流水线并行的分片编号)
      • cp_xx :Context parallel rank(上下文并行分片编号)
      • dp_xx :Data parallel rank(数据并行的副本编号)
    • 每个目录里可能包含:

      • distrib_optim.pt
        • 分布式优化器(比如 ZeRO)的状态分片,包含梯度累积缓冲、参数分片等,用于 resume 训练使用,若确定不再需要继续训练,则可以删除该文件
      • model_optim_rng.pt
        • 保存随机数生成器状态(Python random、NumPy RNG、PyTorch CPU/CUDA RNG、Megatron并行RNG),用于恢复训练时保证随机性一致
        • 注:部分架构中,模型权重也存储在这个文件里面
  • Megatron 格式与 HF 不兼容;需要合并+重命名,下面是官方给出的转换脚本(同步格式)

    1
    2
    3
    4
    5
    6
    python tools/checkpoint_converter.py \
    --model-type GPT \
    --load-dir iter_0001000 \
    --save-dir hf_format \
    --target-tensor-parallel-size 1 \
    --target-pipeline-parallel-size 1
  • HF 的一般格式现在是类似下面的形式

    1
    2
    3
    4
    5
    6
    7
    hf_format/
    ├── model_00001-of-00010.safetensors # 文件权重
    ├── model_xxx...
    ├── model.safetensors.index.json # 分片成多个文件时用于索引
    ├── tokenizer.json
    ├── tokenizer_config.json
    └── config.json # 由脚本自动生成

DeepSpeed 框架文件格式

  • ZeRO-3 会对参数进行分片,分片数量参数有关,磁盘目录(16 GPU)

    1
    2
    3
    4
    5
    6
    7
    global_step1000/
    ├── bf16_zero_pp_rank_00_mp_rank_00_optim_states.pt # 优化器状态
    ├── bf16_zero_pp_rank_01_mp_rank_00_optim_states.pt
    ├── ...
    ├── zero_pp_rank_00_mp_rank_00_model_states.pt # 权重分片
    ├── zero_pp_rank_01_mp_rank_00_model_states.pt
    └── ...
  • DeepSpeed 与 HF 不兼容;需要合并(DeepSpeed 自带工具)

    1
    python zero_to_fp32.py global_step1000 ds_model.pth
  • 进一步精简权重文件(仅保留权重)并转 HF 的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import torch
    from transformers import AutoConfig, AutoModelForCausalLM

    state_dict = torch.load('ds_model.pth', map_location='cpu')
    torch.save(state_dict, 'pytorch_model.bin') # 仅权重

    config = AutoConfig.from_pretrained('meta-llama/Llama-2-7b-hf')
    model = AutoModelForCausalLM.from_config(config)
    model.load_state_dict(state_dict)
    model.save_pretrained('hf_from_ds')

PyTorch FSDP 框架文件格式

  • 磁盘目录(8 GPU)

    1
    2
    3
    4
    5
    checkpoint-1000/
    ├── __0_0.distcp # 每个 rank 的分片
    ├── ...
    ├── __7_0.distcp # 每个 rank 的分片
    └── .metadata # FSDP 元数据
  • PyTorch FSDP 与 HF 不兼容;需要合并,官方合并脚本(PyTorch 大于 2.2)

    1
    2
    3
    python -m torch.distributed.checkpoint.format_utils dcp_to_torch_save \
    checkpoint-1000 \
    fsdp_model.pth
  • 再转成 HF Safetensors(更快、安全)

    1
    2
    3
    4
    5
    from safetensors.torch import save_file
    import torch

    state_dict = torch.load('fsdp_model.pth')
    save_file(state_dict, 'model.safetensors')

附录:在不加载模型的情况下查看 safetensors 文件参数类型

  • 使用 transformers 库加载模型后查看参数,参数可能会被自动转换(依据不同模型实现有所不同,部分模型参数加载后是 float32)
    • 注意:即使 config.json 中显示是 "torch_dtype": "bfloat16",在 from_pretrain 函数不显示指定参数类型的情况下,也会出现自动转换为 float32 的情况
  • 显示指定参数类型加载后,输出与指定类型一致,但是看不到原始的参数类型了
  • 下面介绍两种方法,可以直接查看某个 safetensors 文件的参数类型

方式一:命令行查看

  • 使用 hexdump 命令可以抽取部分文件查看其 dtype 信息

    1
    hexdump -C -n 4096 model_00001-of-00010.safetensors | grep -A 20 '"dtype"'
  • 这条命令的作用是查看 safetensors 模型文件的十六进制内容,并筛选出包含 “dtype” 的行及其后 20 行,以便分析模型数据类型相关信息。下面是详细解释:

    • hexdump:用于以十六进制和 ASCII 形式显示文件内容的工具
    • -C:以规范的十六进制+ASCII 格式显示,左侧为十六进制值,右侧为对应的可打印字符
    • -n 4096:仅显示文件的前 4096 个字节(4KB)
    • grep -A 20:在文本中搜索匹配模式,除了显示匹配的行外,还显示该行之后的 20 行内容(A 即 After 的缩写)
  • 执行命令后会看到类似的输出:

    1
    ..."dtype":"BF16"...

方式二:python 查看

  • 安装 safetensors 包

  • 执行下面的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from safetensors.torch import load_file

    # 加载 .safetensors 文件
    weight_file = "~/model/Qwen2.5-7B-Instruct/model-00001-of-00004.safetensors"

    state_dict = load_file(weight_file, device="cpu")

    # 查看存储类型
    for name, param in list(state_dict.items())[:5]:
    print(f"参数 {name} 在硬盘上的存储类型: {param.dtype}")
  • 输出如下:

    1
    2
    3
    4
    5
    参数 model.embed_tokens.weight 在硬盘上的存储类型: torch.bfloat16
    参数 model.layers.0.input_layernorm.weight 在硬盘上的存储类型: torch.bfloat16
    参数 model.layers.0.mlp.down_proj.weight 在硬盘上的存储类型: torch.bfloat16
    参数 model.layers.0.mlp.gate_proj.weight 在硬盘上的存储类型: torch.bfloat16
    参数 model.layers.0.mlp.up_proj.weight 在硬盘上的存储类型: torch.bfloat16
  • bfloat16 与 Qwen2.5-7B-Instruct 的 config.json 类型能对齐


附录:ckpt 中添加自定义模型类

  • 在模型 ckpt 目录(hf 文件目录)下,可以存放 *.py 文件,用于定义自定义的模型结构
  • 这些 *.py 文件会被 transformers 库加载,故而可以在 config.json 中指定使用
  • 注意:megatron 训练一般不会使用 config.json 中指定的类,而是根据各种超参加载的
  • transformers 库 AutoModelForCausalLM.from_pretrained -> AutoConfig.from_pretrained 加载模型的方式有两种:
    • 第一种:config.json 包含 model_type 参数的
      • 此时要求模型类提前备注册过
    • 第二种:config.json 不包含 model_type 参数的
      • 此时可以按照自定义的类进行初始化(定义在 *.py 中,放到 ckpt 路径下即可)
      • 执行 AutoModelForCausalLM.from_pretrained 函数时添加 trust_remote_code=True 参数,否则无法加载模型文件

Sklearn——模型方法和参数使用笔记

本文不定期更新


模型的一般使用流程

  • init
  • fit(x_train, y_train)
  • predict(x_test)

模型输出预测概率

  • 方法名称: predict_proba(x_test)
  • 该方法对于预测时使用概率或者分数的算法来说直接返回概率值,对于不能返回概率的类来说一般返回交叉验证结果的平均值等
    • NB: 概率值
    • LR: 逻辑回归的分数
    • SVM: 交叉验证生成的平均值, 这里的结果与predict预测结果可能有偏差

关于参数

  • 待补充

Pandas——为DataFrame的某一列实行OneHot编码

为DataFrame的某一列实行OneHot编码


使用OneHotEncoder进行编码

  • 基本实现思路:

    • 生成一个OneHotEncoder对象
    • 取出对应的列并处理成N*1维的数组,用其训练OneHotEncoder对象并进行编码转换
    • 将新编码的数据生成为新的DataFrame对象
      • 为新的编码每一列生成新的列名称
      • 为新的每行索引赋值为原始DataFrame对应的索引
    • 按照列合并两个DataFrame
    • 删除之前的列
  • 实现代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    from sklearn.preprocessing import OneHotEncoder

    def one_hot_for_column(df, column):
    """
    encode column of df with one hot method
    :param df: an object of DataFrame
    :param column: the name of column in df
    :return: new object of DataFrame and object of OneHotEncoder
    """
    ohe = OneHotEncoder()

    # ohe.fit(df[column].values.reshape(-1, 1))
    # col_series = ohe.transform(df[column].values.reshape(-1, 1)).toarray()
    # <==>
    col_series = ohe.fit_transform(df[column].values.reshape(-1, 1)).toarray()

    columns = ["%s_%s" % (column, str(m)) for m in range(1, col_series.shape[1] + 1)]
    sub_df = pd.DataFrame(col_series, columns=columns, dtype=int, index=df.index)
    new_df = pd.concat([df, sub_df], axis=1)
    new_df.drop(columns=column, inplace=True)
    return new_df, ohe

MySQL——Error code 28; No space left on device

首先说明这是一个MySQL错误,描述的是MySQL临时文件不能打开,空间不足


问题源头

在Ubuntu系统中,爬取数据过多,数量百万级到千万级,而且存储都是以小文件的方式存储的,造成inode的大量使用,从而发生异常,发生异常时服务器尚有20多G的硬盘空间


解决方式

将数据打包起来,然后删除打包后的数据


总结

在做数据分析时最好不要使用小文件存储数据,如果非要存储收也尽量注意打包压缩暂时不必要使用的文件

NLP——LLM排行榜


整体说明

  • 目前,大模型(如LLM、多模态模型等)的评测和排名主要通过一些权威的基准测试和第三方平台进行
  • 本文记录并持续更新一些常见的在线排名网站和评测平台,涵盖不同领域的模型能力评估

LMSYS Chatbot Arena

  • 链接:https://lmarena.ai/
  • 领域:通用大模型排名
  • 基于人类反馈的实时对战排名(如GPT-4、Claude、Gemini等)
  • 采用Elo评分机制,反映用户偏好
  • 包含闭源模型
  • Chatbot Arena LLM Leaderboard: Community-driven Evaluation for Best LLM and AI chatbots
  • LmArena(原LMSYS)是一个由加州大学伯克利分校SkyLab和LMSYS研究团队开发的开源平台,专注于通过众包方式评估和比较不同AI模型的性能

OpenCompass

  • 链接:https://rank.opencompass.org.cn/home
  • 领域:通用大模型排名、多模态模型排名、对战排名均有
  • 包含豆包、Qwen、DeepSeek等
  • 司南 OpenCompass 是由上海人工智能实验室(Shanghai AI Lab)推出的一个开源、中立、全面的 LLM 评测体系,旨在对各类大模型进行系统性、标准化的能力评估与排名

LiveCodeBench

  • 链接:https://livecodebench.github.io/leaderboard.html
  • 领域:代码能力排名

Open LLM Leaderboard (Hugging Face)

  • 链接:https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard
  • 领域:通用大模型排名
  • 评估开源大模型在多项任务(如ARC、HellaSwag、MMLU等)上的表现
  • 涵盖模型:LLaMA、Falcon、Mistral等诸多模型,还有许多名字不出名的是基于其他模型微调后改名的
  • 仅评估开源模型

Stanford HELM (Holistic Evaluation of Language Models)

  • 链接:https://crfm.stanford.edu/helm/
  • 领域:通用大模型排名
  • 斯坦福的全面评测框架,覆盖准确性、公平性、鲁棒性等维度
  • 其中可选很多评估标注,比如MMLU,Finance等

C-Eval (中文评测基准)

  • 链接:https://cevalbenchmark.com/static/leaderboard.html
  • 领域:中文测评
  • 评估中文知识、推理能力的测试集,涵盖52个学科
  • 排名包含:GPT-4、ChatGLM、通义千问等

SuperCLUE (中文通用大模型评测)

  • 链接:https://www.superclueai.com/
  • 领域:中文测评
  • 中文版综合性评测,包括基础能力、专业任务等

MMBench

  • 链接:https://mmbench.opencompass.org.cn/leaderboard
  • 领域:多模态模型排名
  • 评估图文理解、生成能力的基准(如GPT-4V、Gemini Vision)

GLUE/SuperGLUE

  • 链接:https://gluebenchmark.com/
  • 领域:自然语言理解
  • 经典NLU任务评测,但近年逐渐被更大基准取代,都是一些比较老的模型评估

NLP——词嵌入的前世今生

词嵌入的发展,NNLM,CBOW,skip-gram
词嵌入(Word Embedding)也称为词向量(Word2Vec): 指的是将词转换成向量的形式


基本问题

  • 用语言模型做预训练
    • 语言模型: 如何计算一段文本序列在某种语言下出现的概率?
  • 如何表示文本中的一个词?

文本表示模型

词袋模型

  • One-Hot: 向量维度与词的数量相同,某个维度为1,其他都为0
  • TF-IDF: 计算词对文档的贡献(权重)
  • TextRank: 类似于PageRank的思想
    • 如果一个单词出现在很多单词后面的话,那么说明这个单词比较重要
    • 一个TextRank值很高的单词后面跟着的一个单词,那么这个单词的TextRank值会相应地因此而提高
优缺点
  • OneHot:
    • 维度灾难
    • 语义鸿沟
  • TF-IDF和TextRank
    • [个人理解]也无法表示语义,所以存在语义鸿沟

主题模型

  • LSA: 矩阵分解(SVD)的方式,又名 Latent Semantic Indexing
  • pLSA: 简单的概率隐式语义模型
  • LDA: 无监督聚类常用的模型,有Gibbs Sampling和变分推断等实现,网上有很多资料,也有很多实现
  • L-LDA: LDA的有监督版本,核心思想就是在LDA吉布斯实现的版本基础上加上采样限制,使得每次采样只能控制在对应主题上,效果比较好,网上没有官方的实现,大部分实现不完全,感兴趣可以试试我的实现Labeled-LDA-Python
    • L-LDA理论上可以得到比LDA质量更高,效果更好的词向量
优缺点:
  • LSA:
    • 利用全局语料特征
    • 但SVD求解计算复杂度大

基于词向量的固定表征

  • Word2vec: 基于上下文训练, 拥有相同上下文的词相近,基于分布式假设(相同上下文语境的词有似含义)
  • FastText: 通过对”词-词”共现矩阵进行分解从而得到词表示的方法,基于分布式假设(相同上下文语境的词有似含义)
  • GloVe: 基于全局预料,结合了LSA和word2vec的优点, 论文: GloVe: Global Vectors for Word Representation
优缺点
  • 目前提到的以上所有都是静态词向量,无法解决一次多义等问题
  • Word2vec和FastText:
    • 优化效率高,但是基于局部语料
    • 本质上二者也都是语言模型
  • GloVe:
    • 基于全局语料库、并结合上下文语境构建词向量, 结合了LSA和word2vec的优点
    • 可以看作是更换了目标函数和权重函数的全局word2vec

基于词向量的动态表征

  • ELMo:
    • 采样 LSTM 提取特征
    • 采用双向语言模型
    • 实际上是两个单向语言模型(方向相反)的拼接,这种融合特征的能力比BERT一体化融合特征方式弱
  • GPT:
    • 采样 Transformer 进行特征提取
    • 采用单向语言模型
  • BERT:
    • 采用Transformer进行特征提取
    • 采用双向语言模型
优缺点
  • 三者都是基于语言模型的动态词向量,能解决一次多义问题
  • ELMo:
    • 采用1层静态向量+2层 LSTM,多层提取能力有限
  • GPT和BERT:
    • Transformer 可采用多层,并行计算能力强
  • 很多任务表明:
    • Transformer 特征提取能力强于 LSTM
  • GPT和BERT都采用 Transformer,Transformer 是 encoder-decoder 结构,GPT 的单向语言模型采用 decoder 部分,decoder 的部分见到的都是不完整的句子;BERT 的双向语言模型则采用 encoder 部分,采用了完整句子

NNLM/RNNLM

  • 词向量为副产物,存在效率不高等问题;

不同模型的对比

word2vec vs NNLM

  • 本质上都可以看做是语言模型
  • 对 NNLM 来说,目不是词向量,是语言模型
  • word2vec 虽然本质上也是语言模型,但是更关注词向量本身,因此做了很多优化来提高计算效率
    • 与 NNLM 相比,词向量直接 sum(CBOW),而不是拼接,并取消隐藏层
    • 考虑到 Softmax 需要遍历整个词汇表,采用 Hierarcal Softmax和 Negative Sampling 进行优化
    • word2vec 所做的一切都是为了一切为了快速生成词向量

word2vec vs fastText

  • 都可以进行无监督学习, fastText 训练词向量时会考虑 subword(子词)
    • 在 fastText 中,每个中心词被表示成子词的集合,下面我们用单词 “where” 作为例子来了解子词是如何产生的
    • 首先,我们在单词的首尾分别添加特殊字符“<”和“>”以区分作为前后缀的子词
    • 然后,将单词当成一个由字符构成的序列来提取 n 元语法
      • 例如,当n=3时,我们得到所有长度为3的子词:“<wh>” “whe” “her” “ere” “<re>”以及特殊子词“<where>”
  • fastText还可以进行有监督学习进行文本分类:
    • 结构与CBOW类似,但学习目标是人工标注的分类结果, 而不是中心词 \(w\)
    • 采用hierarchical softmax对输出的分类标签建立哈夫曼树,样本中标签多的类别被分配短的搜寻路径;
    • 引入N-gram,考虑词序特征;
    • 引入subword(子词)来处理长词,处理未登陆词问题

word2vec vs GloVe vs LSA

  • word2vec vs GloVe
    • 语料库:
      • word2vec是局部语料库训练的,特征提取基于滑动窗口,可以在线学习
      • GloVe的滑动窗口是为了建立”词-词”共现矩阵,需要统计共现概率,不能在线学习
    • 无监督学习:
      • word2vec是无监督学习
      • GloVe通常被认为是无监督学习(无需标注),但实际上GloVe还是有label的,即共现次数 \(log(X_{ij})\)
    • 损失函数:
      • word2vec损失函数实质上是带权重的交叉熵,权重固定;
      • GloVe的损失函数是最小平方损失函数,权重可以做映射变换
    • 总结:
      • word2vec的损失函数是带权重的交叉熵 , 权重是固定的
      • GloVe可以看作是目标函数为MSE ,权重函数可变的全局word2vec
  • GloVe vs LSA
    • LSA(Latent Semantic Analysis)可以基于co-occurance matrix构建词向量,实质上是基于全局语料采用SVD进行矩阵分解,然而SVD计算复杂度高;
    • GloVe可看作是对LSA一种优化的高效矩阵分解算法,采用Adagrad对最小平方损失进行优化;

ELMo、GPT、BERT

  • 三者使用了两种不同的NN组件提取特征
    • ELMo: LSTM
    • GPT, BERT: Transformer
  • 三者使用了两种不同的语言模型:
    • GPT: 单向语言模型
    • ELMo, BERT: 双向语言模型
    • ELMo实际上是两个方向相反的单向语言模型的拼接, 融合特征的能力比BERT那种一体化的融合特征方式弱
    • GPT和BERT都采用Transformer,Transformer是 Encoder-Decoder结构
      • GPT为单向语言模型,采用的是Decoder部分, Decoder部分见到的都是不完整的句子
      • BERT为双向语言模型,采用的是Encoder部分,采用了完整的句子

下面是一些模型的详细介绍


NNLM

模型目标

  • 给定一段长度为m的序列时,预测下一个词(第m+1)个词出现的概率
  • 参考博客DL——NNLM

word2vec

  • 此处只做简单介绍,更详细的讲解请参考博客word2vec学习笔记
  • 一个比较好的手写笔记版:通俗易懂讲解Word2vec的本质 - 对白的文章 - 知乎
  • 损失函数: 带权重的交叉熵损失函数(权重固定)

两类实现

  • 一般实现: 每次训练一个样本 \((w_{in}, w_{out})\),需要计算所有词和当前词一起对应的 softmax, 很耗时间,需要 \(O(V)\) 复杂度的时间
  • 优化实现: Hierarcal Softmax 和 Negative Sampling 两种方式
    • Hierarcal Softmax: 每次训练一个样本 \((w_{in}, w_{out})\),只需要更新平均 \(O(log V)\) 个非叶子节点(每个非叶子结点就是一个词向量)即可
    • Negative Sampling: 每次训练一个样本 \((w_{in}, w_{out})\),只需要更新 \({w_j|w_j\in {w_O}\bigcup W_{neg}}\) 个词向量, 通常负样本的集合大小取 \(log(V)\) 量级甚至更小
层次 Softmax 模型框架
  • 层次 Softmax(Hierarchical Softmax),也称为层次化 Softmax
  • 对于词表大小为 \(V\) 的场景,如果使用普通的 Softmax,则每次需要在分母上计算 \(V\) 次指数运算并求和,使用 层次 Softmax 后转化为 \(\log(V)\) 次二分类任务
  • 核心思想: 输出层由语料库中词出现的频数当作权值构造出的哈夫曼树作为输出
  • 引入哈夫曼树 , Hierarcal Softmax是一种有效计算Softmax的方式,使用二叉树来表示
  • 其中Hierarchical Softmax模型的输出层由语料库中词出现的频数当作权值构造出的哈夫曼树作为输出
  • CBOW
    • 输入层: \(2c\)个词向量
    • 投影层: \(2c\)个词向量的累加
    • 输出层: 哈夫曼树(重点是词w所在的叶子节点, 以及w到根节点的路径)
      • 所有单词没有输出向量表示形式,每个内部结点有一个输出向量 \(v\)
      • 输出层共有 \(V - 1\) 个非叶节点, 也就是要学习 \(V - 1\) 个输出向量
      • 看起来并没有什么优化,但是每次迭代训练一个样本 \(w_{in}, w_{out}\) 时,我们只需要优化从根节点到输出单词 \(w_{out}\) 的路径上的输出向量即可, 平均共 \(O(log V)\) 个向量
      • 每个单词的概率计算需要考虑叶子节点来求出
    • 传统softmax公式 :在传统的softmax函数中,计算目标词与所有词汇之间的概率分布公式为\(P ( w_t | C ) = \frac{e^{v_{w_t}^T v_{w_c} } }{\sum_{w’} e^{v_{w’}^T v_{w_c} } }\),其中\(w_t\)是目标词,\(w_c\)是上下文词,\(v_{w_t}\)和\(v_{w_c}\)是目标词和上下文词的词向量
      • 其中:\(v_{w_c}\) 和 \(v_{w_t}\) 就是我们要学习的词向量
    • 层次softmax公式 :给定一个目标词\(w_t\),上下文词\(w_c\),通过霍夫曼树计算从目标词到上下文词的路径概率。假设从根节点到叶节点的路径上有多个节点,对于目标词\(w_t\),路径\(P\)到达目标词,要最大化的概率公式为\(P ( w_t | C ) = \prod_{k = 1}^{L} \sigma(v_{w_t}^T v_{n_k})\)。其中\(L\)是路径的长度(即路径上的节点数),\(n_k\)是路径上的第\(k\)个节点(非叶子节点),\(v_{w_t}\)是目标词的词向量,\(v_{n_k}\)是路径节点\(n_k\)的词向量。每一个路径的概率通过sigmoid函数计算:\(\sigma(x) = \frac{1}{1 + e^{-x} }\)
      • 其中:\(v_{w_t}\) 就是我们要学习的词向量
  • Skip-gram
    • 输入层:词 \(w\) 的向量
    • 投影层:依旧是词 \(w\) 的向量
    • 输出层:哈夫曼树(重点是词 \(w\) 的上下文窗内 \(2c\) 个词所在的叶子节点,以及各自到根节点的路径)
Negative Sampling模型框架
  • 实际上就是简单的对每一个样本中每一个词都进行负例采样(本质上就是用负采样代替了层次softmax的哈弗曼树)
  • 负采样是噪声对比估计的一个简化版本,目的是提高训练速度并改善所得词向量的质量
  • 核心思想: 在每次迭代过程中, 有大量的输出向量需要更新,为了解决这一困难, Negative Sampling的做法是只更新其中一部分输出向量
  • 利用不同词在语料中出现的频次多少来决定被采样到的概率(单词出现的频次越大,越可能被选做负样本)
  • 负采样: 利用不同词在语料库中出现的频次多少来决定该词被采样到的概率
  • 每次训练一个样本 \((w_{in}, w_{out})\),只需要更新 \({w_j|w_j\in {w_O}\bigcup W_{neg}}\) 个词向量, 通常负样本的集合大小取 \(log(V)\) 量级甚至更小
  • CBOW
    • 输入层: \(2c\)个词向量
    • 投影层:\(2c\)个词向量的累加
    • 输出层:负采样词集(重点是词w的负词词集的参数 \(\theta\),负词的概率永远是1-Sigmoid函数值)
  • Skip-gram模型:
    • 输入层:词w的向量
    • 投影层:依旧是词w的向量
    • 输出层:每个上下文词u的负采样(重点是词w的负词词集的参数 \(\theta\),负词的概率永远是1-Sigmoid函数值)
总结
  • 层次Softmax模型:
    • CBOW模型的一次更新是:
      • 输入 \(2c\) 个词向量的累加(简单的sum,而不是拼接)
      • 对中心词 \(w\) 上的路径节点系数进行更新(输出层)
      • 对所有的上下文词的词向量进行整体一致更新(输入层到隐藏层的参数, 修改多个词向量)
    • Skip-gram模型的一次更新是:
      • 输入中心词 \(w\) 的词向量(直接输入,无其他操作)
      • 对每个上下文词 \(u(i)\) 所在的路径上的节点系数进行更新(输出层,修改多个上下文的结点)
      • 对词w的词向量进行单独更新(输入层到隐藏层的参数,只修改一个词向量)
    • CBOW一次训练更新计算量小,Skip-gram一次训练计算量大(更新的系数更多?)
  • CBOW看起来更新的更平滑,适合小量文本集上的词向量构建,Skip-gram每次更新都更加有针对性,所以对于大文本集上表现更好

word2vec的缺陷

  • 不能解决多义词问题(只能把几种意思同时编码进向量里)
    • 这是所有固定词向量的通病
    • 解决方案是动态词向量(允许不同上下文使用不同词向量表达同一个词),包括ELMo, GPT, BERT

NLP——WizardLM(Evol-Instruct)

注:本文包含 AI 辅助创作

  • 参考链接:
    • 原始论文:(Evol-Instruct)WizardLM: Empowering large pre-trained language models to follow complex instructions, Microsoft & PKU, arXiv 20230424, 20230610, 20250527
    • 相关 GitHub 地址:github.com/nlpxucan/evol-instruct

Paper Summary

  • 整体说明:
    • 论文提出了一种为 LLM 生成多样化和复杂指令数据的进化算法 Evol-Instruct(使用 LLM 而非人类来创建大量不同复杂度指令数据的途径),并基于此数据集微调得到了 LLaMA(得到 WizardLM)
    • WizardLM 在一系列公认的基准测试中显著超越了典型的开源 LLM,如 Alpaca 和 Vicuna
    • WizardLM 在代码、数学、GPT-4 和人工评估方面均以显著优势超越基线模型
  • 背景 & 问题:
    • 使用开放域指令跟随数据训练 LLM 已经取得了巨大成功
    • 问题1:人工创建此类指令数据非常耗时且劳动密集
    • 问题2:人类可能难以生成高复杂度的指令
  • 基本思路:从一个初始指令集出发,论文使用提出的 Evol-Instruct 方法逐步将其重写为更复杂的指令
  • 模型训练:论文将所有生成的指令数据混合以微调 LLaMA(论文将得到的模型称为 WizardLM)
    • 自动评估和人工评估均一致表明, WizardLM 的性能优于基线模型,如 Alpaca(基于 Self-Instruct 训练)和 Vicuna(基于人工创建的指令训练)
    • 论文通过实验结果证明:由 Evol-Instruct 精心构建的指令跟随数据集的质量能够显著提升 LLM 的性能

Introduction and Discussion

  • LLM 已成为众多自然语言处理任务的首选方法 (2020; 2022; 2023)
  • LLM 在大规模文本数据上进行训练以预测后续 Token ,使其能够针对各种输入生成连贯流畅的文本
  • 然而,这些模型通常难以遵循用户指定的指令或目标,这限制了它们在现实场景中的实用性和适用性
  • NLP 界近期见证了众多努力,旨在训练 LLM 更好地遵循指令并变得更有帮助 (2023;)
    • 训练指令跟随语言模型的初步尝试 (2022; 2021; ) 基于一系列不同的 NLP 任务集合,并辅以少量手写指令
  • 这些封闭域指令存在两个主要缺点:
    • 首先,一个 NLP 数据集中的所有样本仅共享少数几个常见指令,严重限制了其多样性;
    • 其次,指令通常只要求完成一项任务 (但在现实生活中,人类的指令通常具有多个且多样的任务需求)
  • 通过使用真实用户生成的开放域指令数据,OpenAI 的 LLM(例如 InstructGPT (2022) 和 ChatGPT)取得了巨大成功
    • 这些开放域指令能够充分释放 LLM 的无限潜力 (2023; ),并使它们能够执行更复杂多样的任务
  • 但像 OpenAI 那样使用人类创建开放域指令数据集会遇到以下挑战:
    • 整个标注过程极其昂贵且耗时 (2023; )
    • 人工创建指令的难度级别分布偏向于简单或中等,困难指令较少(根据图 5a 中 ShareGPT (2023) 的难度统计)
    • 人类标注者容易疲劳,无法持续高强度工作以产生足够比例的高难度指令 (2023; )
  • 基于这些问题,开发一种能够以相对较低成本大规模自动生产开放域指令(尤其是更困难的指令)的方法,成为进一步推进指令微调语言模型(instruction-tuned language models)的关键 (2023; )
  • 在这项工作中,论文引入了 Evol-Instruct ,一种使用 LLM 而非人类来自动大规模生成不同难度级别开放域指令的新方法,以提升 LLM 的性能
  • 图 1 展示了 Evol-Instruct 的运行示例
  • 从一个简单的初始指令 “1+1=?” 开始,论文的方法随机选择深度演化(In-depth Evolving)(蓝色方向线)或广度演化(In-breadth Evolving)(红色方向线)来将简单指令升级为更复杂的指令或创建新指令(以增加多样性)
    • 深度演化包括五种操作类型:添加约束(add constraints)、深化(deepening)、具体化(concretizing)、增加推理步骤(increase reasoning steps)和复杂化输入(complicate input)
    • 广度演化是突变(mutation) ,即基于给定指令生成一个全新的指令
    • 这六种操作通过使用特定的提示词(prompt)来提示(prompting)一个 LLM 来实现
  • 由于演化后的指令是由 LLM 生成的,有时演化会失败
    • 论文采用一个指令淘汰器(instruction eliminator)来过滤失败的指令,这被称为淘汰演化(Elimination Evolving)
    • 论文重复这个进化过程若干轮,以获得包含各种复杂度的足够指令数据
  • 为了验证 Evol-Instruct 的有效性以及它创建的用于微调的指令是否超越人类创建的指令
    • 论文演化来自 Alpaca (2023) 数据(由机器创建)的指令,微调 LLaMA (2023) 模型,并全面比较微调后的模型 WizardLM 与在 ShareGPT(指令由人类创建)上训练的 Vicuna (2023)
      • Alpaca 数据总共有 \(52k\) 个样本,是使用 self-instruct (2022a) 从仅 \(175\) 个人工创建的种子指令生成的
      • 论文选择 Alpaca 数据作为演化的初始数据,这可以确保 WizardLM 的训练指令几乎没有人直接参与标注
    • 论文使用 OpenAI ChatGPT API 执行了四轮演化 ,最终获得 \(250k\) 条指令
    • 为了与 Vicuna 的 \(70k\) 真实用户数据进行公平比较
      • 论文从完整的 \(250k\) 数据中采样了 \(70k\) 条指令 ,并微调了 LLaMA 13B 模型
    • 由于原始 Alpaca 数据只有 \(52k\) 个样本,论文使用其 self-instruct 方法生成了额外的 \(18k\) 数据,并使用其代码重新训练了 LLaMA 13B 模型,得到 Alpaca 13B 作为论文的基线
    • 由于先前指令跟随测试数据集中困难指令比例较低 ,论文手动创建了一个新的难度平衡的测试数据集 ,命名为 WizardEval
  • 论文在广泛的 LLM 基准测试(涵盖推理、代码、数学、通用对话等)上评估了 Alpaca、Vicuna、ChatGPT 和 WizardLM
  • 论文的主要发现如下:
    • 论文引入了 Evol-Instruct ,一种通过自动大规模生成各种主题和难度级别的开放域指令来大幅提升开源 LLM 性能的新方法
    • 论文开发了 WizardLM 模型,其在一系列基准测试中显著超越了典型的开源 LLM,如 Alpaca 和 Vicuna
      • WizardLM 在代码、数学、GPT-4 和人工评估方面均以显著优势优于基线模型
    • 论文进行了一项初步研究,强调了指令复杂度在监督微调大规模预训练语言模型中取得出色性能的重要性

Approach

  • 本节将详细阐述所提出的 Evol-Instruct 的细节
  • 如图 2 所示,该流程主要包含两个组件:
    • 指令演化器(Instruction Evolver)
    • 指令淘汰器(Instruction Eliminator)
  • 这些组件的细节将在第 3.2 节中介绍,指令微调方法将在第 3.3 节中描述

Definition of Instruction Data Evolution(指令数据演化)

  • 论文从给定的初始指令数据集开始演化:
    $$D^{(0)}=(I_{k}^{(0)},R_{k}^{(0)})_{1\leq k\leq N}$$
    • 其中 \(I_{k}^{(0)}\) 是 \(D^{(0)}\) 中的第 \(k\) 条指令
    • \(R_{k}^{(0)}\) 是第 \(k\) 条指令的相应响应
    • \(N\) 是 \(D^{(0)}\) 中的样本数量
  • 在每次演化中,论文通过使用 Evol-Instruct 提示词提示(prompting)一个 LLM
    • 将 \(D^{(t)}\) 中的所有 \(I^{(t)}\) 升级为 \(I^{(t+1)}\),然后使用该 LLM 为新演化出的 \(I^{t+1}\) 生成相应的响应 \(R^{t+1}\)
    • 从而,论文获得一个演化后的指令数据集 \(D^{t+1}\)
  • 通过迭代执行 \(M\) 次演化,我们可以顺序获得 \(M\) 个演化数据集:
    $$[D^{(1)}\cdots D^{(M)}]$$
  • 论文的工作专注于开放域指令数据,其中指令具有变化的输入和任务,指令部分和输入部分之间没有明确的区分

Automatic Instruction Data Evolution

  • 论文的指令演化流程包括三个步骤:
    • 1) 指令演化(instruction evolving)
    • 2) 响应生成(response generation)
    • 3) 淘汰演化(elimination evolving),即过滤未能成功演化的指令
Instruction Evolution
  • 论文发现 LLM 可以使用特定的提示词使给定的指令变得更加复杂和困难。此外,它们可以生成完全全新、复杂度相当但完全不同的指令。利用这一发现,我们可以迭代地演化一个初始指令数据集,提高其难度级别并扩展其丰富性和多样性。论文使用给定的初始指令数据集 \(D^{(0)}\) 初始化指令池(instruction pool)。在每个演化轮次(epoch)中,从前一轮次升级的指令被从池中取出。然后论文利用指令演化器(instruction evolver)来演化每个取出的指令,并利用指令淘汰器(instruction eliminator)来检查演化是否失败。成功演化的指令被添加到池中,而不成功的指令则原样放回,希望在下个演化轮次中能成功升级它们
Instruction Evolver
  • 指令演化器是一个使用 Evol-Instruct 提示词来演化指令的 LLM,有两种类型:深度演化和广度演化
In-Depth Evolving
  • 通过五种类型的提示词来增强指令,使其更复杂和困难:

    • 添加约束(add constraints)、深化(deepening)、具体化(concretizing)、增加推理步骤(increased reasoning steps)和复杂化输入(complicating input)
  • 深度演化提示词的核心部分是“您的目标是将给定的提示词重写为一个更复杂的版本,以使那些著名的 AI 系统(例如 ChatGPT 和 GPT4 (OpenAI, 2023))更难处理。但重写后的提示词必须是合理的、可被人类理解并回应”

  • 论文要求 LLM 创建具有挑战性但合理且非 AI 任意想象的指令

  • 需要逐步增加难度以避免指令集中充斥极其复杂的指令,这会损害训练模型的泛化性能

  • 为了控制难度增加,论文使每次演化“更难一点”,并限制最多添加 10 到 20 个单词

  • 在上述五种演化中,除了复杂化输入(complicating input)外,其他都可以在没有任何上下文示例(in-context examples)的情况下实现

  • 论文展示添加约束的提示词如下(深化、具体化和增加推理步骤的提示词将在附录 A-C 中详述)

  • 示例 3.1:深度演化中添加约束的提示词(Prompt for Adding Constraints of In-Depth Evolving)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    I want you act as a Prompt Rewriter.
    Your objective is to rewrite a given prompt into a more complex version to make those famous AI systems (e.g., ChatGPT and GPT4) a bit harder to handle. But the rewritten prompt must be reasonable and must be understood and responded by humans.
    Your rewriting cannot omit the non-text parts such as the table and code in #Given Prompt#:. Also, please do not omit the input in #Given Prompt#.
    You SHOULD complicate the given prompt using the following method:
    **Please add one more constraints/requirements into #Given Prompt#**
    You should try your best not to make the #Rewritten Prompt# become verbose, #Rewritten Prompt# can only add 10 to 20 words into #Given Prompt#. ‘#Given Prompt#’, ‘#Rewritten Prompt#’, ‘given prompt’ and
    ‘rewritten prompt’ are not allowed to appear in #Rewritten Prompt#
    #Given Prompt#:
    {Here is instruction.} #Rewritten Prompt#:

    我希望您扮演一个提示词重写器(Prompt Rewriter)
    您的目标是将给定的提示词重写为一个更复杂的版本,以使那些著名的 AI 系统(例如 ChatGPT 和 GPT4)更难处理。但重写后的提示词必须是合理的、可被人类理解并回应
    您的重写不能省略 #给定提示词# 中的非文本部分,例如表格和代码。同时,请不要省略 #给定提示词# 中的输入
    您**应该**使用以下方法使给定提示词复杂化:
    **请向 #给定提示词# 中添加一个更多的约束/要求**
    您应尽力避免使 #重写后的提示词# 变得冗长,#重写后的提示词# 只能在 #给定提示词# 的基础上增加 10 到 20 个单词。“#给定提示词#”、“#重写后的提示词#”、“给定提示词”和“重写后的提示词”不允许出现在 #重写后的提示词# 中
    **#给定提示词#:**
    {这里是指令。}
    **#重写后的提示词#:**
  • 对于复杂化输入(complicating input),论文将使用上下文演示(in-context demonstration)。由于演示较长,论文在下面提供一个简要模板,完整提示词详见附录 D

  • 示例 3.2:深度演化中复杂化输入的提示词(Prompt for Complicating Input of In-Depth Evolving)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    I want you act as a Prompt Rewriter.
    Your objective is to rewrite a given prompt into a more complex version to make those famous AI systems (e.g., ChatGPT and GPT4) a bit harder to handle. But the rewritten prompt must be reasonable and must be understood and responded by humans.
    You must add [XML data] format data as input data in [Rewritten Prompt]
    #Given Prompt#:
    {Here is instruction of Example 1.}
    #Rewritten Prompt#:
    {Here is rewritten instruction of Example 1.} ... N -1 Examples ...
    You must add [#Given Dataformat#] format data as input data in [Rewritten Prompt] #Given Prompt#:
    {Here is instruction of Example N.}
    #Rewritten Prompt#:

    我希望您扮演一个提示词重写器(Prompt Rewriter)
    您的目标是将给定的提示词重写为一个更复杂的版本,以使那些著名的 AI 系统(例如 ChatGPT 和 GPT4)更难处理。但重写后的提示词必须是合理的、可被人类理解并回应
    您必须在 [重写后的提示词] 中添加 [XML 数据] 格式的数据作为输入数据
    **#给定提示词#:**
    {这里是示例 1 的指令。}
    **#重写后的提示词#:**
    {这里是示例 1 重写后的指令。}
    ... N -1 个示例 ...
    您必须在 [重写后的提示词] 中添加 [#给定数据格式#] 格式的数据作为输入数据
    **#给定提示词#:**
    {这里是示例 N 的指令。}
    **#重写后的提示词#:**
In-Breadth Evolving
  • 广度演化旨在增强主题覆盖度、技能覆盖度以及整体数据集的多样性
  • 开放域指令微调数据集(例如 Alpaca、ShareGPT 等)通常规模较小,缺乏主题和技能多样性
  • 为了解决这个问题,论文设计了一个提示词,基于给定指令生成一个全新的指令,要求新指令更加长尾(more long-tailed)。论文的广度演化提示词如下:
  • 示例 3.3:广度演化的提示词(Prompt for In-Breadth Evolving)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    I want you act as a Prompt Creator.
    Your goal is to draw inspiration from the #Given Prompt# to create a brand new prompt.
    This new prompt should belong to the same domain as the #Given Prompt# but be even more rare.
    The LENGTH and difficulty level of the #Created Prompt# should be similar to that of the #Given Prompt#. The #Created Prompt# must be reasonable and must be understood and responded by humans.
    ‘#Given Prompt#’, ‘#Created Prompt#’, ‘given prompt’ and ‘created prompt’ are not allowed to appear in #Created Prompt#.
    #Given Prompt#:
    {Here is instruction.} #Created Prompt#:

    我希望您扮演一个提示词创建者(Prompt Creator)
    您的目标是从 #给定提示词# 中汲取灵感,创建一个全新的提示词
    这个新提示词应该与 #给定提示词# 属于同一领域,但应更加罕见(rare)
    #创建出的提示词# 的长度和难度级别应与 #给定提示词# 相似
    #创建出的提示词# 必须是合理的、可被人类理解并回应
    “#给定提示词#”、“#创建出的提示词#”、“给定提示词”和“创建出的提示词”不允许出现在 #创建出的提示词# 中
    #给定提示词#:
    {这里是指令。}
    #创建出的提示词#:
Response Generation
  • 论文使用与演化相同的 LLM 来为演化后的指令生成相应的响应
  • 生成提示词是 “{Here is instruction.}”,论文将其输入到 ChatGPT-3.5 的请求中,并将返回的文本正文解析为响应
Elimination Evolving(淘汰演化)
  • 论文将以下四种情况归类为指令演化失败:
    • 1)演化后的指令与原始指令相比未提供任何信息增益
      • 论文使用 ChatGPT 来进行此判断,详情请参阅附录 G
    • 2)演化后的指令使得 LLM 难以生成响应
      • 论文发现当生成的响应包含“抱歉(sorry)”且长度相对较短(即少于 80 个单词)时,通常表明 LLM 难以响应演化后的指令
      • 因此我们可以使用此规则进行判断
    • 3)LLM 生成的响应仅包含标点符号和停用词(stop words)
    • 4)演化后的指令明显复制了演化提示词中的某些词语

Finetuning The LLM On The Evolved Instructions

  • 所有演化完成后,论文将初始指令数据集与所有轮次中演化得到的指令数据合并,并对样本进行随机打乱,以创建用于微调的数据集
    • 这种处理方式确保了数据集中不同难度级别的指令均匀分布,从而最大化模型微调的平滑性
  • 为了证明性能提升并非源于合并后数据量的增加,而是源于论文提出的新方法 Evol-Instruct,论文从合并后的数据中随机抽取与训练基线模型(例如 Vicuna)等量的数据,作为论文最终的微调数据
  • 论文选择 Vicuna 的提示词(prompt)作为论文微调所用的提示词,其具体格式为:“A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user’s questions. USER: Hi ASSISTANT: Hello. USER: Who are you? ASSISTANT: I am WizardLM ……”

Experiment

  • 论文通过自动评估和人工评估两种方式对 WizardLM、Alpaca、Vicuna 和 ChatGPT 进行了评估

Baselines

  • (1) ChatGPT 是由 OpenAI 开发的一款 AI 聊天机器人,能够以自然且引人入胜的方式与用户互动
    • 它建立在 GPT-3.5 和 GPT-4 等 LLM 之上,并基于海量的互联网文本数据进行训练
  • (2) Alpaca 是由斯坦福大学开发的开源指令遵循模型
    • 为了公平比较,论文使用 Alpaca 采用的 Self-Instruct 方法将指令数量从 52k 扩展到 70k,并将原始的 David+003 响应替换为 ChatGPT 的响应
    • 论文基于这份新的 Alpaca 数据,从 LLaMA 13B (2023) 重新训练了 Alpaca 13B
  • (3) Vicuna 基于 LLaMA,并在从 ShareGPT 收集的 70k 用户共享对话上进行了微调
    • 它是目前最先进、最通用的开源指令遵循模型之一
    • 论文使用来自 FastChat 的 13B-v1.1 模型
  • (4) 基于 Llama 13B 训练的开源模型,包括 Baize (2023)、CAMEL (2023a) 和 Tulu (2023)

Experiment detail

  • 为了构建数据集,论文使用 Alpaca 的 \(52k\) 指令数据集进行初始化,并迭代执行 \(M\) 轮演化,其中 \(M=4\)
  • 在每一轮演化中,对于每条指令,论文以相等概率从总共六个演化提示(即五个来自深度演化,一个来自广度演化)中随机选择一个
    • 论文使用 Azure OpenAI ChatGPT API5 执行上述过程
    • 然后,论文利用 ChatGPT 生成响应
    • 最终,论文获得了 \(250k\) 条指令
  • 为了公平比较,论文从 \(250k\) 数据中以相等概率随机采样 \(70k\) 数据作为 WizardLM 的最终训练数据,与 Vicuna 的训练数据量相同
    • 论文使用温度为 1 来生成响应,并将生成的最大 token 数设置为 2048
    • 此外,论文将频率惩罚设置为零,top-p 设置为 \(0.9\)
    • 总共,论文请求 API \(52k\times 4\times 3=624k\) 次以构建完整的数据集
  • 论文使用预训练的 LLaMA 13B (2023) 来初始化论文的模型
    • 论文采用 Adam 优化器,初始学习率为 \(2\times 10^{-5}\),最大 token 数为 2048,每个 GPU 的批次大小为 4
  • 论文在 8 个 V100 GPU 上使用 Deepspeed Zero-3 训练了论文的模型 3 个 epoch ,耗时 140 小时
  • 对于推理,论文对 WizardLM 和基线模型使用贪心搜索,并将最大生成长度设置为 2048

Automatic Evaluation

  • 为了全面概述论文的 WizardLM 的性能,论文在多个 LLM 基准测试中对论文的模型与既定基线进行了比较
  • HuggingFace 的 OpenLLM 排行榜 :(2023) 包括 MMLU (2020)、ARC (2018)、HellaSwag (2019) 和 TruthfulQA (2022)
    • MMLU 包含一系列多项选择的学术问题
    • ARC 是一组小学科学问题
    • HellaSwag 是一个常识推理测试
    • TruthfulQA 衡量模型再现错误陈述的倾向
    • 论文采用了 OpenLLM 的评估代码 (2021)
  • 代码生成 (Code Generation)
    • 论文使用广泛使用的 HumanEval (2021) 基准测试,该测试包含 164 个编码问题,通过报告 pass@1 指标来评估 LLM 在函数级别的代码编写能力
  • 数学推理 (Math Reasoning)
    • 论文使用 GSM8k (2021) 来评估模型的数学能力,GSM8k 包含 1319 个小学数学测试数据
    • 论文采用 4-shot 测试并报告 pass@1
  • GPT-4 评估 (GPT-4 Evaluation)
    • 论文采用了两个广泛认可的 GPT-4 评估基准,包括 AlpacaEval (2023c) 和 MT-Bench (2023)
    • 论文还使用 GPT-4 在论文后续提出的 WizardEval 上评判 LLM
  • 如图 3 和表 1 所示,与其他相同规模的开源模型相比, WizardLM 在大多数基准测试中都具有显著的性能优势。特别是在数学、代码和 GPT-4 评估方面,它相比 Alpaca、Vicuna、Baize、CAMEL 和 Tulu 取得了显著提升

Human evaluation

  • 为了评估 WizardLM ,论文在论文精心制作的测试平台 WizardEval 上进行了人工评估,该测试集包含 218 条来自不同来源(如在线开源项目(Github, ShareGPT)、平台(Twitter)和论坛(Reddit, Discord)的真实世界人类指令
    • 数据包含 29 项技能和领域,代表了人类的主要需求,例如代码生成(Coding Generation)、数学(Math)、推理(Reasoning)、复杂格式(Complex Formats)、写作(Writing)、广泛学科(Extensive Disciplines)等
  • 如图 3(a) 和附录图 6 所示,论文还分别分析了 WizardEval 的难度和技能分布,这表明 WizardEval 能够处理比 Self-Instruct 和 Vicuna 测试集更复杂和要求更高的场景的评估
  • 论文在 WizardLM-13b 和基线模型之间进行了盲法成对比较
    • 论文招募了 10 名受过良好教育的标注员
    • 向每位标注员展示来自 Alpaca-13b、Vicuna-13b、 WizardLM 和 ChatGPT 的四条响应,这些响应被随机打乱以隐藏其来源
  • 然后,标注员根据以下标准(详细定义请参阅附录 K)判断哪个响应更好:
    • (1) 相关性(Relevance)
    • (2) 知识性(Knowledgeable)
    • (3) 推理(Reasoning)
    • (4) 计算(Calculation)
    • (5) 准确性(Accuracy)
  • 然后,他们应将四个响应从 1 到 5 排名(1 表示最好),并允许对可比较的实例给出相同的分数
    • 为了估计胜率,论文比较了每对模型之间的获胜、失败和平局频率
  • 如图 4 (b) 所示
    • WizardLM 取得了比 Alpaca 和 Vicuna 好得多的结果,这证明了 Evol-Instruct 方法的有效性
    • 所有的 Kappa 分数均大于 0.6,这表明标注员之间具有良好的一致性

Ablation Study

  • 使用不同的数据(种子、大小)、演化模型和基础模型大小进行训练 (Training with different data (seed, size), evol model, and base model size)
    • 为了研究不同数据种子、演化模型、演化数据集规模、预训练模型对论文提出的方法的影响,论文进行了以下实验:
      • a)使用 70k ShareGPT 作为种子数据获得 WizardLM-13b (ShareGPT Seed);
      • b)使用 LlaMA-2-70B-Chat 替代 ChatGPT 作为演化执行模型获得 WizardLM-13b (LlaMA-2-70B-Chat Evol);
      • c)论文在更大规模的预训练模型 Llama-1 65B 和 Llama-2 70B 上训练,分别获得 WizardLM-65b 和 WizardLM-70b;
      • d)使用完整的 250k 演化数据获得 WizardLM-13b (250K);
      • e)使用与 LlaMA 系列完全不同的基础模型 Mistral-7B,获得 WizardLM-7b (Mistral);
      • f)为了比较更多样化的指令数据,论文选择 Supernatural Instructions (2022b) 并随机抽取 70k 数据训练 llama-13b 获得 LlaMA-13b (SNI)
    • 完整结果如表 2 所示:
      • 为了探究 WizardLM-13b (ShareGPT Seed) 在 GSM8k 上表现较差的原因,论文分别从 ShareGPT 和 Alpaca 数据中随机采样 2000 条指令,然后使用 ChatGPT 判断(提示词请参阅附录 G)一条指令是否与“数学”相关,论文发现 ShareGPT 仅包含 4.3% 的数学数据,而 Alpaca 数据包含 11.8% 的数学数据,因此作者认为较少的数学数据导致 WizardLM-13b (ShareGPT Seed) 的 GSM8k 性能较差
    • 表2结果表明:
      • (i) ShareGPT 是比 Alpaca 更好的 evol-instruct 种子;
      • (ii) 更大的演化数据规模可以提高模型能力;
      • (iii) 论文提出的 Evol-Instruct 方法不依赖于 ChatGPT,其他强大的开源模型如 Llama-2 也是 ChatGPT 的良好替代品;
      • (iv) 论文的演化数据也显示出比 Supernatural Instructions 更好的微调性能
      • 此外,在不同预训练基础(例如 Llama-1 65B、Llama-2、Mistral-7B)上的结果表明,论文的 Evol-Instruct 可以广泛应用于各种预训练模型
  • 深度演化分析 (Analysis of In-depth Evolving)
    • 图 4(a) 和 4(b) 展示了一项消融研究,调查了数据演化轮数的影响
    • 为了研究演化过程的深度,论文使用 ChatGPT 来判断指令的难度级别。使用的提示词请参阅附录 E
    • 图 4(b) 显示了使用每轮演化数据微调的模型在(第 4.3 节中的九个自动基准测试上的)平均分数
    • 从 \(C0\) 到 \(C4\) 的每轮数据大约为 \(52k\)
    • 从该图的趋势可以看出,随着训练指令数据复杂度的逐渐增加,微调模型的性能也同步提高
    • 为了探究 ChatGPT 难度评分的正确性,论文还使用 GPT-4 和人工来测量指令难度,附录 I 表 3 中的详细结果表明 ChatGPT、GPT-4 和人工标注员之间具有良好的一致性
  • 广度演化分析 (Analysis of In-breadth Evolving)
    • 论文旨在检查指令的语义广度
    • 论文使用 t-SNE (2008) 和 k-means (1979) 算法将指令的 BERT 嵌入划分为 20 个簇
    • 附录 F 中的图 6 显示了聚类情况,突出了论文的方法与 ShareGPT 和 Alpaca 相比具有更优越的分散性,表明论文的指令具有更大的主题多样性

Related Work

Closed domain instruction tuning

  • 早期的指令跟随训练工作 (2021; 2023) 关注 LM 的跨任务泛化能力,其中 LM 在广泛的公共 NLP 数据集上进行微调,并在不同的 NLP 任务集上进行评估
    • T5 (2020) 做出了最早的尝试,使用统一的文本到文本(text-to-text)格式共同训练自然语言处理(NLP)任务,如问答、文档摘要和情感分类
    • 诸如 FLAN (2021)、ExT5 (2022)、T0 (2022) 和 KnowDA (2022c) 等工作将 NLP 任务的数量增加到大约一百个,并为每个任务精心设计了几个指令 (2023;)
    • 诸如 ZeroPrompt (2022) 和 FLAN-T5 (2022) 等工作将任务数量提升至数千个
  • 这些研究一致表明,使用多样化的 NLP 任务指令微调 LM 可以增强它们在新任务上的性能
  • 但使用这些封闭形式指令(即指令通常仅针对单个 NLP 任务,且输入数据形式简单)训练的 LLM 在真实用户场景中往往表现不佳

Open domain instruction tuning

  • 论文的工作属于这一研究路线
  • OpenAI 雇佣了许多标注员并编写了许多带有相应正确答案的指令
    • 这些人工创建的指令形式多样,任务类型丰富
    • 基于这个数据集,OpenAI 将 GPT-3 (2020) 训练成 InstructGPT (2022),它可以处理各种真实用户指令,并导致了 ChatGPT 的成功
  • Orca (2023) 不仅学习来自 LLM 的表层响应文本,还捕获复杂的推理过程信号
  • 由于 OpenAI 的这些杰出工作并未开源,Alpaca (2023) 和 Vicuna (2023) 随后基于开源 LLM LLaMA (2023) 积极探索了开放域指令微调
  • Alpaca 使用了一个包含 \(50k\) 条指令的数据集,这些指令是从有限(例如 175 个样本)的手写指令种子集中生成的
  • 论文的工作与 InstructGPT 和 Vicuna 的不同之处在于:
    • 论文使用 AI 生成的数据进行指令微调
    • 与 Alpaca 的 self-instruct (2022a) 生成方法不同, Evol-Instruct 可以控制生成指令的难度和复杂度级别

附录 A:Deepening Prompt(深化 Prompt)

  • 示例 A.1:用于深度演化的深化提示 (Prompt for Deepening of In-Depth Evolving)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    I want you act as a Prompt Rewriter.
    Your objective is to rewrite a given prompt into a more complex version to make those famous AI systems (e.g., ChatGPT and GPT4) a bit harder to handle. But the rewritten prompt must be reasonable and must be understood and responded by humans.
    Your rewriting cannot omit the non-text parts such as the table and code in #Given Prompt#:. Also, please do not omit the input in #Given Prompt#.
    You SHOULD complicate the given prompt using the following method:
    If #Given Prompt# contains inquiries about certain issues, the depth and breadth of the inquiry can be increased.
    You should try your best not to make the #Rewritten Prompt# become verbose, #Rewritten Prompt# can only add 10 to 20 words into #Given Prompt#. ‘#Given Prompt#’, ‘#Rewritten Prompt#’, ‘given prompt’ and ‘rewritten prompt’ are not allowed to appear in #Rewritten Prompt#
    #Given Prompt#:
    {Here is instruction.} #Rewritten Prompt#:

    我希望你扮演一个提示词重写器(Prompt Rewriter)。
    你的目标是将给定的提示词(prompt)改写成更复杂的版本,以使那些著名的人工智能系统(例如 ChatGPT 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。
    你的改写不能省略 #给定提示词#(#Given Prompt#)中的非文本部分,例如表格和代码。此外,请不要省略 #给定提示词# 中的输入部分。
    你应当通过以下方法来使给定提示词复杂化:
    如果 #给定提示词# 包含对某些问题的询问,可以增加询问的深度和广度。
    你应尽力避免使 #改写后的提示词#(#Rewritten Prompt#)变得冗长,#改写后的提示词# 只能在 #给定提示词# 的基础上增加 10 到 20 个词。禁止在 #改写后的提示词# 中出现“#给定提示词#”、“#改写后的提示词#”、“given prompt”或“rewritten prompt”这些短语。
    **#给定提示词#:**
    {这里是指令。}
    **#改写后的提示词#:**

附录 B: Concretizing Prompt(具体化 Prompt)

  • 示例 B.1:用于深度演化的具体化提示 (Prompt for Concretizing of In-Depth Evolving)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    I want you act as a Prompt Rewriter.
    Your objective is to rewrite a given prompt into a more complex version to make those famous AI systems (e.g., ChatGPT and GPT4) a bit harder to handle. But the rewritten prompt must be reasonable and must be understood and responded by humans.
    Your rewriting cannot omit the non-text parts such as the table and code in #Given Prompt#:. Also, please do not omit the input in #Given Prompt#.
    You SHOULD complicate the given prompt using the following method:
    Please replace general concepts with more specific concepts.
    You should try your best not to make the #Rewritten Prompt# become verbose, #Rewritten Prompt# can only add 10 to 20 words into #Given Prompt#. ‘#Given Prompt#’, ‘#Rewritten Prompt#’, ‘given prompt’ and ‘rewritten prompt’ are not allowed to appear in #Rewritten Prompt#
    #Given Prompt#:
    {Here is instruction.} #Rewritten Prompt#:

    我希望你扮演一个提示词重写器(Prompt Rewriter)。
    你的目标是将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 ChatGPT 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。
    你的改写不能省略 #给定提示词# 中的非文本部分,例如表格和代码。此外,请不要省略 #给定提示词# 中的输入部分。
    你应当通过以下方法来使给定提示词复杂化:
    请将一般性概念替换为更具体的概念。
    你应尽力避免使 #改写后的提示词# 变得冗长,#改写后的提示词# 只能在 #给定提示词# 的基础上增加 10 到 20 个词。禁止在 #改写后的提示词# 中出现“#给定提示词#”、“#改写后的提示词#”、“given prompt”或“rewritten prompt”这些短语。
    **#给定提示词#:**
    {这里是指令。}
    **#改写后的提示词#:**

附录 C:Increased Reasoning Steps Prompt

  • 示例 C.1:用于深度演化的增加推理步骤提示 (Prompt for Increased Reasoning Steps of In-Depth Evolving)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    I want you act as a Prompt Rewriter.
    Your objective is to rewrite a given prompt into a more complex version to make those famous AI systems (e.g., ChatGPT and GPT4) a bit harder to handle. But the rewritten prompt must bereasonable and must be understood and responded by humans.
    Your rewriting cannot omit the non-text parts such as the table and code in #Given Prompt#:. Also, please do not omit the input in #Given Prompt#.
    You SHOULD complicate the given prompt using the following method:
    If #Given Prompt# can be solved with just a few simple thinking processes, you can rewrite it to explicitly request multiple-step reasoning.
    You should try your best not to make the #Rewritten Prompt# become verbose, #Rewritten Prompt# can only add 10 to 20 words into #Given Prompt#. ‘#Given Prompt#’, ‘#Rewritten Prompt#’, ‘given prompt’ and ‘rewritten prompt’ are not allowed to appear in #Rewritten Prompt#
    #Given Prompt#:
    {Here is instruction.} #Rewritten Prompt#:

    我希望你扮演一个提示词重写器(Prompt Rewriter)。
    你的目标是将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 ChatGPT 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。
    你的改写不能省略 #给定提示词# 中的非文本部分,例如表格和代码。此外,请不要省略 #给定提示词# 中的输入部分。
    你应当通过以下方法来使给定提示词复杂化:
    如果 #给定提示词# 可以通过几个简单的思考过程解决,你可以将其改写成明确要求多步推理的形式。
    你应尽力避免使 #改写后的提示词# 变得冗长,#改写后的提示词# 只能在 #给定提示词# 的基础上增加 10 到 20 个词。禁止在 #改写后的提示词# 中出现“#给定提示词#”、“#改写后的提示词#”、“given prompt”或“rewritten prompt”这些短语。
    **#给定提示词#:**
    {这里是指令。}
    **#改写后的提示词#:**

附录 D:Complicate Input Prompt

  • 示例 D.1:用于演化的复杂化输入提示 (Prompt for Complicate Input of Evolving)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    我希望你扮演一个提示词重写器。你的目标是使用数据格式将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 chatgpt 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。  
    你必须在 [改写后的提示词] 中添加 [XML 数据] 格式的文本作为输入数据。

    **#给定提示词#:**
    我正在使用这段 php 代码来获取 xml 数据

    **#改写后的提示词#:** 我有这个 xml 文件,我想获取 xml 数据以自动填充 HTML 表格,代码可以运行,但会导致表格内容重复。

    以下是 xml 数据:

    <root>
    <stats>
    <item>
    <day>2017-11-01</day>
    <impressions>2192</impressions>
    <money>1.96790003</money>
    </item>
    <item>
    <day>2017-11-02</day>
    <impressions>2824</impressions>
    <money>3.208500033</money>
    </item>
    <item>
    <day>2017-11-03</day>
    <impressions>3680</impressions>
    <money>3.321799981</money>
    </item>
    </stats>
    <total>
    <impressions>8696</impressions>
    <money>8.498200044</money>
    </total>
    <filter>
    <dateFrom>2017-11-01</dateFrom>
    <dateTo>2017-11-03</dateTo>
    <groupBy>day</groupBy>
    <format>xml</format>
    </filter>
    </root>

    我正在使用这段 php 代码来获取 xml 数据,但这段代码是从整个 xml 数据中获取,导致表格字段重复。

    <?php
    \$dom = new DOMDocument;
    \$dom -> load('http://example.com/', \$dateselected . '&dateTo =', \$dateselected2 . '&format=xml');
    \$day = \$dom->getElementsByTagName('day');
    \\$impressions = \$dom->getElementsByTagName('impressions');
    echo ( "<table>");
    foreach(\$day as \$node1) {
    foreach(\$impressions as \$node2) {
    echo '<tr>';
    echo "<td>", \$node1 -> textContent . "<td>";
    echo "<td>", \$node2 -> textContent . "<td>";
    echo "<td>", \$node2 -> textContent *0.5/1000 . "<td>";
    echo '</tr>';
    }
    }
    echo( "<table>");
    ?>

    有人能提示我如何修复这个问题吗?谢谢

    ####
  • 示例 D.2:用于演化的复杂化输入提示 (Prompt for Complicate Input of Evolving)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    我希望你扮演一个提示词重写器。你的目标是使用数据格式将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 chatgpt 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。  

    你必须在 [改写后的提示词] 中添加 [SQL 数据库] 格式的文本作为输入数据。

    **#给定提示词#**
    实现 SQL 查询结果

    **#改写后的提示词#**(必须包含一个具体的 SQL 数据库作为输入):
    有一个名为 messages 的表格,包含的数据如下所示:

    | Id | Name | Other_Columns |
    |----|------|---------------|
    | 1 | A | A_data_1 |
    | 2 | A | A_data_2 |
    | 3 | A | A_data_3 |
    | 4 | B | B_data_1 |
    | 5 | B | B_data_2 |
    | 6 | C | C_data_1 |

    如果我运行查询 `select * from messages group by name`,我将得到以下结果:

    | 1 | A | A_data_1 |
    | 4 | B | B_data_1 |
    | 6 | C | C_data_1 |

    哪个查询会返回以下结果?

    | 3 | A | A_data_3 |
    | 5 | B | B_data_2 |
    | 6 | C | C_data_1 |

    也就是说,应返回每个组中的最后一条记录。目前,我使用的查询是:

    SELECT *
    FROM (SELECT *
    FROM messages
    ORDER BY id DESC) AS x
    GROUP BY name

    但这看起来非常低效。是否有其他方法可以实现相同的结果?

    ####
  • 示例 D.3:用于演化的复杂化输入提示 (Prompt for Complicate Input of Evolving)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    我希望你扮演一个提示词重写器。你的目标是使用数据格式将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 chatgpt 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。  

    你必须在 [改写后的提示词] 中添加 [python 代码] 格式的文本作为输入数据。

    **#给定提示词#**
    转换 python 代码

    **#改写后的提示词#**(必须包含一个具体的 python 代码作为输入):
    我有以下 Python 代码:

    ```python
    cursor.execute("INSERT INTO table VALUES var1, var2, var3,")

    其中 var1 是整数,var2 和 var3 是字符串。
    如何编写变量名而不让 Python 将它们作为查询文本的一部分?

    ####

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    * **示例 D.4:用于演化的复杂化输入提示 (Prompt for Complicate Input of Evolving)**  
    ```md
    我希望你扮演一个提示词重写器。你的目标是使用数据格式将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 chatgpt 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。
    你必须在 [改写后的提示词] 中添加 [HTML 页面] 格式的文本作为输入数据。

    **#给定提示词#**
    滚动整个 HTML 页面

    **#改写后的提示词#**(必须包含一个具体的 HTML 页面作为输入):
    我希望能够滚动整个页面,但不显示滚动条。
    在 Google Chrome 中,可以使用:


    ::-webkit-scrollbar {
    display: none;
    }

    但 Mozilla Firefox 和 Internet Explorer 似乎不支持这种方式。
    我也在 CSS 中尝试了:

    overflow: hidden;

    这样可以隐藏滚动条,但我无法再滚动了。有没有办法可以在隐藏滚动条的同时仍然能够滚动整个页面?

    请仅使用 CSS 或 HTML。

    ###
  • 示例 D.5:用于演化的复杂化输入提示 (Prompt for Complicate Input of Evolving)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    我希望你扮演一个提示词重写器。你的目标是使用数据格式将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 chatgpt 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。  

    你必须在 [改写后的提示词] 中添加 [Shell 命令] 格式的文本作为输入数据。

    **#给定提示词#**
    Shell scp 文件

    **#改写后的提示词#**(必须包含一个具体的 Shell 命令作为输入):
    我正在尝试从远程服务器 scp 一个文件到我的本地机器。只有端口 80 是可访问的。
    我尝试了:

    ```shell
    scp -p 80 username@www.myserver.com/root/file.txt .

    但出现了这个错误:cp: 80: No such file or directory
    如何在 scp 命令中指定端口号?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    * **示例 D.6:用于演化的复杂化输入提示 (Prompt for Complicate Input of Evolving)**  
    ```md
    我希望你扮演一个提示词重写器。你的目标是使用数据格式将给定的提示词改写成更复杂的版本,以使那些著名的人工智能系统(例如 chatgpt 和 GPT4)更难处理。但改写后的提示词必须是合理的,且必须能被人类理解并回应。

    你必须在 [改写后的提示词] 中添加 [JSON 数据] 格式的数据作为输入数据,添加 [JSON 数据] 代码作为输入代码。

    改写后的提示词必须是一个问题式指令。

    **#给定提示词#:**
    给定一个客户购买历史的 JSON 数据集,我们如何计算客户在同一商店进行重复购买的概率?我们能否利用条件概率公式:\(P(A|B)=P(A\cap B)/P(B)\),其中 A 表示客户进行重复购买的事件,B 表示客户再次在同一商店购买的事件?此外,我们如何应用这个公式来识别最有可能进行重复购买的客户群体?你能提供一个使用给定 JSON 数据集实现这个公式的示例吗?

    改写后的提示词必须是一个问题式指令。

    **#改写后的提示词#**(必须包含一个具体的 JSON 数据作为输入):

附录 E:Difficulty Judge Prompt

  • 示例 E.1:用于判断指令难度的提示 (Prompt for Juding the Difficulty of Instructions)
    1
    2
    3
    4
    5
    6
    我们希望您评估并评定以下问题的难度和复杂性。您应给出一个从 1 到 10 的整体分数,分数越高表示难度和复杂性越高。您必须仅给出分数,不提供任何其他理由。  

    **## 问题:**
    { 这里是指令。 }

    **## 分数:**

附录 F:Equal Prompt

  • 示例 F.1:用于判断两个指令是否等价的提示 (Prompt for Determining whether Two Instructions are Equal)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    以下是两个给 ChatGPT AI 的指令,您认为它们是否彼此等价,需满足以下要求:  

    1. 它们具有相同的约束和要求。
    2. 它们具有相同的询问深度和广度。

    第一个提示:{这里是第一个指令。}

    第二个提示:{这里是第二个指令。}

    您的判断(仅回答:等价 或 不等价。无需解释原因。):

附录 G:Math Judgement Prompt

  • 示例 G.1:用于判断指令是否与数学相关的提示 (Prompt for judging whether an instruction is math related)
    1
    2
    3
    请判断以下问题是否是一个数学问题,并仅返回 True 或 False,不提供任何解释。  

    问题:{指令}

附录 H:WizardEval Analysis

  • 论文收集了 Evol-Instruct 测试集,其中包含来自各种来源的真实世界人类指令,例如在线开源项目、平台和论坛
  • 论文分析了数据并识别出 29 种不同的技能,这些技能代表了人类的主要需求,例如代码生成与调试、数学、推理、复杂格式、写作、广泛学科等等
  • 图 6 展示了论文测试集中实例和技能的分布情况
  • 论文的测试集包含 218 个实例,每个实例都是针对特定技能的指令
  • 论文将论文的测试集与 Vicuna 的测试集进行了比较,后者是用于评估指令遵循模型的基准数据集
  • 论文发现 Vicuna 的测试集只有 80 个实例和 9 种技能,比论文的测试集小得多且多样性低得多
  • 图 4a 显示了测试数据的难度和复杂性如何在不同实例间变化
  • 论文的测试数据具有更均匀的分布,这意味着它包含不同难度和复杂性级别的指令
  • 另一方面,Vicuna 和 Alpaca 的分布则存在偏差,这意味着它们主要包含低难度和低复杂性的指令
  • 这表明这两个语料库无法处理对更复杂和要求更高场景的评估

附录 I:Different difficulty Annotators

  • 论文仅使用 ChatGPT 来事后分析生成指令的“难度”分布,但论文并未使用此分析结果来指导数据生成或模型训练
  • 为了探索 ChatGPT 执行难度分析的能力,论文采样了 600 条指令,并使用更强大的 GPT-4 模型和 5 位受过良好教育的人类标注者一起进行难度评估
  • 评估结果见表 3。结果表明,ChatGPT、GPT-4 和人工标注在难度变化趋势上表现出高度的一致性
  • 为了研究 ChatGPT 难度评分的正确性,论文增加了一个新的实验来测量 ChatGPT 与人类之间在难度判断上的一致性:
    • 论文每次以相等概率从六个数据集(Alpaca、ShareGPT、C1 到 C4)中随机选择两条指令,组成一对
    • 总共论文选择了 300 个指令对
    • 然后,论文请 ChatGPT 和 5 位受过良好教育的人类标注者判断在一个指令对中哪一条更难,人类之间的 Kappa 分数为 0.68,ChatGPT 与人类(多数投票)之间的 Kappa 分数为 0.66,这表明 ChatGPT 和人类标注者之间具有良好的一致性

附录 J: Cluster Scatter Plot(聚类散点图)

  • 广度演化旨在增强主题覆盖度、技能覆盖度和整体数据集的多样性。为了(定性分析)检查不同数据集的广度(多样性),论文首先使用 BERT
  • 对每条指令进行编码并获得其 768 维的嵌入向量,然后使用名为 t-SNE 的降维算法将嵌入维度降至 2 维,最后论文应用聚类算法 k-means 将每个数据集的指令划分为 20 个簇,以便进行直观的可视化
  • 如图 7 所示,论文数据集的数据点比 ShareGPT 和 Alpaca(Self-Instruct)的数据点更加分散,这表明论文的指令具有更好的主题多样性

附录 K: Human Evaluation Aspects

  • 标注者从以下五个维度判断哪个回答更好:
    • (1) 相关性 (Relevance): 评估模型正确理解上下文和问题语义含义的能力
    • (2) 知识性 (Knowledgeable): 模型是否能够准确使用各种详细的知识来解决问题
    • (3) 推理能力 (Reasoning): 评估模型执行正确推理过程或设计有效推理概念以解决问题的能力
    • (4) 计算能力 (Calculation): 评估模型是否能在数学、生物、化学和物理领域对所提供的公式进行准确的数学计算
    • (5) 准确性 (Accuracy): 评估模型对于给定指令是否能在相应领域正确执行

附录 L: Performance details of different checkpoints

  • 在论文中,论文使用 3 个训练周期 (epoch) 训练论文的模型,并且在上文的“第 4 节 实验”中仅报告了最终检查点的性能,以与之前的工作保持一致
  • 如下表 4 所示,论文报告了模型在不同周期(2.5, 2.75, 3)的检查点性能
    • 对于 13B 模型,我们可以看到除了 GSM8k 之外,在每个基准测试上表现最好的始终是 WizardLM-13b (ShareGPT Seed)
    • 对于 65b/70b 模型,论文也看到 WizardLM-70b 在所有基准测试中都是最好的
    • 因此,作者认为这主要是由模型训练过程中在某些基准测试上的波动引起的
1…444546…61
Joe Zhou

Joe Zhou

Stay Hungry. Stay Foolish.

608 posts
49 tags
GitHub E-Mail
© 2026 Joe Zhou
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4