1.llm_aigc

下载本文pdf:https://github.com/daiwk/collections/blob/master/pdfs/llm_aigc.pdf

各种学习相关代码

https://github.com/daiwk/llms_new

从word2v到Transformer

LSTM

超生动图解LSTM和GRU,一文读懂循环神经网络!

fasttext&word2vec

注:w2v训练时的内积不是2个emb-in的内积,而是emb-in和emb-out的内积

fasttext源码解析

  • Dictionary::readWord:空格分割,一次读出来一个word

  • Dictionary::add:每个word求个hash,加进词典时,id就是从0开始的序号,同时记录一下词频

  • Dictionary::threshold:按词频排序,扔掉低频词

  • Dictionary::initNgrams:每个词,加上前缀BOW(<)和后缀(>),然后先扔进这个词的subwords里,然后再调用 Dictionary::computeSubwords把这个词的ngrams也扔进它的subwords里

整个词表,是word数+bucket这么大,其中bucket表示可容纳的subwords和wordNgrams的数量,默认200w

为什么Word2Vec训练中, 需要对负采样权重开3/4次幂?

Distributed Representations of Words and Phrases and their Compositionality里提到

通过对权重开3/4次幂,可以提升低频词被抽到的概率。在保证高频词容易被抽到的大方向下,通过权重3/4次幂的方式,适当提升低频词、罕见词被抽到的概率。如果不这么做,低频词,罕见词很难被抽到,以至于不被更新到对应的Embedding。

BPE/WordPiece分词

【Subword】深入理解NLP Subword算法:BPE、WordPiece、ULM

Transformer原理

从三大顶会论文看百变Self-Attention

包学包会,这些动图和代码让你一次读懂「自注意力」

http://jalammar.github.io/illustrated-transformer/

从熵不变性看Attention的Scale操作

Transformers Assemble(PART I) 讲了3篇

Transformers Assemble(PART II) 又讲了三篇

为什么层次化softmax没人用了

Transformer 结构中最后一层 softmax 为什么不再使用 层次化softmax了呢?

主要还是计算资源的问题。

Mikolov发明word2vec的几个版本大概在13-14年前后。那个时候GPU非常少见,印象里面CMU的NLP组没有GPU,Stanford NLP lab只有6块K40。

大规模直接算softmax是在google的14年那篇seq2seq做MT的文章。为了快,把一个softmax并行在4块GPU上,每个GPU负责四分之一。那个年代,大多数NLP组全组都不会有4块GPU。

hierarchical softmax是softmax的近似,suboptimal的。当如今计算资源足够大的时候,当然包括时间和显存 (BERT 和 Elmo 都没有用hierarchical),hierarchical softmax就逐渐退出了历史舞台。

Transformer会不会规划未来

Transformer本可以深谋远虑,但就是不做

Do Language Models Plan for Future Tokens?

在训练期间的梯度既会为当前token位置的损失优化权重,也会为该序列后面的token进行优化,那么这二者会以怎样的比例分配资源?

  • 预缓存假设(pre-caching hypothesis):在时间步tt计算与当前时间步的推理任务无关可能对未来时间步t+τt + \tau有用的特征

  • 面包屑假设(breadcrumbs hypothesis):与时间步tt最相关的特征已经等同于将在时间步t+τt + \tau最有用的特征。

设计了一种合成场景,其中只能通过显式的预缓存完成任务,即模型必须为下一token预先计算信息,**否则就无法在一次单向通过中准确计算出正确答案。**发现明显的证据说明transformer可以学习预缓存,即当必须预计算信息来最小化损失时,它们就会这样做。

但在真实语言数据上,语言模型并不会显著地准备用于未来的信息。相反,它们是计算对预测下一个token有用的特征——事实证明这对未来的步骤也很有用

Transformer的FLOPS和访存带宽

https://zhuanlan.zhihu.com/p/624740065

AA的shape是m×km\times kBB的shape是k×nk\times n,那么矩阵乘法ABAB需要m×k×nm\times k\times n次的乘法,也需要同样多次的加法,所以FLOPS是2×m×k×n2\times m\times k\times n

假设batchsize是bb,序列长度ss,原来的emb是dd,即输入的是[b,s,d][b,s,d],一般d=dk=dv=dqd=d_k=d_v=d_qWQW_QWKW_KWVW_V都是dv×dvd_v\times d_v,对应的Q、K、V矩阵都是s×dvs\times d_v,有head_numhead\_num个头,每个头的维度per_head_d=dhead_numper\_head\_d=\frac{d}{head\_num}

attention的FLOPS

attention的公式:

Q=xWQ,K=xWK,V=xWVxout =softmax(QKTh)VWo+x\begin{aligned} &Q=x W_Q, K=x W_K, V=x W_V\\ &x_{\text {out }}=\operatorname{softmax}\left(\frac{Q K^T}{\sqrt{h}}\right) \cdot V \cdot W_o+x \end{aligned}
  • 计算3个Q、K、V:要算三次s×ds\times dd×dvd\times d_v的矩阵乘法,所以是:3×2×b×s×d×dv3\times 2\times b\times s\times d\times d_v

    • 输入:[b,s,d][b, s, d]和3个[b,d,dv][b, d, d_v]

    • 输出:[b,s,dv][b, s, d_v],再把最后一维dvd_v拆成head_numhead\_num份,再把中间两维互换一下,得到[b,head_num,s,per_head_d][b, head\_num, s, per\_head\_d]

  • 计算Q和K的相似度:要算一次s×dvs\times d_vdv×sd_v\times s的矩阵乘法,2×b×s2×dk2\times b\times s^2\times d_k

    • 输入:[b,head_num,s,per_head_d][b, head\_num, s, per\_head\_d][b,head_num,per_head_d,s][b, head\_num, per\_head\_d, s]

    • 输出:[b,head_num,s,s][b, head\_num, s, s]

  • 把相似度用到V上:要算一次s×ss\times ss×dvs\times d_v的矩阵乘法,,2×b×s2×dv2\times b\times s^2 \times d_v

    • 输入:[b,head_num,s,s][b, head\_num, s, s][b,head_num,s,per_head_d][b, head\_num, s, per\_head\_d]

    • 输出:[b,head_num,s,per_head_d][b, head\_num, s, per\_head\_d]

  • 最后过一个线性映射:要算一次s×dvs\times d_v的和dv×dvd_v\times d_v的矩阵乘法,2×b×s×dv×dv2\times b\times s\times d_v\times d_v

    • 输入:[b,s,dv][b, s, d_v][dv,dv][d_v, d_v]

    • 输出:[b,s,dv][b, s, d_v]

因为dk=dv=dq=dd_k=d_v=d_q=d,单纯计算attention总共就是8bsd2+4bs2d8bsd^2 + 4bs^2d

FFN的FLOPS

FFN的公式:

x=fgelu (xout W1)W2+xout x=f_{\text {gelu }}\left(x_{\text {out }} W_1\right) W_2+x_{\text {out }}

在原始Transformer中,W1W_1的shape是[d,4d][d,4d]W2W_2的shape是[4d,d][4d,d]

  • 第一个线性层:2×b×s× d×4d=8×b×s× d22\times b\times s\times\ d\times 4d=8\times b\times s\times\ d^2

    • 输入:[b,s,d][b, s, d][d,4d][d,4d]

    • 输出:[b,s,4d][b, s, 4d]

  • 第二个线性层:2×b×s× 4d×d=8×b×s× d22\times b\times s\times\ 4d\times d=8\times b\times s\times\ d^2

    • 输入:[b,s,4d][b, s, 4d][4d,d][4d,d]

    • 输出:[b,s,d][b, s, d]

所以一层Transformer,即attention+FFN的计算量为(8bsd2+4bs2d)+16bsd2=24bsd2+4bs2d(8bsd^2 + 4bs^2d)+16bsd^2=24bsd^2+4bs^2d

有两点需要注意的:

  • 对NLP任务来讲,一般dd是个比较固定的值,如512,而ss变大,效果会更好,所以一般是s>ds>d,所以复杂度取决于ss的大小。

  • 但有些模型的初始设置不是这样的,例如GPT3的175B模型里,s=2048,d=12288s=2048,d=12288,当然,算力够的话也可以把ss变大

自己感觉:既然是24bsd2+4bs2d24bsd^2+4bs^2d,其实就是6sd26sd^2s2ds^2d的大小,即6d6dss的大小,如果6d>s6d>s,则d2d^2起主导,反之s2s^2起主导

DIN的FLOPS

特殊地,对于推荐中的DIN那种,看当前item和历史s个item的相关性,即q的序列长度只有1,不考虑多头,而这其实也是decoder预测下一个词时过一层Transformer的复杂度

已经有3个序列长度为s1s-1的QKV的cache,要算第ss个词和这s1s-1个词的attention

  • 计算第ss个词的3个Q、K、V:要算三次$1\times d$和d×dvd\times d_v的矩阵乘法,所以是:3×2×b×1×d×dv3\times 2\times b\times 1\times d\times d_v

    • 输入:[b,1,d][b, 1, d]和3个[b,d,dv][b, d, d_v]

    • 输出:[b,1,dv][b, 1, d_v]

  • 计算Q和K的相似度:要算一次1×dv1\times d_vdv×sd_v\times s的矩阵乘法,2×b×1×dk×s2\times b\times 1\times d_k\times s【这里的K是历史s1s-1长度的序列拼上当前词,当然对DIN来讲要去掉当前词,这里先忽略这个】

    • 输入:[b,1,dv][b, 1, d_v][b,dv,s][b, d_v, s]

    • 输出:[b,1,s][b, 1, s]

  • 把相似度用到V上:要算一次1×s1\times ss×dvs\times d_v的矩阵乘法,,2×b×1×dv×s2\times b\times 1 \times d_v \times s【同样地,这里的V是历史s1s-1长度的序列拼上当前词,当然对DIN来讲要去掉当前词,这里先忽略这个】

    • 输入:[b,1,s][b, 1, s][b,s,dv][b, s, d_v]

    • 输出:[b,1,dv][b, 1, d_v]

  • 最后过一个线性映射:要算一次1×dv1\times d_v的和dv×dvd_v\times d_v的矩阵乘法,2×b×1×dv×dv2\times b\times 1\times d_v\times d_v

    • 输入:[b,1,dv][b, 1, d_v][dv,dv][d_v, d_v]

    • 输出:[b,1,dv][b, 1, d_v]

  • 第一个线性层:2×b×1× d×4d=8×b×1× d22\times b\times 1\times\ d\times 4d=8\times b\times 1\times\ d^2

    • 输入:[b,1,d][b, 1, d][d,4d][d,4d]

    • 输出:[b,1,4d][b, 1, 4d]

  • 第二个线性层:2×b×1× 4d×d=8×b×1× d22\times b\times 1\times\ 4d\times d=8\times b\times 1\times\ d^2

    • 输入:[b,1,4d][b, 1, 4d][4d,d][4d,d]

    • 输出:[b,1,d][b, 1, d]

总共是6bd2+2bds+2bds+2bd2+8bd2+8bd2=24bd2+4bds6bd^2+2bds+2bds+2bd^2+8bd^2+8bd^2=24bd^2+4bds

Transformer的访存

GPU架构的介绍参考https://developer.nvidia.com/blog/nvidia-ampere-architecture-in-depth/https://www.zhihu.com/question/319355296/answer/2193938981,GPU对比CPU如下:

  • 任务模式

    • CPU由专为顺序串行处理而优化的几个核心组成

    • GPU则拥有一个由数以千计的更小、更高效的核心(专为同时处理多重任务而设计)组成的大规模并行计算架构。同时CPU相当的一部分时间在执行外设的中断、进程的切换等任务,而GPU有更多的时间并行计算。

  • 功能定位

    • CPU不但要承担计算任务还有承担逻辑控制等任务。

    • GPU在渲染画面时需要同时渲染数以百万记的顶点或三角形,故GPU的设计是可以充分支持并行计算。

  • 系统集成

    • GPU作为一类外插设备,在尺寸、功率、散热、兼容性等方面的限制远远小于CPU,这样可以让GPU有较大的显存和带宽。

以A100为例,整体架构如下

  1. PCIE层:通过PCIE接口以外设的方式集成到服务器上。

  2. 中间一坨绿色的部分是GPU的计算核心SM(Streaming Multiprocessor),在A100中,一个SM有64个用于计算的Core,共108个SM(图里是GA100,有128个SM),故共6192个Core。

  3. 中间蓝色部分是L2缓存

  4. NVLink:多个GPU间进行通信的组件,会优化GPU间的通信,提升传输效率。

  5. 两侧的HBM2是显存,目前的A100的显存有两种40G and 80G

A100的SM如图所示,

GPU的显存分成两部分:

  • Global Memory:整体架构图中的两侧HBM2部分,例如A100 80G就有80G的global memory,2TB/s带宽,访问速度比较慢

  • Shared Memory:SM图中浅蓝色的L1 Data Cache,例如A100中每个SM中有192KB,访问速度比较快

从图中可见,A100的FP16312T的FLOPS

以矩阵乘法为例,[M,K]×[K,N]>[M,N][M, K] \times [K, N] -> [M,N]

  • 计算时间:2MKN/FLOPS2MKN/FLOPS

  • 访存时间为:(MN+MK+KN)/memory_bandwidth(MN+MK+KN)/memory\_bandwidth,因为首先要读取MKMKNKNK这两个矩阵,然后结果还要写入MNMN这个矩阵里。假设是fp16,占2bytes,那就还要乘以2

假设b=1,s=4096,d=dk=2048b=1,s=4096,d=d_k=2048,以计算Q和K的相似度为例,对比一下训练和预测时的计算耗时访存耗时

  • 训练时M=4096,N=2048,K=4096M=4096,N=2048,K=4096==>计算是瓶颈

    • FLOPS:2×b×s2×dk=2×1×40962×2048=687194767362\times b\times s^2\times d_k=2\times 1\times 4096^2\times 2048=68719476736

    • 计算耗时:FLOPS/max_FLOPS=68719476736/(312×1012)=0.00022s=220×106s=220usFLOPS/max\_FLOPS=68719476736/(312\times 10^{12})=0.00022s=220\times 10^{-6}s=220us

    • 访存耗时:(MN+MK+KN)/memory_bandwidth=2×(4096×2048+4096×4096+4096×2048)/(2×1012)=3.35544×105s=33.544×106=33.5544us(MN+MK+KN)/memory\_bandwidth=2\times (4096\times 2048+4096\times 4096+4096\times 2048)/(2\times 10^{12})=3.35544\times 10^{-5}s=33.544\times 10^{-6}=33.5544us

  • 预测时M=1,N=2048,K=4096M=1,N=2048,K=4096==>访存是瓶颈

    • FLOPS:2×b×1×dk×s=2×1×2048×4096=167772162\times b\times 1\times d_k\times s=2\times 1\times 2048\times 4096=16777216

    • 计算耗时:FLOPS/max_FLOPS=16777216/(312×1012)=5.38×108s=0.0538×106s=0.0538usFLOPS/max\_FLOPS=16777216/(312\times 10^{12})=5.38\times 10^{-8}s=0.0538\times 10^{-6}s=0.0538us

    • 访存耗时:(MN+MK+KN)/memory_bandwidth=2×(1×2048+1×4096+4096×2048)/(2×1012)=8.3948×106s=8.3948us(MN+MK+KN)/memory\_bandwidth=2\times (1\times 2048+1\times 4096+4096\times 2048)/(2\times 10^{12})=8.3948\times 10^{-6}s=8.3948us

一些常见的名词:

  • H2D:host to device,从cpu拷贝到gpu

  • D2H:device to host,从gpu拷贝到cpu

Transformer加速

lightseq

LightSeq: A High Performance Inference Library for Transformers

LightSeq2: Accelerated Training for Transformer-based Models on GPUs

https://github.com/bytedance/lightseq

PLM:仅编码器/仅解码器/编码器+解码器

仅编码器的BERT

BERT小学生级上手教程,从原理到上手全有图示,还能直接在线运行

BERT源码分析(PART I)

BERT源码分析(PART II)

Dive into BERT:语言模型与知识

关于BERT,面试官们都怎么问

主要讲了下面3篇:

Language Models as Knowledge Bases?

Linguistic Knowledge and Transferability of Contextual Representations

What does BERT learn about the structure of language?

A Primer in BERTology: What we know about how BERT works

摘要:目前,基于 Transformer 的模型已经广泛应用于自然语言处理中,但我们依然对这些模型的内部工作机制知之甚少。在本文中,来自麻省大学洛威尔分校的研究者对流行的 BERT 模型进行综述,并综合分析了 40 多项分析研究。他们还概览了对模型和训练机制提出的改进,然后描画了未来的研究方向。

Pre-trained Models for Natural Language Processing: A Survey

BERT系列文章汇总导读

ALBERT、XLNet,NLP技术发展太快,如何才能跟得上节奏?

绝对干货!NLP预训练模型:从transformer到albert

ALBERT一作蓝振忠:预训练模型应用已成熟,ChineseGLUE要对标GLUE基准

有哪些令你印象深刻的魔改Transformer?

BERT模型超酷炫,上手又太难?请查收这份BERT快速入门指南!

multi-head att 实现

输入原始的query(即from_tensor)之后, 把[batch, from_seq, emb]变成[?, emb],其中?=batch*from_seq

from_tensor_2d = reshape_to_matrix(from_tensor)

def reshape_to_matrix(input_tensor):
    """Reshapes a >= rank 2 tensor to a rank 2 tensor (i.e., a matrix)."""
    ndims = input_tensor.shape.ndims
    if ndims < 2:
        raise ValueError("Input tensor must have at least rank 2. Shape = %s" %
            (input_tensor.shape))
    if ndims == 2:
        return input_tensor
    width = input_tensor.shape[-1]
output_tensor = tf.reshape(input_tensor, [-1, width])
    return output_tensor

然后再接一个fc,把[?, emb]变成[?, head_num * per_head],一般head_num * per_head=emb

query_layer = tf.layers.dense(
        from_tensor_2d,
        num_attention_heads * size_per_head,
        activation=query_act,
        name="query",
        kernel_initializer=create_initializer(initializer_range))

因为?=batch*from_seq,所以可以直接做如下变换

query_layer = transpose_for_scores(query_layer, batch_size,
        num_attention_heads, from_seq_length,
        size_per_head)

实际就是把?拆开成batch, from_seq,整个变成[batch, from_seq, head_num, per_head],然后做了个 transpose,把1和2互换了下,得到[batch, head_num, from_seq, per_head]

def transpose_for_scores(input_tensor, batch_size, num_attention_heads,
        seq_length, width):
    output_tensor = tf.reshape(
            input_tensor, [batch_size, seq_length, num_attention_heads, width])

    output_tensor = tf.transpose(output_tensor, [0, 2, 1, 3])
    return output_tensor

然后key也做完全一样的操作(不过处理的是to_tensor,如果是self-attention,那to_tensor=from_tensor), 得到[batch, head_num, to_seq, per_head]

to_tensor_2d = reshape_to_matrix(to_tensor)
key_layer = tf.layers.dense(
        to_tensor_2d,
        num_attention_heads * size_per_head,
        activation=key_act,
        name="key",
        kernel_initializer=create_initializer(initializer_range))

key_layer = transpose_for_scores(key_layer, batch_size, num_attention_heads,
        to_seq_length, size_per_head)

然后就算QKTQK^T了,注意这里对key取了转置,也就是[batch, head_num, from_seq, per_head]乘以[batch, head_num, per_head, to_seq],得到的结果是[batch, head_num, from_seq, to_seq]

attention_scores = tf.matmul(query_layer, key_layer, transpose_b=True)
attention_scores = tf.multiply(attention_scores,
    1.0 / math.sqrt(float(size_per_head)))

if attention_mask is not None:
    # `attention_mask` = [B, 1, F, T]
    attention_mask = tf.expand_dims(attention_mask, axis=[1])

    # Since attention_mask is 1.0 for positions we want to attend and 0.0 for
    # masked positions, this operation will create a tensor which is 0.0 for
    # positions we want to attend and -10000.0 for masked positions.
    adder = (1.0 - tf.cast(attention_mask, tf.float32)) * -10000.0

    # Since we are adding it to the raw scores before the softmax, this is
    # effectively the same as removing these entirely.
    attention_scores += adder
attention_probs = tf.nn.softmax(attention_scores)
attention_probs = dropout(attention_probs, attention_probs_dropout_prob)

然后看下value的操作:

value_layer = tf.layers.dense(
        to_tensor_2d,
        num_attention_heads * size_per_head,
        activation=value_act,
        name="value",
        kernel_initializer=create_initializer(initializer_range))

# `value_layer` = [batch, to_seq, head_num, per_head]
value_layer = tf.reshape(
            value_layer,
            [batch_size, to_seq_length, num_attention_heads, size_per_head])

# `value_layer` = [batch, head_num, to_seq, per_head]
value_layer = tf.transpose(value_layer, [0, 2, 1, 3])

# `context_layer` = [batch, head_num, from_seq, per_head]
context_layer = tf.matmul(attention_probs, value_layer)

# `context_layer` = [batch, from_seq, head_num, per_head]
context_layer = tf.transpose(context_layer, [0, 2, 1, 3])

再确认一点,softmax(QKT)softmax(QK^T)[batch, head_num, from_seq, to_seq],而VV[batch, head_num, to_seq, per_head],所以context_layer是[batch, head_num, from_seq, per_head]

最后,再搞一下,变回[batch, from_seq, head_num * per_head]

if do_return_2d_tensor:
# `context_layer` = [B*F, N*H]
    context_layer = tf.reshape(
        context_layer,
        [batch_size * from_seq_length, num_attention_heads * size_per_head])
else:
# `context_layer` = [B, F, N*H]
    context_layer = tf.reshape(
        context_layer,
        [batch_size, from_seq_length, num_attention_heads * size_per_head])

如上过程是Concat(head1,...,headh)Concat(head_1, ..., head_h),其中headi=Attention(QWiQ,KWiK,VWiV)head_i = Attention(QW_i^Q, KW_i^K, VW_i^V)。包装在了函数attention_layer之中,我们注意到原文还有一个大小为hdv×dmodelhd_v \times d_{model}WOW^O,也就是大小为dmodel×dmodeld_{model}\times d_{model},再看看源码。。也就是说,正常的bert里,attention_heads就只有一个元素,然后接了个hidden_size的fc,而前面的代码里也提到了hidden_size正好就是dmodeld_{model},所以这就是WOW^O

attention_heads = []
with tf.variable_scope("self"):
    attention_head = attention_layer(xxxxx)
    attention_heads.append(attention_head)
    attention_output = None
    if len(attention_heads) == 1:
        attention_output = attention_heads[0]
    else:
        # In the case where we have other sequences, we just concatenate
        # them to the self-attention head before the projection.
        attention_output = tf.concat(attention_heads, axis=-1)
    # Run a linear projection of `hidden_size` then add a residual
    # with `layer_input`.
    with tf.variable_scope("output"):
        attention_output = tf.layers.dense(
            attention_output,
            hidden_size,
            kernel_initializer=create_initializer(initializer_range))
        attention_output = dropout(attention_output, hidden_dropout_prob)
        attention_output = layer_norm(attention_output + layer_input)

关于 mask,可以看看这个https://juejin.im/post/5b9f1af0e51d450e425eb32d

摘抄一下:

什么是padding mask呢?回想一下,我们的每个批次输入序列长度是不一样的!也就是说,我们要对输入序列进行对齐!具体来说,就是给在较短的序列后面填充0。因为这些填充的位置,其实是没什么意义的,所以我们的attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。 具体的做法是,把这些位置的值加上一个非常大的负数(可以是负无穷),这样的话,经过softmax,这些位置的概率就会接近0!

而sequence mask是为了使得decoder不能看见未来的信息。也就是对于一个序列,在time_step为t的时刻,我们的解码输出应该只能依赖于t时刻之前的输出,而不能依赖t之后的输出。因此我们需要想一个办法,把t之后的信息给隐藏起来。 那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为1,下三角的值权威0,对角线也是0。把这个矩阵作用在每一个序列上,就可以达到我们的目的啦。

masked-language-model的实现

https://github.com/google-research/bert/blob/eedf5716ce1268e56f0a50264a88cafad334ac61/run_pretraining.py#L240

如下,其中hidden_size就是是dmodeld_{model}

def get_masked_lm_output(bert_config, input_tensor, output_weights, positions,
                         label_ids, label_weights):
  """Get loss and log probs for the masked LM."""
  input_tensor = gather_indexes(input_tensor, positions)

  with tf.variable_scope("cls/predictions"):
    # We apply one more non-linear transformation before the output layer.
    # This matrix is not used after pre-training.
    with tf.variable_scope("transform"):
      input_tensor = tf.layers.dense(
          input_tensor,
          units=bert_config.hidden_size,
          activation=modeling.get_activation(bert_config.hidden_act),
          kernel_initializer=modeling.create_initializer(
              bert_config.initializer_range))
      input_tensor = modeling.layer_norm(input_tensor)

    # The output weights are the same as the input embeddings, but there is
    # an output-only bias for each token.
    output_bias = tf.get_variable(
        "output_bias",
        shape=[bert_config.vocab_size],
        initializer=tf.zeros_initializer())
    logits = tf.matmul(input_tensor, output_weights, transpose_b=True)
    logits = tf.nn.bias_add(logits, output_bias)
    log_probs = tf.nn.log_softmax(logits, axis=-1)

    label_ids = tf.reshape(label_ids, [-1])
    label_weights = tf.reshape(label_weights, [-1])

    one_hot_labels = tf.one_hot(
        label_ids, depth=bert_config.vocab_size, dtype=tf.float32)

    # The `positions` tensor might be zero-padded (if the sequence is too
    # short to have the maximum number of predictions). The `label_weights`
    # tensor has a value of 1.0 for every real prediction and 0.0 for the
    # padding predictions.
    per_example_loss = -tf.reduce_sum(log_probs * one_hot_labels, axis=[-1])
    numerator = tf.reduce_sum(label_weights * per_example_loss)
    denominator = tf.reduce_sum(label_weights) + 1e-5
    loss = numerator / denominator

  return (loss, per_example_loss, log_probs)

其中的gather如下:

def gather_indexes(sequence_tensor, positions):
  """Gathers the vectors at the specific positions over a minibatch."""
  sequence_shape = modeling.get_shape_list(sequence_tensor, expected_rank=3)
  batch_size = sequence_shape[0]
  seq_length = sequence_shape[1]
  width = sequence_shape[2]

  flat_offsets = tf.reshape(
      tf.range(0, batch_size, dtype=tf.int32) * seq_length, [-1, 1])
  flat_positions = tf.reshape(positions + flat_offsets, [-1])
  flat_sequence_tensor = tf.reshape(sequence_tensor,
                                    [batch_size * seq_length, width])
  output_tensor = tf.gather(flat_sequence_tensor, flat_positions)
  return output_tensor

注意调用时传的是如下参数

    (masked_lm_loss,
     masked_lm_example_loss, masked_lm_log_probs) = get_masked_lm_output(
         bert_config, model.get_sequence_output(), model.get_embedding_table(),
         masked_lm_positions, masked_lm_ids, masked_lm_weights)

BERT的可解释性

ACL 2019 | 理解 BERT 每一层都学到了什么

What does BERT learn about the structure of language?

探索BERT深层次的表征学习是一个非常有必要的事情,一是这可以帮助我们更加清晰地认识BERT的局限性,从而改进BERT或者搞清楚它的应用范围;二是这有助于探索BERT的可解释性

更复杂的BERT

站在BERT肩膀上的NLP新秀们(PART III)

BERT时代与后时代的NLP

美团BERT的探索和实践

Bert时代的创新(应用篇):Bert在NLP各领域的应用进展

中文BERT

WWM

哈工大讯飞联合实验室发布基于全词覆盖的中文BERT预训练模型

https://github.com/ymcui/Chinese-BERT-wwm

论文:Pre-Training with Whole Word Masking for Chinese BERT

ERNIE

参考中文任务全面超越BERT:百度正式发布NLP预训练模型ERNIE

ERNIE: Enhanced Representation through Knowledge Integration

使用entity-level masking和phrase-level masking两种mask方法

输入的每个样本由5个 ';' 分隔的字段组成,数据格式:

  • token_ids

  • sentence_type_ids:两句话,第一句都是0,第二句都是1

  • position_ids

  • seg_labels:分词边界信息: 0表示词首、1表示非词首、-1为占位符, 其对应的词为 CLS 或者 SEP;

  • next_sentence_label

例如:

1 1048 492 1333 1361 1051 326 2508 5 1803 1827 98 164 133 2777 2696 983 121 4 19 9 634 551 844 85 14 2476 1895 33 13 983 121 23 7 1093 24 46 660 12043 2 1263 6 328 33 121 126 398 276 315 5 63 44 35 25 12043 2;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;0 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;-1 0 0 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 -1 0 0 0 1 0 0 1 0 1 0 0 1 0 1 0 -1;0

和bert在mask上的区别:

一个句子的不同level的mask方式:

ERNIE 2.0: A CONTINUAL PRE-TRAINING FRAMEWORK FOR LANGUAGE UNDERSTANDING

跨语言

XLM

Massively Multilingual Sentence Embeddings for Zero-Shot Cross-Lingual Transfer and Beyond,XLM的主要思想还是来自于这篇文章,借用了BERT的框架最后成了XLM。本文提出了LASER(Language-Agnostic SEntence Representations)

XLM:facebook提出Cross-lingual Language Model Pretraining,加了language emb

  • 无监督的方法:只依赖单语种数据(monolingual data)

  • 有监督的方法:对平行语料使用新的跨语言loss

Facebook最新语言模型XLM-R:多项任务刷新SOTA,超越单语BERT

XLM-R

Unsupervised Cross-lingual Representation Learning at Scale

来自facebook。针对多种跨语言的传输任务,大规模地对多语言语言模型进行预训练可以显著提高性能。在使用超过 2TB 的已过滤 CommonCrawl 数据的基础上,研究者在 100 种语言上训练了基于 Transformer 的掩模语言模型。该模型被称为 XLM-R,在各种跨语言基准测试中,其性能显著优于多语言 BERT(mBERT),其中 XNLI 的平均准确度为+ 13.8%,MLQA 的平均 F1 得分为+ 12.3%,而 FQ 的平均 F1 得分为+ 2.1% NER。XLM-R 在低资源语言上表现特别出色,与以前的 XLM 模型相比,斯瓦希里语(Swahili)的 XNLI 准确性提升了 11.8%,乌尔都语(Urdu)的准确性提升了 9.2%。研究者还对获得这些提升所需的关键因素进行了详细的实证评估,包括(1)积极转移和能力稀释;(2)大规模资源资源的高低性能之间的权衡。最后,他们首次展示了在不牺牲每种语言性能的情况下进行多语言建模的可能性。XLM-Ris 在 GLUE 和 XNLI 基准测试中具有强大的单语言模型,因此非常具有竞争力。

更长序列

transformer-xl

Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context

最简单的处理长文本方法:对长文本直接切成多个segment,每个segment独立过transformer,segment间是没有信息流动的

transformer-xl的处理方法:参考RNN的隐藏记忆单元,对上一个segment计算的隐藏状态序列进行fixed和cached,并在模型处理下一个新的segment时将其缓存为可重用的扩展上下文

如图,第k+1层的第i个元素,用到了第k层的第i-1, i-2, ...,i - segment_len+1这几个元素,所以对于最顶层的来讲,实际看到的窗口就更长了。为此还提出了相对位置编码,即使用两个token的相对距离代替之前的绝对位置。

此外,Stabilizing Transformers for Reinforcement Learning说明了为什么标准的transformer架构很难在强化学习中优化。研究者同时提出了一种架构Gated Transformer-XL(GTrXL),可以很好地提升transformer架构和变体的稳定性,并加速学习,可以超过LSTM,在多任务学习 DMLab-30 基准上达到 SOTA 的水平。

XLNet

XLNet : 运行机制及和 Bert 的异同比较

Transformer-XL与XLNet笔记

什么是XLNet中的双流自注意力

20项任务全面碾压BERT,CMU全新XLNet预训练模型屠榜(已开源)

参考拆解XLNet模型设计,回顾语言表征学习的思想演进

他们创造了横扫NLP的XLNet:专访CMU博士杨植麟

XLNet: Generalized Autoregressive Pretraining for Language Understanding

代码:https://github.com/zihangdai/xlnet

  • 自回归(autoregressive, AR):主要的论文有这几篇:Semi-supervised sequence learningDeep contextualized word representationsImproving language understanding by generative pre-training。通过一个autoregressive的模型来估计文本语料库的概率分布。也就是给定一个文本序列x=(x1,,xT)\mathbf{x}=\left(x_{1}, \cdots, x_{T}\right),AR将likelihood因式分解(factorize)成一个前向的乘积p(x)=t=1Tp(xtx<t)p(\mathbf{x})=\prod_{t=1}^{T} p\left(x_{t} | \mathbf{x}_{<t}\right),或者是一个后向的乘积p(x)=t=T1p(xtx>t)p(\mathbf{x})=\prod_{t=T}^{1} p\left(x_{t} | \mathbf{x}_{>t}\right)。由于 AR 语言模型仅被训练用于编码单向(uni-directional)语境(前向或后向),因而在深度双向语境建模中效果不佳。而下游语言理解任务通常需要双向语境信息,导致 AR 语言建模无法实现有效预训练。

  • 自编码(autoencoding, AE):相关的预训练模型不会进行明确的密度估计(explicit density estimation),而是从残缺的(corrupted)输入中重建原始数据。例如bert,使用一定比例的[MASK],然后预测被mask掉的是什么东西。由于目标并不是密度估计,所以在重建的时候,可以考虑双向的上下文信息。但存在如下两个问题:

    • finetune时的真实数据缺少预训练期间使用的[MASK]这些mask信息,这导致预训练和微调效果的差异(pretrain-finetune discrepancy)

    • 输入中要预测的token是被mask掉的,所以无法像AR那样使用乘积rule来建立联合概率分布。也就是说,给定未mask的 token,BERT假设预测的token之间彼此独立,这其实是对自然语言中普遍存在的高阶、长期依赖关系的一种过度简化

基于这些优缺点,提出了一种泛化的自回归预训练模型XLNet:

  • Permutation Language Model(PLM):在自回归LM模式下,最大化所有可能的因式分解顺序的对数似然,学习双向语境信息;

    • 把原来的[MASK]这个token干掉了,转而用attention mask来搞

    • 引入了排列:即原来是1234,可以输入3241,这个时候改一下mask就行

  • 引入了Transformer-XL的主要思路:相对位置编码以及分段RNN机制,实践已经证明这两点对于长文档任务是很有帮助的

更多的任务

MT-DNN

Multi-Task Deep Neural Networks for Natural Language Understanding

其他改进

RoBERTa

参考重回榜首的BERT改进版开源了,千块V100、160GB纯文本的大模型

RoBERTa: A Robustly Optimized BERT Pretraining Approach

  • 修改了一些超参

  • 删掉nsp任务

  • 更大的batchsize和学习率

RoBERTa中文预训练模型,你离中文任务的「SOTA」只差个它

https://github.com/brightmart/roberta_zh

DeBERTa

Deberta: Decoding-enhanced bert with disentangled attention

  • disentangled attention mechanism:每个词使用2个向量,HH编码内容,PP编码相对位置,i和j间的attention如下:

Ai,j={Hi,Pij}×{Hj,Pji}T=HiHjT+HiPjiT+PijHjT+PijPjiT\begin{array}{r} \mathrm{A}_{\mathrm{i}, \mathrm{j}}=\left\{\mathrm{H}_{\mathrm{i}}, \mathrm{P}_{\mathrm{i} \mid \mathrm{j}}\right\} \times\left\{\mathrm{H}_{\mathrm{j}}, \mathrm{P}_{\mathrm{j} \mid \mathrm{i}}\right\}^{\mathrm{T}} \\ =\mathrm{H}_{\mathrm{i}} \mathrm{H}_{\mathrm{j}}^{\mathrm{T}}+\mathrm{H}_{\mathrm{i}} \mathrm{P}_{\mathrm{j} \mid \mathrm{i}}^{\mathrm{T}}+\mathrm{P}_{\mathrm{i} \mid \mathrm{j}} \mathrm{H}_{\mathrm{j}}^{\mathrm{T}}+\mathrm{P}_{\mathrm{i} \mid \mathrm{j}} \mathrm{P}_{\mathrm{j} \mid \mathrm{i}}^{\mathrm{T}} \end{array}
  • 预训练:使用enhanced mask decoder,把绝对位置信息引入解码层,来预估被mask掉的token

  • finetune:virtual adversarial training

ELECTRA

2019最佳预训练模型:非暴力美学,1/4算力超越RoBERTa

ELECTRA: 超越BERT, 19年最佳NLP预训练模型

ELECTRA: pre-training text encoders as discriminators rather than generators

使用新的预训练task:RTD(replaced token detection):

  • 使用一个生成网络采样出token,替换一些原有的token

  • 训练一个判别模型,预估一个token是否是被替换的

RTD比MLM更sample-efficient,因为RTD只做二分类,而MLM需要做全词表的softmax

sentence Transformers

俄罗斯套娃 (Matryoshka) 嵌入模型概述

Matryoshka representation learning

俄罗斯套娃嵌入模型旨在将更重要的信息存储在早期的维度中,将不太重要的信息存储在后面的维度中。俄罗斯套娃嵌入模型的这一特点允许我们截断模型产生的原始 (大) 嵌入,同时仍保留足够的信息以在下游任务上表现良好。

https://sbert.net/examples/training/matryoshka/README.html

训练时:

from sentence_transformers import SentenceTransformer
from sentence_transformers.losses import CoSENTLoss, MatryoshkaLoss

model = SentenceTransformer("microsoft/mpnet-base")

base_loss = CoSENTLoss(model=model)
loss = MatryoshkaLoss(
    model=model,
    loss=base_loss,
    matryoshka_dims=[768, 512, 256, 128, 64],
    matryoshka_weight=[1, 1, 1, 1, 1],
)

model.fit(
    train_objectives=[(train_dataset, loss)],
    ...,
)

预测时

from sentence_transformers import SentenceTransformer
from sentence_transformers.util import cos_sim

model = SentenceTransformer("tomaarsen/mpnet-base-nli-matryoshka")

matryoshka_dim = 64
embeddings = model.encode(
    [
        "The weather is so nice!",
        "It's so sunny outside!",
        "He drove to the stadium.",
    ]
)
embeddings = embeddings[..., :matryoshka_dim] # Shrink the embedding dimensions
print(embeddings.shape)
# => (3, 64)

# Similarity of the first sentence to the other two:
similarities = cos_sim(embeddings[0], embeddings[1:])
print(similarities)
# => tensor([[0.8910, 0.1337]])

注意,如果嵌入已经归一化,那么在截断后它们将不再归一化,因此你可能需要重新归一化

from sentence_transformers import SentenceTransformer
from sentence_transformers.util import cos_sim
import torch.nn.functional as F

model = SentenceTransformer("nomic-ai/nomic-embed-text-v1.5", trust_remote_code=True)

matryoshka_dim = 64
embeddings = model.encode(
    [
        "search_query: What is TSNE?",
        "search_document: t-distributed stochastic xxx.",
        "search_document: Amelia Mary Earhart was xxx.",
    ],
    convert_to_tensor=True,
)
# The Nomic team uses a custom architecture, 
# making them recommend Layer Normalization before truncation
embeddings = F.layer_norm(embeddings, normalized_shape=(embeddings.shape[1],))
embeddings[..., :matryoshka_dim] # Shrink the embedding dimensions

similarities = cos_sim(embeddings[0], embeddings[1:])
# => tensor([[0.7154, 0.4468]])

Piccolo2

拿下SOTA!最强中文Embedding模型对标OpenAI,技术路线公开

Piccolo2: General Text Embedding with Multi-task Hybrid Loss Training

https://huggingface.co/sensenova/piccolo-large-zh-v2

更小的BERT

BERT 瘦身之路:Distillation,Quantization,Pruning

albert

刚刚,Google发布24个小型BERT模型,直接通过MLM损失进行预训练

ALBERT:用于语言表征自监督学习的轻量级 BERT

谷歌ALBERT模型V2+中文版来了:之前刷新NLP各大基准,现在GitHub热榜第二

超小型BERT中文版横空出世!模型只有16M,训练速度提升10倍

https://github.com/brightmart/albert_zh

预训练小模型也能拿下13项NLP任务,谷歌ALBERT三大改造登顶GLUE基准

ALBERT 模型在 GLUE、RACE 和 SQuAD 基准测试上都取得了新的 SOTA 效果,并且参数量还少于 BERT-large。

ALBERT: a lite bert for self-supervised learning of language representations

通过对词嵌入矩阵进行因式分解,再为下游任务共享不同层的所有参数,这样可以大大降低 BERT 的参数量。

还提出了一种新型句间连贯性损失函数,它可以强迫模型学习句间的连贯性表达,从而有利于各种下游 NLP 任务。

ALBERT 通过两个参数削减技术克服了扩展预训练模型面临的主要障碍。

  • 对嵌入参数化进行因式分解:将大的嵌入矩阵分解为两个小的矩阵,从而将隐藏层的大小与词汇嵌入的大小分离开来。这种分离使得隐藏层的增加更加容易,同时不显著增加词汇嵌入的参数量。

  • 跨层参数共享:避免参数量随着网络深度的增加而增加。

两种技术都显著降低了 BERT 的参数量,同时不对其性能造成明显影响,从而提升了参数效率。ALBERT 的配置类似于 BERT-large,但参数量仅为后者的 1/18,训练速度却是后者的 1.7 倍。这些参数削减技术还可以充当某种形式的正则化,可以使训练更加稳定,而且有利于泛化。

为了进一步提升 ALBERT 的性能,还引入了一个自监督损失函数,用于句子级别的预测(SOP)。SOP 主要聚焦于句间连贯,用于解决原版 BERT 中下一句预测(NSP)损失低效的问题。

albert_tiny:

input_ids先查word_embeddings(\(V\times E=21118*128)),得到dim=128的表示,再查word_embeddings_2(\(E\times M =128*312\)),得到dim=312的表示。

搞positionembedding时,并不用输入0 1 2...,只需要做一些slice的变换就行了

    with tf.control_dependencies([assert_op]):
      full_position_embeddings = tf.get_variable(
          name=position_embedding_name,
          shape=[max_position_embeddings, width],
          initializer=create_initializer(initializer_range))
      # Since the position embedding table is a learned variable, we create it
      # using a (long) sequence length `max_position_embeddings`. The actual
      # sequence length might be shorter than this, for faster training of
      # tasks that do not have long sequences.
      #    
      # So `full_position_embeddings` is effectively an embedding table
      # for position [0, 1, 2, ..., max_position_embeddings-1], and the current
      # sequence has positions [0, 1, 2, ... seq_length-1], so we can just
      # perform a slice.
      position_embeddings = tf.slice(full_position_embeddings, [0, 0],
                                     [seq_length, -1]) 
      num_dims = len(output.shape.as_list())

      # Only the last two dimensions are relevant (`seq_length` and `width`), so
      # we broadcast among the first dimensions, which is typically just
      # the batch size.
      position_broadcast_shape = [] 
      for _ in range(num_dims - 2):
        position_broadcast_shape.append(1)
      position_broadcast_shape.extend([seq_length, width])
      position_embeddings = tf.reshape(position_embeddings,
                                       position_broadcast_shape)
      output += position_embeddings

然后会通过create_attention_mask_from_input_mask把input_ids和input_mask搞一下,得到attention_mask去和attention做mask,主要是算loss啥的,把后面的mask掉不算

distillbert

参考小版BERT也能出奇迹:最火的预训练语言库探索小巧之路

1.4w个stars。。

https://huggingface.co/transformers

DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter

tinybert

TinyBERT:模型小7倍,速度快8倍,华中科大、华为出品

TinyBERT: Distilling BERT for Natural Language Understanding

提出了一个two-stage learning framework,在pre-training阶段和task-specific阶段都进行distill。

相比baseline,只有28% parameters和31%的inference时间

在glue上,7.5x小,infer上有9.4x快。

哪吒”出世!华为开源中文版BERT模型

NEZHA: Neural Contextualized Representation for Chinese Language Understanding

https://github.com/huawei-noah/Pretrained-Language-Model

华为诺亚方舟开源哪吒、TinyBERT模型,可直接下载使用

reformer

哈希革新Transformer:这篇ICLR高分论文让一块GPU处理64K长度序列

Reformer: The Efficient Transformer

https://github.com/google/trax/blob/master/trax/models/research/reformer.py

大型的 Transformer 往往可以在许多任务上实现 sota,但训练这些模型的成本很高,尤其是在序列较长的时候。在 ICLR 的入选论文中,我们发现了一篇由谷歌和伯克利研究者发表的优质论文。文章介绍了两种提高 Transformer 效率的技术,最终的 Reformer 模型和 Transformer 模型在性能上表现相似,并且在长序列中拥有更高的存储效率和更快的速度。论文最终获得了「8,8,6」的高分。在最开始,文章提出了将点乘注意力(dot-product attention)替换为一个使用局部敏感哈希(locality-sensitive hashing)的点乘注意力,将复杂度从 O(L2 ) 变为 O(L log L),此处 L 指序列的长度。此外,研究者使用可逆残差(reversible residual layers)代替标准残差(standard residuals),这使得存储在训练过程中仅激活一次,而不是 n 次(此处 n 指层数)。最终的 Reformer 模型和 Transformer 模型在性能上表现相同,同时在长序列中拥有更高的存储效率和更快的速度。

大幅减少GPU显存占用:可逆残差网络(The Reversible Residual Network)

LTD-bert

内存用量1/20,速度加快80倍,腾讯QQ提出全新BERT蒸馏框架,未来将开源

Q-bert

AAAI 2020 | 超低精度量化BERT,UC伯克利提出用二阶信息压缩神经网络

Q-BERT: Hessian Based Ultra Low Precision Quantization of BERT

Adabert

推理速度提升29倍,参数少1/10,阿里提出AdaBERT压缩方法

AdaBERT: Task-Adaptive BERT Compression with Differentiable Neural Architecture Search

仅解码器的GPT

AI也能精彩表达:几种经典文本生成模型一览

GPT

2018年的Improving language understanding by generative pre-training,生成式预训练(Generative pre-training, gpt),用transformer的decoder,参数量117m(0.1b),无监督预训练和有监督微调。

微调阶段为每种下游任务专门设计:

  • 分类:输入一段文本,经过transformer,最后接一个Linear

  • entailment(蕴含):输入2段文本,premise(假设)和hypothesis(假说),经过transformer,最后接一个Linear

  • 相似度:输入2段文本a和b,a+b过transformer,b+a过transformer,再合起来接一个Linear

  • 多选题:输入context+答案1过transformer+Linear,答案2、答案3同样操作,将3个输出合在一起求softmax

GPT2

2019年的Language models are unsupervised multitask learners模型结构小改,增加数据,参数量变大为15亿(1.5b),无监督语言建模。

  • layernorm前移到每个sub-block之前

  • additional layernorm在最后的self-attention block才加上

  • 修改初始化方法,以考虑残差路径上的累积并缩放残差层的权重

15亿参数最强通用NLP模型面世!Open AI GPT-2可信度高于所有小模型

中文GPT2

只需单击三次,让中文GPT-2为你生成定制故事

https://github.com/imcaspar/gpt2-ml

https://colab.research.google.com/github/imcaspar/gpt2-ml/blob/master/pretrained_model_demo.ipynb

语言模型秒变API,一文了解如何部署DistilGPT-2

huggingface的distill gpt-2:https://github.com/huggingface/transformers

nanogpt代码解读

简化版的gpt, tiktoken:gpt2中使用的开源分词工具,比huggingface的tokenizer快得多

import tiktoken
enc = tiktoken.get_encoding("gpt2")

# 字节对编码过程,我的输出是[31373, 995]
encoding_res = enc.encode("hello world")
print(encoding_res)

# 字节对解码过程,解码结果:hello world
raw_text = enc.decode(encoding_res)
print(raw_text)

类似的:https://github.com/karpathy/llm.c

https://github.com/karpathy/build-nanogpt/tree/master

fork了一个:https://github.com/daiwk/build-nanogpt

GPT的整体结构:

class GPT(nn.Module):

    def __init__(self, config):
        super().__init__()
        self.config = config

        self.transformer = nn.ModuleDict(dict(
            wte = nn.Embedding(config.vocab_size, config.n_embd),
            wpe = nn.Embedding(config.block_size, config.n_embd),
            # 这里有n层,每层是一个Block
            h = nn.ModuleList([Block(config) for _ in range(config.n_layer)]),
            # 最后一层需要加一个layer norm
            ln_f = nn.LayerNorm(config.n_embd),
        ))
        # 最后一层的linear
        self.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False)

        # weight sharing scheme
        self.transformer.wte.weight = self.lm_head.weight

        # init params
        self.apply(self._init_weights)
class Block(nn.Module):

    def __init__(self, config):
        super().__init__()
        self.ln_1 = nn.LayerNorm(config.n_embd)
        self.attn = CausalSelfAttention(config)
        self.ln_2 = nn.LayerNorm(config.n_embd)
        self.mlp = MLP(config)

    def forward(self, x):
        # 这里对原来的add&norm进行了改造,保留一个从始至终的+x的操作,让梯度能够直通输入
        x = x + self.attn(self.ln_1(x))
        x = x + self.mlp(self.ln_2(x))
        return x
class MLP(nn.Module):

    def __init__(self, config):
        super().__init__()
        self.c_fc    = nn.Linear(config.n_embd, 4 * config.n_embd)
        self.gelu    = nn.GELU(approximate='tanh')
        self.c_proj  = nn.Linear(4 * config.n_embd, config.n_embd)
        self.c_proj.NANOGPT_SCALE_INIT = 1

    def forward(self, x):
        x = self.c_fc(x)
        x = self.gelu(x)
        x = self.c_proj(x)
        return x
class CausalSelfAttention(nn.Module):

    def __init__(self, config):
        super().__init__()
        assert config.n_embd % config.n_head == 0
        # key, query, value projections for all heads, but in a batch
        self.c_attn = nn.Linear(config.n_embd, 3 * config.n_embd)
        # output projection
        self.c_proj = nn.Linear(config.n_embd, config.n_embd)
        self.c_proj.NANOGPT_SCALE_INIT = 1
        # regularization
        self.n_head = config.n_head
        self.n_embd = config.n_embd
        # not really a 'bias', more of a mask, but following the OpenAI/HF naming though
        self.register_buffer("bias", torch.tril(torch.ones(config.block_size, config.block_size))
                                     .view(1, 1, config.block_size, config.block_size))

    def forward(self, x):
        B, T, C = x.size() # batch size, sequence length, embedding dimensionality (n_embd)
        # calculate query, key, values for all heads in batch and move head forward to be the batch dim
        # nh is "number of heads", hs is "head size", and C (number of channels) = nh * hs
        # e.g. in GPT-2 (124M), n_head=12, hs=64, so nh*hs=C=768 channels in the Transformer
        qkv = self.c_attn(x)
        q, k, v = qkv.split(self.n_embd, dim=2)
        k = k.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
        q = q.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
        v = v.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
        y = F.scaled_dot_product_attention(q, k, v, is_causal=True) # flash attention
        y = y.transpose(1, 2).contiguous().view(B, T, C) # re-assemble all head outputs side by side
        # output projection
        y = self.c_proj(y)
        return y

编码器+解码器

T5

谷歌T5模型刷新GLUE榜单,110亿参数量,17项NLP任务新SOTA

谷歌最新T5模型17项NLP任务霸榜SuperGLUE,110亿参数量!

Exploring the limits of transfer learning with a unified text-to-text transformer

将所有NLP任务都建模成text-to-text的生成任务,

mT5(mt5: A massively multilingual pre-trained text-to-text transformer)是T5的变种,基于新的Common Crawl的数据集(包括101种语言)上预训练

MASS

MASS: Masked Sequence to Sequence Pre-training for Language Generation

bert只使用了Transformer的encoder部分,其下游任务也主要是适用于自然语言理解(NLU),对于类似文本摘要、机器翻译、对话应答生成等自然语言生成(NLG)任务显然是不太合适的。MASS 采用了编码器-解码器框架,并尝试在给定部分句子的情况下修复整个句子。MASS输入句子包含了一些连续的 Token,并且中间会带有一些连续的Mask,模型的任务是预测出被Mask掉的词是什么。相比 BERT 只有编码器,MASS 联合训练编码器与解码器,能获得更适合机器翻译的表征能力。

训练步骤主要分为两步:

  • Encoder: 输入为被随机mask掉连续部分token的句子,使用Transformer对其进行编码;这样处理的目的是可以使得encoder可以更好地捕获没有被mask掉词语信息用于后续decoder的预测;

  • Decoder: 输入为与encoder同样的句子,但是mask掉的正好和encoder相反,和翻译一样,使用attention机制去训练,但只预测encoder端被mask掉的词。该操作可以迫使decoder预测的时候更依赖于source端的输入而不是前面预测出的token,防止误差传递。

BART

多项NLP任务新SOTA,Facebook提出预训练模型BART​

BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension

BART是一个适用于seq2seq模型的去噪自编码器。预训练包括两个阶段:

  • 使用任意噪声函数破坏文本

  • 用seq2seq模型来重建原始文本

LLM概述

PLM(pretrained language models),即bert等

LLM简史

LLM列表(持续更新中)

  • 百亿:除了LLaMA(最大650亿)和NLLB(最大545亿),大多数在100亿-200亿之间,通常需要数百甚至上千个GPU或TPU。

  • 千亿:OPT、OPT-IML、BLOOM和BLOOMZ与GPT-3(175B)大致相同,GLM有1300亿,Galactica有1200亿,通常需要数千个GPU或者TPU。

ckpt?模型发布时间大小预训练数据规模硬件训练时间

Y

2019.10

11B

1万亿tokens

1024 TPU v3

-

N

2020.05

175B

3000万亿tokens

-

-

N

2020.06

600B

1万亿tokens

2048 TPU v3

4天

Y

2020.10

13B

1万亿tokens

-

-

Y

2021.04

13B

1.1TB

2048 Ascend 910

-

Y

2021.06

198B

2.6TB

-

-

N

2021.07

12B

1000万亿tokens

-

-

N

2021.07

10B

3750亿tokens

384 v100

-

N

2021.08

178B

3000亿tokens

800 GPU

-

N

2021.09

82B

3000亿tokens

1024 A100

13.4天

N

2021.09

137B

-

128 TPU v3

60小时

N

2021.10

245B

1800亿tokens

2128 GPU

-

Y

2021.10

11B

-

512 TPU v3

27小时

N

2021.12

52B

4000亿tokens

-

-

N

2021.12

175B

-

-

-

N

2021.12

280B

3000亿tokens

4096 TPU v3

920小时

N

2021.12

260B

-

-

-

N

2021.12

1200B

2800亿tokens

1024 TPU v4

574小时

N

2022.01

137B

7680亿tokens

1024 TPU v3

57.5天

N

2022.01

530B

2700亿tokens

4480 80G A100

-

N

2022.02

41B

9670亿tokens

-

-

N

2022.03

175B

-

-

-

N

2022.03

70B

1.4万亿tokens

-

-

Y

2022.03

16B

5770亿tokens

-

-

Y

2022.04

20B

825GB

96 40G A100

-

Y

2022.04

11B

-

256 TPU v3

4小时

N

2022.04

540B

7800亿tokens

6144 TPU v4

-

Y

2022.05

20B

825GB

96 40G A100

-

Y

2022.05

175B

1800亿tokens

992 80G A100

-

Y

2022.07

54.5B

-

-

-

N

2022.08

20B

1.3万亿tokens

128 A100

120天

N

2022.09

70B

64 TPU v3

-

-

N

2022.09

10B

3000亿tokens

128 A100 40G

24天

N

2022.10

540B

-

512 TPU v4

5天

N

2022.10

540B

-

512 TPU v4

37小时

N

2022.10

540B

-

-

-

Y

2022.10

130B

4000亿tokens

768 40G A100

60天

Y

2022.10

11B

-

-

-

Y

2022.11

176B

3660亿tokens

384 80G A100

105天

Y

2022.11

13B

-

-

-

Y

2022.11

120B

1060亿tokens

-

-

Y

2022.11

176B

-

-

-

Y

2022.12

175B

-

128 40G A100

-

Y

2023.02

65B

1.4万亿tokens

2048 80G A100

21天

N

2023.03

-

-

-

-

Y

2022.09

13B

8500亿tokens

1536 Ascend 910

60天

N

2023.03

1085B

3290亿tokens

512 Ascend 910

100天

Y

2023.04

12B

3000亿tokens

256 40G A100

-

可以直接把对应的md丢给gpt,叫它导出一个excel,然后就可以自定义排序或者画散点图看了

LLM数据集

llm中文数据集:https://juejin.cn/post/7238921093553438779

  • Books:

    • BookCorpus:超过11000本电子书,用于GPT和GPT-2。

    • Gutenberg:超过70000本文学作品,包括小说、散文、诗歌、戏剧、历史、科学、哲学和其他公共领域,用于MT-NLG和LLaMA。

    • Books1和Books2:比BookCorpus大得多,但未公开,用于GPT-3。

  • CommonCrawl:最大的开源网络爬虫数据库之一,百万亿字节,有大量噪音和低质信息,需要过滤,有如下4个子集:

    • C4:包括en(806G,训练T5、LaMDA、Gopher、UL2)、en.noclean(6T)、realnewslike(36G)、webtextlike(17G)、multilingual(38T,训练mT5)。

    • CC-Stories:31G,内容以故事的形式展示

    • CC-News:76G

    • RealNews:120G

  • Reddit Links:Reddit上的帖子,高赞通常比较有用,可以拿来创建高质量数据集。

    • WebText:由Reddit上的高赞链接组成,未公开,对应的开源版是OpenWebText

    • Pushshift.io:实时更新的数据集,包括Reddit自创建以来的历史数据,有数据存储,也有实用工具,供用户搜索、总结和统计分析。

  • Wikipedia:大部分文章使用写作风格,并支持引用,英语版本用于大多数LLM,如GPT-3、LaMDA、LLaMA,还有多语言版。

  • Code:包括开源许可证的公共代码库(如github)和与代码相关的问答平台(如StackOverflow),Google公开了BigQuery数据集,CodeGen用的BIGQUERY是其的一个子集。

  • 其他:

    • The Pile有800G,包括书籍、网站、代码、科学论文和社交媒体平台,有22个子集,用于GPT-J(6B)、CodeGen(16B)、Megatron-Turing NLG(530B)。

    • ROOTS由各种小数据集组成,共1.6T,包括59种语言(自然语言和编程语言),用于BLOOM。

LLM开源库

一些开源的小模型:从零训练的 1B 以下小模型汇总

一些综述

大模型面试八股

大模型八股答案(一)——基础知识

大模型八股答案(二)——训练框架

扩展法则(scaling law)

openai的扩展法则

2020年,openai的Scaling laws for neural language models通过拟合模型在不同数据大小(2000w到230亿个token)、不同的模型大小(7.68亿到15亿个非嵌入参数)的性能,提出了在计算预算cc的条件下,LL是用nats表示的交叉熵损失,模型性能与模型规模NN数据集规模DD以及训练计算量CC间存在如下幂律关系:

L(N)=(NcN)αN,αN0.076,Nc8.8×1013L(N)=(\frac{N_c}{N})^{\alpha _N}, {\alpha}_N\sim 0.076,N_c\sim 8.8\times 10^{13}

L(D)=(DcD)αD,αD0.05,Nc5.4×1013L(D)=(\frac{D_c}{D})^{\alpha _D}, {\alpha}_D\sim 0.05,N_c\sim 5.4\times 10^{13}

L(C)=(CcC)αC,αC0.05,Cc3.1×108L(C)=(\frac{C_c}{C})^{\alpha _C}, {\alpha}_C\sim 0.05,C_c\sim 3.1\times 10^{8}

其中,NcN_c表示非嵌入参数数量,DcD_c表示训练token数量,CcC_c表示FP-days。

Go Wider Instead of Deeper说了,transformer效果的提升不在于计算量的变大,而应该在于通过提升模型的hidden dim来增加模型参数量

Chinchilla扩展法则

DeepMind在Training compute-optimal large language models中提出了Chichilla扩展法则来指导LLM最优计算量的训练。通过变化更大范围的模型大小(7000w到160亿参数)和数据大小(50亿到5000亿个token)进行实验,拟合了如下的扩展法则:

L(N,D)=E+ANα+BDβL(N, D)=E+\frac{A}{N^\alpha}+\frac{B}{D^\beta}

其中E=1.69,A=406.4,B=410.7,α=0.34,β=0.28E=1.69,A=406.4,B=410.7,\alpha = 0.34, \beta =0.28,通过在约束条件C6NDC\approx 6ND下优化损失L(N,D)L(N,D),将计算预算最优地分配给模型大小和数据大小的方法:

Nopt(C)=G(C6)a,Dopt(C)=G1(C6)bN_{o p t}(C)=G\left(\frac{C}{6}\right)^a, \quad D_{o p t}(C)=G^{-1}\left(\frac{C}{6}\right)^b

其中a=αα+βa=\frac{\alpha}{\alpha+\beta}b=βα+βb=\frac{\beta}{\alpha+\beta}GG是由A,B,α,βA,B,\alpha,\beta计算出的扩展系数。

随着计算预算的增加,

  • openai的扩展法则更偏向于将更大预算分给模型大小,因为其对比各模型时使用了固定的训练数据量和学习率等超参,低估了数据量的作用。每增加10倍的计算量,应该让数据集大小增加为约1.8倍,模型参数量增加为约5.5倍。即模型参数量更加的重要

  • Chinchilla扩展法则认为模型大小和数据大小要同比例增加,即aabb取值差不多。因为其在无视模型大小的前提下,发现设置与数据量差不多match的学习率能获得更好的loss。每增加10倍的计算量,应该让数据集大小增加为约3.16倍,模型参数量也增加为约3.16倍。即数据集大小和模型参数量一样重要

然而,有一些能力(如涌现)无法根据扩展法则进行预测,只有当模型达到一定规模时才会出现。

飘红的就是常见的10B模型,大概要205B的token来训练,能达到计算最优点,当然并不一定是loss最小的点,这个可以参考llama3的现象

scaling law的一些讨论

Scaling Laws 又失灵了?谷歌新研究:扩散模型不是越大越好

Bigger is not Always Better: Scaling Properties of Latent Diffusion Models

腾讯混元、北大发现Scaling law「浪涌现象」,解决学习率调参难题

Surge Phenomenon in Optimal Learning Rate and Batch Size Scaling

涌现能力

涌现能力:在小型模型中不存在而在大型模型中产生的能力,当规模达到一定程度时,性能显著提升,超出随机水平(参考 Emergent Abilities of Large Language Models)。与物理学中的相变现象类似(物质从一种相(状态)转变为另一种相的过程,通常伴随着能量的吸收或释放,并且涉及不同的物理性质,例如固体、液体和气体之间的转变)。

普林斯顿DeepMind用数学证明:LLM不是随机鹦鹉!「规模越大能力越强」有理论根据

A Theory for Emergence of Complex Skills in Language Models

LLM的3种典型涌现能力及其对应代表模型:

上下文学习(in-context learning)

GPT-3(Language models are few-shot learners)提出,只要提供一个自然语言指令和/或几个任务演示,语言模型就能通过完成输入文本的词序列的方式来为测试实例生成预期输出,不用额外的梯度更新。

  • ICL能力小模型不具备:1750亿的GPT-3有ICL能力,但GPT-1和GPT-2无此能力。

  • ICL能力取决于具体下游任务:130亿的GPT-3能在算术任务上有ICL,但1750亿的GPT-3在波斯语QA上无能为力。

指令遵循(instruction following)

使用自然语言描述的混合多任务数据集进行微调(指令微调),LLM在未见过的以指令形式描述的任务上表现出色,具有更好的泛化能力。例如Multitask prompted training enables zero-shot task generalizationTraining language models to follow instructions with human feedbackFinetuned language models are zero-shot learners

Finetuned language models are zero-shot learners的实验中,当模型大小达到680亿时,经过指定微调的LaMDA-PT开始在未见过的任务上显著优于未微调的模型,而80亿或更小的模型则没有这个现象。

Scaling instruction-finetuned language models的实验中,PaLM至少在620亿参数上才能在4个评估基准的各种任务上表现良好。

逐步推理(multi-step reasoning)

对于涉及多个推理步骤的复杂任务(如数学),可以使用思维链(Chain-of-Thought, CoT)提示策略(Chain of thought prompting elicits reasoning in large language models),让LLM通过利用中间推理步骤的提示机制来解决这类任务。

Chain of thought prompting elicits reasoning in large language models发现,CoT在模型大于600亿的PaLM和LaMBDA变体中能够提升在算术推理基准任务的效果,而当模型大于1000亿时,相比标准提示的优势更明显。

How does GPT Obtain its Ability? Tracing Emergent Abilities of Language Models to their Sources

LLM关键点

如何让LLM能够通用有能力

扩展

更大的模型、数据规模和更多的训练计算,但计算预算是有限的,可以用扩展法更高效地分配计算资源,如Chinchilla在相同计算预算下增加训练token数,优于更大模型规模的Gopher,同时需要数据清理。

训练

能力引导

当LLM执行某些特定任务时,可能不会显式地展示出其通用求解器的能力,设计合适的任务指令或具体的ICL策略可以激发这种能力,例如

  • 通过包含中间推理步骤的CoT提示

  • 使用自然语言表达的任务描述,对LLM进行指令微调

对齐微调

由于预训练语料库包括高质量和低质量的数据,LLM可能生成有毒、偏见甚至有害的内容,要让LLM和人类价值观保持一致,如有用性、诚实性和无害性。RLHF相关工作如Training language models to follow instructions with human feedbackDeep reinforcement learning from human preferences能够产生高质量、无害的回答(例如拒绝回答侮辱性问题)。

工具操作

LLM本质是基于海量文本语料库进行文本生成训练的,对于不适合以文本形式表达的任务表现不佳(如数字计算),且其能力受限于预训练数据,无法获取最新信息。可以利用外部工具:

数据收集

数据获取

  • 通用文本数据:

    • 网页:例如CommonCrawl,同时需要过滤和处理以提高质量

    • 对话文本:公共对话数据如PushShift.io,对于在线社交媒体的对话数据,可以转换成树形结构,每句话与回应其的话相连。多方的对话树可以划分为预训练语料库中的多个子对话。过度引入对话数据可能会有潜在风险(OPT: open pre-trained transformer language models):陈述性指令和直接疑问句被错误地认为是对话的开始,导致指令的有效性下降。

    • 书籍:更正式的长文本,利于学习语言知识建模长期依赖关系生成叙述性和连贯的文本

  • 专用文本数据:

    • 多语言文本:BLOOM的预训练语料中包括了46种语言,PaLM包含了122种

    • 科学文本:如arxiv论文、科学教材、数学 网页等,通常需要特定的标记化和预处理。

    • 代码:一是编程问答社区,二是开源代码仅为。对应长距离依赖和准确的执行逻辑,可能是复杂推理能力的来源。将推理任务格式化为代码形式还能帮LLM生成更准确的结果(如Language models of code are few-shot commonsense learnersAutoformalization with large language models

数据预处理

  • 质量过滤:有一些基于分类器的方法,例如维基百科的数据为正样本,负采样其他数据训练二分类器,但这种方法会删除方言、口语和社会语言的高质量文本,可能导致有偏、减少多样性。还有启发式的方法,主要包括:

    • 基于语言的过滤:如果该llm主要用于某种语言,可以把其他语言删了

    • 基于度量的过滤:利用生成文本的评估度量(如perplexity)来检测和删除不自然的句子

    • 基于统计的过滤:如标点符号分布符号和单词比例句子长度

    • 基于关键词的过滤:删除噪声或无用元素,如HTML标签超链接模板攻击性词语等。

  • 去重:Scaling laws and interpretability of learning from repeated data中发现重复数据会降低多样性,可能导致训练不稳定。下面3个级的去重都很有用

    • 句子级:删掉包含重复单词和短语的句子,因为可能在语言建模中引入重复模式The curious case of neural text degeneration)(后面的章节会讲)

    • 文档级:通过文档间的表层特征(如n-gram或单词重合率)来删掉重复文档

    • 数据集级:训练集中删掉测试集可能出现的重复文本,防止训练集和评估集间的重叠

  • 隐私去除:删掉可识别个人信息(PII),如基于关键词(姓名、地址、电话号码)识别。另外,Deduplicating Training Data Mitigates Privacy Risks in Language Models发现LLM在隐私攻击下的脆弱性可能归因于预训练语料中存在重复PII数据

  • 分词:可以直接利用已有分词器,也可以使用专门为预训练语料库设计的分词器,如SentencePiece,而且BPE(byte pair encoding)能确保分词后的信息不会丢失,但其中的如NFKC(Unicode normalization forms)的归一化技术可能会降低分词的性能

预训练语料的重要性

  • 混合来源:不同领域和场景的数据能让LLM有更强大的泛化能力。需要仔细设置数据分布,Gopher对数据分布消融,发现增加书籍数据可以提升捕捉长期依赖的能力,增加c4数据集比例可以提升其在c4验证集上的效果,但单独训练过多的某个领域数据会影响LLM在其他领域的泛化能力。

  • 数据量:模型性能方面,数据大小也能看到与模型大小类似的扩展法则。LLaMA发现,用更多数据训练更长时间,较小的模型也能实现良好性能。

  • 数据质量:Gopher、GLaM和T5都发现,在清理后的数据上训练能提升llm效果。数据的重复可能导致『双下降现象』(Scaling laws and interpretability of learning from repeated dataDeep double descent: Where bigger models and more data hurt),甚至会导致训练不稳定。此外,Scaling laws and interpretability of learning from repeated data还发现,重复数据会降低LLM从上下文复制的能力,从而影响ICL中的泛化能力

注:双下降指的是随着模型复杂性的增加,可能loss先下降,然后再升高,最后又下降

  • 当模型的复杂性低于数据的复杂性时,增加模型的复杂性可以帮助减少训练误差。

  • 当模型的复杂性超过数据的复杂性时,增加模型的复杂性反而可能导致训练误差增加。这是因为模型开始过拟合数据,捕获数据中的噪声而非实际的模式。

  • 当模型的复杂性远大于数据的复杂性时,训练误差可能再次开始减少。这是因为模型有足够的能力来对数据的噪声进行平滑,同时仍然能够捕获数据的实际模式。

一些训练+预测框架简介

pathways

Pathways: Asynchronous Distributed Dataflow for ML

下载了,pdf

这个回答分析得不错 https://www.zhihu.com/question/524596983/answer/2420225275

Google的大规模稀疏模型设计

DESIGNING EFFECTIVE SPARSE EXPERT MODELS

代码:https://github.com/tensorflow/mesh/blob/master/mesh_tensorflow/transformer/moe.py

megatron-lm

https://zhuanlan.zhihu.com/p/646406772

deepspeed

https://zhuanlan.zhihu.com/p/343570325

ray-llm

https://github.com/ray-project/ray/releases/tag/ray-2.4.0

Google的几大LLM加速工具

maxdiffusion

https://github.com/google/maxdiffusion

JetStream

https://github.com/google/JetStream

maxtext

https://github.com/google/maxtext

LLM模型架构

MoE原理

MoE模型的前世今生

MoE 系列论文解读:Gshard、FastMoE、Tutel、MegaBlocks 等

CMU开源GRIFFIN:一种新颖的无需训练的MoE方法,提高大模型的生成效率!

Prompt-prompted Mixture of Experts for Efficient LLM Generation

From Sparse to Soft Mixtures of Experts: softmoe

MoE的核心问题是一个如何把token分配给哪个专家离散优化问题,有如下离散+稀疏的分配方法,都需要辅助loss平衡每个专家的负载,以减少drop tokens:

  • 线性规划

  • 强化学习

  • 人为固定规则

  • 最优运输方法

  • 贪心topk token-choose-expert

  • 贪心topk expert-choose-token

在softmoe中,假设N个token,S个slot,E个expert

代码:

https://github.com/google-research/vmoe/blob/main/vmoe/projects/soft_moe/router.py#L97https://github.com/google-research/vmoe/blob/main/vmoe/moe.py#L128

A Survey on Mixture of Experts

主流框架

  • 编码器-解码器架构(encoder-decoder):标准Transformer,如T5、BART,只有少数LLLM还用这种结构,如Flan-T5

  • 因果解码器架构(causual decoder):也叫decoder-only单向注意力掩码,输入和输出token通过解码器以相同方式进行处理,以GPT系列为代表,现有大部分LLM都是这种架构,如OPT、BLOOM、Gopher等。

  • 前缀解码器架构(prefix decoder):修正因果解码器的掩码机制,使其能对前缀token执行双向注意力,并且仅对生成的token执行单向注意力(和encoder-decoder类似),即Unified language model pre-training for natural language understanding and generation提出的uni-lm。What language model architecture and pretraining objective works best for zero-shot generalization?建议不从头开始预训练,而是继续训练因果编码器,然后将其转换成前缀编码器以加速收敛。例如U-PaLM从PaLM演化而来,还有GLM-130B也是这种架构。

https://github.com/microsoft/unilm

对于这3种架构,都可以用MoE进行扩展,每个输入的一小部分神经网络权重稀疏激活,如Switch Transformer和GLaM。Unified scaling laws for routed language models发现,通过增加专家数量或总参数大小,性能会有显著改进。

讨论:为什么现在的LLM都是Decoder only的架构?

https://www.zhihu.com/question/588325646/answer/2940298964

组件配置

标准化(norm)

LN(layer norm)能缓解LLM训练不稳定的问题,其位置很重要。

此外,在emb后直接加额外的LN能提升训练稳定性,但会导致显著的性能下降(What language model to train if you have one million GPU hours?),在后来的LLM中被移除BLOOM: A 176b-parameter open-access multilingual language model)。

神经网络可能不再需要激活函数?Layer Normalization也具有非线性表达!

On the Nonlinearity of Layer Normalization

激活函数

FFN中的激活函数:

原始Transformer中

FFN(x,W1,W2,b1,b2)=max(0,xW1+b1)W2+b2\operatorname{FFN}\left(x, W_1, W_2, b_1, b_2\right)=\max \left(0, x W_1+b_1\right) W_2+b_2

T5中把bias干掉了

FFNReLU(x,W1,W2)=max(xW1,0)W2\operatorname{FFN}_{\operatorname{ReLU}}\left(x, W_1, W_2\right)=\max \left(x W_1, 0\right) W_2

然后,$\operatorname{GELU}(x)=x \Phi(x)$,同时$\operatorname{Swish}_\beta(x)=x \sigma(\beta x)$,接下来

GLU(x,W,V,b,c)=σ(xW+b)(xV+c)\operatorname{GLU}(x, W, V, b, c)=\sigma(x W+b) \otimes(x V+c) Bilinear(x,W,V,b,c)=(xW+b)(xV+c)\operatorname{Bilinear}(x, W, V, b, c)=(x W+b) \otimes(x V+c) ReGLU(x,W,V,b,c)=max(0,xW+b)(xV+c)\operatorname{ReGLU}(x, W, V, b, c)=\max (0, x W+b) \otimes(x V+c) GEGLU(x,W,V,b,c)=GELU(xW+b)(xV+c)\operatorname{GEGLU}(x, W, V, b, c)=\operatorname{GELU}(x W+b) \otimes(x V+c) SwiGLU(x,W,V,b,c,β)=Swishβ(xW+b)(xV+c)\operatorname{SwiGLU}(x, W, V, b, c, \beta)=\operatorname{Swish}_\beta(x W+b) \otimes(x V+c)

对应起来就是

FFNGLU(x,W,V,W2)=(σ(xW)xV)W2\operatorname{FFN}_{\mathrm{GLU}}\left(x, W, V, W_2\right)=(\sigma(x W) \otimes x V) W_2 FFNBilinear (x,W,V,W2)=(xWxV)W2\operatorname{FFN}_{\text {Bilinear }}\left(x, W, V, W_2\right)=(x W \otimes x V) W_2 FFNReGLU(x,W,V,W2)=(max(0,xW)xV)W2\operatorname{FFN}_{\operatorname{ReGLU}}\left(x, W, V, W_2\right)=(\max (0, x W) \otimes x V) W_2 FFNGEGLU (x,W,V,W2)=(GELU(xW)xV)W2\operatorname{FFN}_{\text {GEGLU }}\left(x, W, V, W_2\right)=(\operatorname{GELU}(x W) \otimes x V) W_2 FFNSwiGLU (x,W,V,W2)=(Swish1(xW)xV)W2\operatorname{FFN}_{\text {SwiGLU }}\left(x, W, V, W_2\right)=\left(\operatorname{Swish}_1(x W) \otimes x V\right) W_2

位置编码

Transformer的self-attention有转换不变性,故要位置编码以引入绝对或相对位置信息来建模序列。

Transformer升级之路:RoPE的底数设计原则

Base of RoPE Bounds Context Length

注意力机制和Bias

小结

归一化位置

sublayer表示FFN或self-attention模块

方法公式

post Norm

Norm(x+Sulayerb(x))\operatorname{Norm}(\mathbf{x}+\operatorname{Sulayerb}(\mathbf{x}))

pre Norm

x+Sublayer(Norm(x))\mathbf{x}+\operatorname{Sublayer}(\operatorname{Norm}(\mathbf{x}))

Sandwich Norm

x+Norm(Sublayer(Norm(x)))\mathbf{x}+\operatorname{Norm}(\operatorname{Sublayer}(\operatorname{Norm}(\mathbf{x})))

归一化方法

方法公式

Layer Norm

xμσγ+β,μ=1di=1dxi,σ=1di=1d(xiμ)2\frac{\mathrm{x}-\mu}{\sqrt{\sigma}} \cdot \gamma+\beta, \quad \mu=\frac{1}{d} \sum_{i=1}^d x_i, \quad \sigma=\sqrt{\frac{1}{d} \sum_{i=1}^d(x_i-\mu)^2}

RMSNorm

xRMS(x)γ,RMS(x)=1di=1dxi2\frac{\mathrm{x}}{\operatorname{RMS}(\mathrm{x})} \cdot \gamma, \quad \operatorname{RMS}(\mathbf{x})=\sqrt{\frac{1}{d} \sum_{i=1}^d x_i^2}

Deep Norm

LayerNorm(αx+Sublayer(x))LayerNorm (\alpha \cdot \mathbf{x}+\operatorname{Sublayer}(\mathbf{x}))

激活函数

方法公式

ReLU

ReLU(x)=max(x,0)\operatorname{ReLU}(\mathbf{x})=\max (\mathbf{x}, \mathbf{0})

GeLU

GeLU(x)=0.5x[1+erf(x/2)],erf(x)=2π0xet2dt\operatorname{GeLU}(\mathbf{x})=0.5 \mathrm{x} \otimes[1+\operatorname{erf}(\mathbf{x} / \sqrt{2})], \quad \operatorname{erf}(x)=\frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} d t

Swish

Swish(x)=xsigmoid(x)\operatorname{Swish}(\mathbf{x})=\mathbf{x} \otimes \operatorname{sigmoid}(\mathbf{x})

SwiGLU

SwiGLU(x1,x2)=Swish(x1)x2\operatorname{SwiGLU}\left(\mathbf{x}_1, \mathbf{x}_2\right)=\operatorname{Swish}\left(\mathbf{x}_1\right) \otimes \mathbf{x}_2

GeGLU

GeGLU(x1,x2)=GeLU(x1)x2\operatorname{GeGLU}\left(\mathbf{x}_1, \mathbf{x}_2\right)=\operatorname{GeLU}\left(\mathbf{x}_1\right) \otimes \mathbf{x}_2

位置嵌入

  • AijA_{ij}q和k之间注意力分数

  • rijr_{i-j}:基于q和k之间偏移的可学习标量

  • Rθ,ij\mathbf{R}_{\theta, i-j}:旋转角度为tθt\cdot \theta的旋转矩阵

方法公式

绝对位置编码

xi=xi+pi\mathbf{x}_i=\mathbf{x}_i+\mathbf{p}_i

相对位置编码

Aij=WqxixjTWkT+rijA_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{x}_j^T \mathbf{W}_k^T+r_{i-j}

RoPE

Aij=WqxiRθ,ijxjTWkTA_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{R}_{\theta, i-j} \mathbf{x}_j^T \mathbf{W}_k^T

Alibi

Aij=WqxiRθ,ijxjTWkTAij=WqxixjTWkTm(ij)A_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{R}_{\theta, i-j} \mathbf{x}_j^T \mathbf{W}_k^T A_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{x}_j^T \mathbf{W}_k^T-m(i-j)

预训练任务

语言建模

语言建模是仅解码器LLM的常见目标,给定token序列x={x1,,xn}\mathbf{x}=\left\{x_1, \ldots, x_n\right\},旨在基于序列中前面的token,自回归地预估目标token:

LLM(x)=i=1nlogP(xix<i)\mathcal{L}_{L M}(\mathbf{x})=\sum_{i=1}^n \log P\left(x_i \mid x_{<i}\right)

前缀解码器架构使用的是前缀语言建模任务,其loss不涉及对前缀内token的预测,故预训练时涉及的序列中token较少,故当预训练token数相同时,前缀语言模型的性能往往略低于传统语言模型任务。

另外,自回归的loss:

  • 训练时:是可以并行的,因为每个位置的label是已知的,可以并行算,

  • 预测时:是串行的,因为得预测完了第t个词,才能去预测第t+1个词。

去噪自编码

DAE是BERT待模型的常见任务,即MLM(masked language model),输入x\x~\mathbf{x}_{\backslash \tilde{\mathbf{x}}}是一些有随机替换区间的损坏文本,目标是恢复被替换的token x~\tilde{\mathbf{x}}

LDAE(x)=logP(x~x\x~)\mathcal{L}_{D A E}(\mathbf{x})=\log P\left(\tilde{\mathbf{x}} \mid \mathbf{x}_{\backslash \tilde{\mathbf{x}}}\right)

在T5和GLM-130B中使用,自回归地恢复替换区间

其他任务

multi-token prediction,一次预估未来的k个词

Better & Faster Large Language Models via Multi-token Prediction

新的模型结构

长上下文的问题

LLM长上下文的问题

以中文为例,大部分模型每个token对应的中文字数都>1.5个字,所以200k的token就对应30w字的上下文

对长文本的几个要求:

  • 在文本比较长的时候,还能保证通顺,ppl要足够低

  • 能attention到前面提过的细节,不能自我矛盾

注意:如果训练时是2k长度的语料,而推理设定8k窗口,那么PPL会急剧上升,因为

  • RoPE不能很好地处理没有训练过的位置编码

  • 推理时注意力机制所处理的token数量远超训练时的数量,导致注意力机制的崩坏

两阶段训练方式

  • 直接输入连续长文本(如书籍)

  • 多个中等文本拼接,再通过attention mask来限制各段文本之间注意力,让它们可以在各自的位置上各训各的,互不干扰。甚至实际上即使不做attention mask,效果也挺好。

如果简单地增加长度,例如从4k变到32k,长度增加8倍,为了加速计算需要缓存中间结果(如QK的结果是s2s^2的空间复杂度),所以显存会扩大82=648^2=64倍。一般的做法是2阶段:

  • 第一阶段:用2k或者4k训练一个基础模型,让模型学好文本内容短位置关系

  • 第二阶段:用比第一阶段小的数据量优化模型在长上下文的效果,具体做法见下节

针对位置编码的插值类方法

线性插值

Extending Context Window of Large Language Models via Positional Interpolation

NTK-Aware Interpolation

NTK-by-parts

Dynamically NTK Scaled RoPE

针对attention score的缩放方法

YaRN

logn

lossless long context

专访月之暗面杨植麟:lossless long context is everything

longRoPE

LongRoPE:超越极限,将大模型上下文窗口扩展超过200万tokens

CoPE

解决Transformer根本缺陷,CoPE论文爆火:所有大模型都能获得巨大改进

Contextual Position Encoding: Learning to Count What’s Important

retrieval head

Retrieval Head Mechanistically Explains Long-Context Factuality

SSM

挑战Transformer的Mamba是什么来头?作者博士论文理清SSM进化路径

Pretraining Without Attention

预训练无需注意力,扩展到4096个token不成问题,与BERT相当

Diffusion Models Without Attention

丢掉注意力的扩散模型:Mamba带火的SSM被苹果、康奈尔盯上了

Long Range Language Modeling via Gated State Spaces 认为 Transformer 和 SSM 完全可以互补。

选择性状态空间模型(selective state space model)是Mamba论文作者Albert Gu此前主导研发的S4架构(Structured State Spaces for Sequence Modeling)的一个简单泛化。

https://stacks.stanford.edu/file/druid:mb976vf9362/gu_dissertation-augmented.pdf

序列模型在训练和推理时的侧重点:

  • 训练时:在整个list上计算loss,需要优化forward的耗时

  • 推理时:一次输入一个时间步,需要高效地顺序处理

SSM原理

输入u(t)Ru(t) \in \mathbb{R},输出是y(t)Ry(t) \in \mathbb{R},引入状态x(t)RNx(t) \in \mathbb{R}^N,目标是学习映射u(t)y(t)u(t) \mapsto y(t)

x(t)=Ax(t)+Bu(t)y(t)=Cx(t)+Du(t)\begin{aligned} x^{\prime}(t) & =\boldsymbol{A} x(t)+\boldsymbol{B} u(t) \\ y(t) & =\boldsymbol{C} x(t)+\boldsymbol{D} u(t) \end{aligned}

结合维基百科的图,方便理解

各变量含义如下(看起来和RNN很像):

  • ARN×N\boldsymbol{A}\in \mathbb{R}^{N\times N}:状态矩阵

  • BRN×N\boldsymbol{B}\in \mathbb{R}^{N\times N}:输入矩阵

  • CRN×N\boldsymbol{C}\in \mathbb{R}^{N\times N}:输出矩阵

  • DRN×N\boldsymbol{D}\in \mathbb{R}^{N\times N}:feedforward矩阵或者feedthrough矩阵

  • x(t):=ddtx(t)x^{\prime}(t):=\frac{d}{d t} \mathbf{x}(t)x(t)x(t)关于tt的导数,所以图里有一个积分\int操作把它变回x(t)x(t)

假设序列长度为LL,那么

  • 时间复杂度:

    • SSM:O(N2L)O(N^2L),因为Ax(t)\boldsymbol{A} x(t)N×NN\times NN×1N\times 1的矩阵乘法,复杂度是N2N^2

    • RNN:O(N2L)O(N^2L),和SSM类似

    • CNN:O(kLM2)O(kLM^2),假设kk个卷积核,每个卷积核M×MM\times M,一般MNM \ll N

  • 空间复杂度:

    • SSM:O(N2+NL)O(N^2+NL),因为中间状态x(t)RNx(t) \in \mathbb{R}^N是需要额外存储

    • RNN:O(N2)O(N^2),所有时间步共享权重,不需要像SSM专门为每个时间步存一个状态x(t)x(t)

    • CNN:kM2kM^2

所以传统SSM的时空复杂度都很高,作者提出了S4(structured state space model)

Mamba

Mamba: Linear-Time Sequence Modeling with Selective State Spaces

https://huggingface.co/state-spaces

https://github.com/havenhq/mamba-chat

MODELING SEQUENCES WITH STRUCTURED STATE SPACES

Mamba2

再战Transformer!原作者带队的Mamba 2来了,新架构训练效率大幅提升

Transformers are SSMs: Generalized Models and Efficient Algorithms Through Structured State Space Duality

https://github.com/state-spaces/mamba

Mamba+Transformer

Mamba真比Transformer更优吗?Mamba原作者:两个都要!混合架构才是最优解

An Empirical Study of Mamba-based Language Models

Block-State Transformer

Block-State Transformer

Jamba

Mamba做大做强!混合Transformer,打败Transformer

https://huggingface.co/ai21labs/Jamba-v0.1

Hawk & Griffin

RNN效率媲美Transformer,谷歌新架构两连发:同等规模强于Mamba

Griffin: Mixing Gated Linear Recurrences with Local Attention for Efficient Language Models

简介

global attention在infer阶段的效率和序列长度成二次关系,而且序列长度与KV cache呈线性增长关系。Fast Transformer Decoding: One Write-Head is All You Need提出的multi-query attention(MQA)可以通过一个constant factor减小cache size,部分缓解这个问题,但cache还是与序列长度线性相关。

循环模型能够将整个序列压缩到一个fixed-size的hidden state,并通过迭代进行更新。但要想取代transformer,rnn不仅需要在效果上可比,还要相似的硬件效率,相关工作如下:

本文提出了新的RG-LRU层,一种新的gated linear recurrent layer,并基于此提出了将MLP和RG-LRU结合的Hawk,还有将MLP和RG-LRU与local attention混合的Griffin。

  • 对于最多超过7B的模型,Hawk和Griffin发现了held-out loss训练FLOPS间的power law scaling(上图左边)

  • Hawk-3B比Mamba-3B在下游任务上要好,而训练的token数只有mamba的一半;Griffin-7B和14B与Llama-2效果相当,而训练数据只有其1/7

  • 训练在TPU-v3上完成,用JAX中的Pallas实现了RG-LRU(Real-Gated Linear Recurrent Unit)层的内核(https://jax.readthedocs.io/en/latest/pallas/index.html),减小内存transfer

  • infer阶段比MQA的吞吐高很多(上图右边),而且对长序列有更低的latency

  • 训练时在长序列上比transformer更好,而且能够高效地学习复制和检索的任务。但如果没有finetune,直接对比pretrain的效果,transformer会更好

网络结构

包括三大类组件:

  • residual block:

  • MLP block:

  • temporal-mixing block

Residual Block

受pre-norm transformer的启发,用的RMSNorm

MLP block

参考Language modeling with gated convolutional networks(类似star两个W直接element-wise product),采用了gated MLP,即如下两个linear的结果(输入维度DD,输出维度都是MD,M=3MD,M=3)进行element-wise product(类似GeGLU(Glu variants improve transformer)),再过一个linear

  • 直接过一个linear,但没有激活

  • linear后加一个GeLU激活

Temporal-mixing block

global Multi-Query Attention(MQA)

Fast Transformer Decoding: One Write-Head is All You Need中为了加速推理,采用了MQA的方法,本文固定了head的维度为Dhead=128D_{head}=128,head的个数HH也固定,且HDhead=DHD_{head}=D,所以model的维度DD需要是128的倍数。没用绝对位置编码,用了RoPE。

local(sliding-window) MQA

Longformer: The long-document transformer提出了可以用local attention,即滑动窗口attention。让每个位置只和前面的固定个tokens去算attentioin,可以

  • 降低计算的FLOPS

  • 让KV cache的size的上界变成了window的size,从而不是序列长度的二次关系

RG-LRU

类似GSS block,也类似Mamba,输入DD,分别过一个linear得到两个分支,均是DRNND_{RNN}

两个分支的输出element-wise product一下,再过一个linear得到dd

参考Resurrecting Recurrent Neural Networks for Long Sequences提出的LRU(Linear Recurrent Unit),并参考传统LSTM和GRU引入了gate:

rt=σ(Waxt+ba), recurrence gate it=σ(Wxxt+bx), input gate at=acrt,ht=atht1+1at2(itxt).\begin{aligned} r_t & =\sigma\left(W_a x_t+b_a\right), \quad \text { recurrence gate } \\ i_t & =\sigma\left(W_x x_t+b_x\right), \quad \text { input gate } \\ a_t & =a^{c r_t}, \\ h_t & =a_t \odot h_{t-1}+\sqrt{1-a_t^2} \odot\left(i_t \odot x_t\right) . \end{aligned}

其中,recurrent weight a=σ(Λ)a=\sigma(\Lambda)是一个对角矩阵,Λ\Lambda是一个可学习的参数。cc是一个常数8,为了计算稳定,在log-space计算acrta^{c r_t},即先算出logat\log a_t,再取exp。

logat=logacrt=logσ(Λ)crt=csoftplus(Λ)rt\log a_t=\log a^{c r_t}=\log \sigma(\Lambda)^{c r_t}=-\operatorname{csoftplus}(\Lambda) \odot r_t

(这个公式可能有点问题,感觉应该是csoftplus(Λ)rt-\operatorname{csoftplus}(-\Lambda) \odot r_t)

还有如下几个特点:

gate特点

先复习一下LSTM:

GRU:

  • 重置门(reset gate):如果重置门关闭,会忽略掉历史信息,即历史不相干的信息不会影响未来的输出。

  • 更新门(update gate):将LSTM的输入门和遗忘门合并,用于控制历史信息对当前时刻隐层输出的影响。如果更新门接近1,会把历史信息传递下去。

  • 两个gate只和xtx_t有关,ht1h_{t-1}无关

  • input gate iti_t和LSTM类似,直接对输入xtx_t进行filter或者scale down。

  • recurrent gate rtr_t和之前的gate机制不同:

    • mamba里的selection机制和GRU的update gate类似,在之前的状态当前输入xtx_t之间进行插值(interpolate),功能类似LSTM的forget gate,能够reset状态,并遗忘之前的信息

    • 本文的recurrent gate则类似于在LRU的更新和之前的隐藏状态之间进行插值,能够有效地丢弃输入,并且保持之前历史里的所有信息。使得模型在处理不相关或重复输入(uniformative inputs)时,更能达到超指数的记忆能力,以更有效地保留有用信息(因为这个gateht1h_{t-1}无关)。

SAMBA

长文本模型近期研究工作梳理

SAMBA: Simple Hybrid State Space Models for Efficient Unlimited Context Language Modeling

feedback attention memory

TransformerFAM: Feedback attention is working memory

infini-attention

Leave No Context Behind: Efficient Infinite Context Transformers with Infini-attention

【重磅】谷歌重塑Transformer:无限记忆力,无限长输入,LLM基础研究重大突破

压缩记忆整合进标准的点积注意力机制,并在单个Transformer块内同时实现了掩码局部注意力长期线性注意力机制

与transformer-xl对比:

https://github.com/mustafaaljadery/gemma-2B-10M

https://github.com/dingo-actual/infini-transformer

MEGA

Mega: Moving average equipped gated attention

https://github.com/facebookresearch/mega

标准的self-attention公式

对于序列长度=nn的输入X={x1,x2,,xn}Rn×d\boldsymbol{X}=\left\{\mathbf{x}_1, \mathbf{x}_2, \ldots, \mathbf{x}_n\right\} \in \mathbb{R}^{n \times d},输出Y={y1,y2,,yn}Rn×d\boldsymbol{Y}=\left\{\mathbf{y}_1, \mathbf{y}_2, \ldots, \mathbf{y}_n\right\} \in \mathbb{R}^{n \times d}

Y=Attn(X)=f(QKTτ(X))V\boldsymbol{Y}=\operatorname{Attn}(\boldsymbol{X})=f\left(\frac{\boldsymbol{Q} \boldsymbol{K}^T}{\tau(\boldsymbol{X})}\right) \boldsymbol{V}
Q=XWq+bq,K=XWk+bk,V=XWv+bv\boldsymbol{Q}=\boldsymbol{X} W_q+b_q,\boldsymbol{K}=\boldsymbol{X} W_k+b_k,\boldsymbol{V}=\boldsymbol{X} W_v+b_v

其中, Attn : Rn×dRn×d\text { Attn : } \mathbb{R}^{n \times d} \rightarrow \mathbb{R}^{n \times d}Wq,Wk,WvRd×dW_q, W_k, W_v \in \mathbb{R}^{d \times d}bq,bk,bvRdb_q, b_k, b_v \in \mathbb{R}^d,而且有两种定义方式:

对于hh个attention heads,计算A=f(QKTτ(X))Rn×n\boldsymbol{A}=f\left(\frac{\boldsymbol{Q} \boldsymbol{K}^T}{\tau(\boldsymbol{X})}\right) \in \mathbb{R}^{n \times n}需要的时间和空间复杂度都是O(hn2)O(hn^2)

EMA

对于输出的序列Y\boldsymbol{Y}采用Exponential Moving Average(指数滑动平均)如下

yt=αxt+(1α)yt1\mathbf{y}_t=\boldsymbol{\alpha} \odot \mathbf{x}_t+(1-\boldsymbol{\alpha}) \odot \mathbf{y}_{t-1}

其中,α(0,1)d\boldsymbol{\alpha} \in(0,1)^d表示权重衰减,\odot是element-wise product

α\boldsymbol{\alpha}越大,1α1-\boldsymbol{\alpha}越小,对历史的衰减也越快:

EMA的计算看成nn独立的卷积,可以通过**FFT(快速傅立叶变换)**来加速计算。具体。。。再看看

Damped EMA:由于输入的x是d维向量,可以引入一个因子δ(0,1)d\boldsymbol{\delta} \in(0,1)^d让EMA更鲁棒:

yt=αxt+(1αδ)yt1\mathbf{y}_t=\boldsymbol{\alpha} \odot \mathbf{x}_t+(1-\boldsymbol{\alpha} \odot \boldsymbol{\delta}) \odot \mathbf{y}_{t-1}

MEGA

EMA可以看成是一种与位置相关的归纳偏置(inductive bias),即假设当前位置与之前位置满足滑动平均的关系,而attention矩阵的计算其实并没有考虑位置信息,所以可以把二者结合一下。

其中的multi-dimensional damped EMA大致流程如下:

  • 先变成h维:先把XRn×d\boldsymbol{X} \in \mathbb{R}^{n \times d}通过矩阵β\beta映射成URn×h\boldsymbol{U}\in \mathbb{R}^{n \times h}

  • 计算EMA:然后通过EMA得到hRn×h\boldsymbol{h}\in \mathbb{R}^{n \times h}(具体ht(j)=αjut(j)+(1αjδj)ht1(j)\mathbf{h}_t^{(j)}=\boldsymbol{\alpha}_j \odot \mathbf{u}_t^{(j)}+\left(1-\boldsymbol{\alpha}_j \odot \boldsymbol{\delta}_j\right) \odot \mathbf{h}_{t-1}^{(j)}

  • 再变回d维:再通过一个矩阵η\eta变回YRn×h\boldsymbol{Y}\in \mathbb{R}^{n \times h}

然后看整个流程:

  • 先计算EMA

X=EMA(X)Rn×dZ=ϕsilu (XWz+bz)Rn×z\begin{aligned} \boldsymbol{X}^{\prime} & =\operatorname{EMA}(\boldsymbol{X}) & & \in \mathbb{R}^{n \times d} \\ \boldsymbol{Z} & =\phi_{\text {silu }}\left(\boldsymbol{X}^{\prime} W_z+b_z\right) & & \in \mathbb{R}^{n \times z} \end{aligned}
  • 再基于EMA的结果计算QK,基于原始的X计算V:

Q=κqZ+μqRn×zK=κkZ+μkRn×zV=ϕsilu (XWv+bv)Rn×v\begin{array}{ll} \boldsymbol{Q}=\boldsymbol{\kappa}_q \odot \boldsymbol{Z}+\boldsymbol{\mu}_q & \in \mathbb{R}^{n \times z} \\ \boldsymbol{K}=\boldsymbol{\kappa}_k \odot \boldsymbol{Z}+\boldsymbol{\mu}_k & \in \mathbb{R}^{n \times z} \\ \boldsymbol{V}=\phi_{\text {silu }}\left(\boldsymbol{X} W_v+b_v\right) & \in \mathbb{R}^{n \times v} \end{array}
  • 计算带位置bias的attention:

O=f(QKTτ(X)+brel)VRn×v\boldsymbol{O}=f\left(\frac{\boldsymbol{Q} \boldsymbol{K}^T}{\tau(\boldsymbol{X})}+\boldsymbol{b}_{\mathrm{rel}}\right) \boldsymbol{V} \quad \in \mathbb{R}^{n \times v}
  • 通过reset gate γ\boldsymbol{\gamma}和update gate φ\boldsymbol{\varphi}计算输出

γ=ϕsilu (XWγ+bγ)Rn×vφ=ϕsigmoid (XWφ+bφ)Rn×dH^=ϕsilu (XWh+(γO)Uh+bh)Rn×dY=φH^+(1φ)XRn×d\begin{aligned} \boldsymbol{\gamma} & =\phi_{\text {silu }}\left(\boldsymbol{X}^{\prime} W_\gamma+b_\gamma\right) & & \in \mathbb{R}^{n \times v} \\ \boldsymbol{\varphi} & =\phi_{\text {sigmoid }}\left(\boldsymbol{X}^{\prime} W_{\varphi}+b_{\varphi}\right) & & \in \mathbb{R}^{n \times d} \\ \hat{\boldsymbol{H}} & =\phi_{\text {silu }}\left(\boldsymbol{X}^{\prime} W_h+(\boldsymbol{\gamma} \boldsymbol{O}) U_h+b_h\right) & & \in \mathbb{R}^{n \times d} \\ \boldsymbol{Y}&=\boldsymbol{\varphi} \odot \hat{\boldsymbol{H}}+(1-\boldsymbol{\varphi}) \odot \boldsymbol{X} \quad & & \in \mathbb{R}^{n \times d} \end{aligned}

这里把attention里的softmax改成了如下的laplace函数:

flaplace (x;μ,σ)=0.5×[1+erf(xμσ2)]f_{\text {laplace }}(x ; \mu, \sigma)=0.5 \times\left[1+\operatorname{erf}\left(\frac{x-\mu}{\sigma \sqrt{2}}\right)\right]

其中,erf(x)=1πxxet2 dt=2π0xet2 dt\operatorname{erf}(x)=\frac{1}{\sqrt{\pi}} \int_{-x}^x e^{-t^2} \mathrm{~d} t=\frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} \mathrm{~d} t误差函数

为了让laplace逼近frelu 2f_{\text {relu }^2},对于x=2x=\sqrt{2}这个点,求解如下方程

frelu2 (2)=flaplace (2)frelu2 (2)=flaplace (2)\begin{aligned} & f_{\text {relu2 }}(\sqrt{2})=f_{\text {laplace }}(\sqrt{2}) \\ & f_{\text {relu2 }}^{\prime}(\sqrt{2})=f_{\text {laplace }}^{\prime}(\sqrt{2}) \end{aligned}

可以得到μ=1/2\mu=\sqrt{1 / 2}σ=1/4π\sigma=\sqrt{1 / 4 \pi},对应的曲线和准确率如下:

mega-chunk

将序列切分成长度固定为cck=n/ck=n/c个chunk,对每个chunk独立计算上面的attention,这样复杂度就变成了O(kc2)=O(nc)O(kc^2)=O(nc),由于有EMA,所以这样做还是能够保持一定程度的长距离依赖。

MEGALODON

Meta无限长文本大模型来了:参数仅7B,已开源

革命新架构掀翻Transformer!无限上下文处理,2万亿token碾压Llama 2

MEGALODON: Efficient LLM Pretraining and Inference with Unlimited Context Length

https://github.com/XuezheMax/megalodon

Megalodon: Efficient LLM Pretraining and Inference with Unlimited Context Length

基于MEGA进行改进,能够同时实现

  • 高效训练(减少通信和计算量)

  • 高效推理(保持恒定的KV缓存)

MOD

Mixture-of-Depths: Dynamically allocating compute in transformer-based language models

multi-head moe

微软让MoE长出多个头,大幅提升专家激活率

Multi-Head Mixture-of-Experts

https://github.com/yushuiwx/MH-MoE

Lory

150B token从头训练,普林斯顿Meta发布完全可微MoE架构Lory

Lory: Fully Differentiable Mixture-of-Experts for Autoregressive Language Model Pre-training

Perciever

Perceiver: General Perception with Iterative Attention

Aaren

Bengio等人新作:注意力可被视为RNN,新模型媲美Transformer,但超级省内存

Attention as an RNN

many-to-one RNN

对query向量qq的attention可以看成是一个函数,对输入的NN个token x1:Nx_{1: N}通过他们的key和value {(ki,vi)}i=1N\left\{\left(k_i, v_i\right)\right\}_{i=1}^N 变换成输出  Attention (q,k1:N,v1:N)\text { Attention }\left(q, k_{1: N}, v_{1: N}\right),假设sˉi=dot(q,ki)\bar{s}_i=\operatorname{dot}\left(q, k_i\right),那么输出就是

oN=i=1Nsoftmax(s)ivi=i=1Nexp(si)vii=1Nexp(si)=a^Nc^No_N=\sum_{i=1}^N \operatorname{softmax}(s)_i v_i=\frac{\sum_{i=1}^N \exp \left(s_i\right) v_i}{\sum_{i=1}^N \exp \left(s_i\right)}=\frac{\hat{a}_N}{\hat{c}_N}

可以发现,分子和分母其实都可以写成递推形式a^k=a^k1+exp(sk)vk\hat{a}_k=\hat{a}_{k-1}+\exp \left(s_k\right) v_kc^k=c^k1+exp(sk)\hat{c}_k=\hat{c}_{k-1}+\exp \left(s_k\right),由于直接这么做可能会产生很大或者很小的值(例如算exp),所以可以通过如下方式进行缓解:计录到第k步的最大值mk=maxi{1,,k}sim_k=\max _{i \in\{1, \ldots, k\}} s_i,然后减掉它,即ak=i=1kexp(simk)via_k=\sum_{i=1}^k \exp \left(s_i-m_k\right) v_ick=i=1kexp(simk)c_k=\sum_{i=1}^k \exp \left(s_i-m_k\right),这样就可以改写为如下形式:

ak=ak1exp(mk1mk)+vkexp(skmk)ck=ck1exp(mk1mk)+exp(skmk)mk=max(mk1,sk)\begin{aligned} a_k & =a_{k-1} \exp \left(m_{k-1}-m_k\right)+v_k \exp \left(s_k-m_k\right) \\ c_k & =c_{k-1} \exp \left(m_{k-1}-m_k\right)+\exp \left(s_k-m_k\right) \\ m_k & =\max \left(m_{k-1}, s_k\right) \end{aligned}

其中第一行其实就是simk=simk+mk1mks_i-m_k=s_i-m_k+m_{k-1}-m_k,然后exp一下,exp(simk)=exp(simk)exp(mk1mk)exp(s_i-m_k)=exp(s_i-m_k)exp(m_{k-1}-m_k),总结成如下图:

所以Attention的RNN cell就是输入(ak1,ck1,mk1,q)\left(a_{k-1}, c_{k-1}, m_{k-1}, q\right),输出(ak,ck,mk,q)\left(a_k, c_k, m_k, q\right),初始的状态是(a0,c0,m0,q)=(0,0,0,q)\left(a_0, c_0, m_0, q\right)=(0,0,0,q)

然后就可以将之前的attention看成如下几类many-to-one的RNN了:

  • 传统attention只计算最后的一个输出

  • self-attention使用输入token作为初始状态

  • Perceiver的cross-attention使用依赖input的隐变量作为初始状态

对于新来的token而言:

  • 传统的RNN一般是流式地输入数据,因此只需要O(1)的内存和计算就行了

  • Transformer需要把这个新token当成一个初始状态加进来,所以需要把之前时间步的再重新算一次,需要O(N)的计算

  • Perceiver中的隐变量是依赖输入的,而且这个新token会改变value,因此初始状态也会变,所以需要从头算一遍,需要O(NL)的计算,L是隐变量个数(可以参考代码perceiver_torch和如下gpt4o的回答)

many-to-many RNN

要计算{oi=Attention(q,x1:i)}i=1N\left\{o_i=\operatorname{Attention}\left(q, x_{1: i}\right)\right\}_{i=1}^N,通过如下的并行前缀扫描算法,对于NN个序列数据的NN个前缀,通过关联运算符\oplus并行计算,能够高效地通过{xk}k=1N\left\{x_k\right\}_{k=1}^N计算{i=1kxi}k=1N\left\{\bigoplus_{i=1}^k x_i\right\}_{k=1}^N

由于Attention(q,x1:k)=ok=akck\operatorname{Attention}\left(\mathrm{q}, \mathrm{x}_{1: \mathrm{k}}\right)=o_k=\frac{a_k}{c_k},为了计算{ Attention (q,x1:k)}k=1N\left\{\text { Attention }\left(\mathrm{q}, \mathrm{x}_{1: \mathrm{k}}\right)\right\}_{k=1}^N,只需要先按这个并行扫描算法计算{ak}k=1N\left\{a_k\right\}_{k=1}^N{ck}k=1N\left\{c_k\right\}_{k=1}^N{mk}k=1N\left\{m_k\right\}_{k=1}^N,再把aka_kckc_k结合起来就行。

接来来定义三元组(mA,uA,wA)\left(\mathrm{m}_A, \mathrm{u}_A, \mathrm{w}_A\right),其中

  • AA:一些下标的集合

  • mA=maxiAsi\mathrm{m}_A=\max _{i \in A} s_i

  • uA=iAexp(simA)\mathrm{u}_A=\sum_{i \in A} \exp \left(s_i-\mathrm{m}_A\right)

  • wA=iAexp(simA)vi\mathrm{w}_A=\sum_{i \in A} \exp \left(s_i-\mathrm{m}_A\right) v_i

所以并行扫描算法的输入是{(m{i},u{i},W{i})}i=1N={(si,1,vi)}i=1N\left\{\left(\mathrm{m}_{\{i\}}, \mathrm{u}_{\{i\}}, \mathrm{W}_{\{i\}}\right)\right\}_{i=1}^N=\left\{\left(s_i, 1, v_i\right)\right\}_{i=1}^N,再来定义操作\oplus

(mA,uA,wA)(mB,uB,wB)=(mAB,uAB,wAB)\left(\mathrm{m}_A, \mathrm{u}_A, \mathrm{w}_A\right) \oplus\left(\mathrm{m}_B, \mathrm{u}_B, \mathrm{w}_B\right)=\left(\mathrm{m}_{A \cup B}, \mathrm{u}_{A \cup B}, \mathrm{w}_{A \cup B}\right)

其中,

  • mAB=max(mA, mB)\mathrm{m}_{A \cup B}=\max \left(\mathrm{m}_A, \mathrm{~m}_B\right)

  • uAB=uAexp(mAmAB)+uBexp(mBmAB)\mathrm{u}_{A \cup B}=\mathrm{u}_A \exp \left(\mathrm{m}_A-\mathrm{m}_{A \cup B}\right)+\mathrm{u}_B \exp \left(\mathrm{m}_B-\mathrm{m}_{A \cup B}\right)

  • wAB=wAexp(mAmAB)+wBexp(mBmAB)\mathrm{w} _{A \cup B}=\mathrm{w}_A \exp \left(\mathrm{m}_A-\mathrm{m}_{A \cup B}\right)+\mathrm{w}_B \exp \left(\mathrm{m}_B-\mathrm{m}_{A \cup B}\right)

这个并行扫描算法最终输出下式,即{(mk,ck,ak)}k=1N\left\{\left(m_k, c_k, a_k\right)\right\}_{k=1}^N

{(m{1,,k},u{1,,k},w{1,,k})}k=1N={(mk,i=1kexp(simk),i=1kexp(simk)vi)}k=1N\left\{\left(\mathrm{m}_{\{1, \ldots, k\}}, \mathrm{u}_{\{1, \ldots, k\}}, \mathrm{w}_{\{1, \ldots, k\}}\right)\right\}_{k=1}^N=\left\{\left(m_k, \sum_{i=1}^k \exp \left(s_i-m_k\right), \sum_{i=1}^k \exp \left(s_i-m_k\right) v_i\right)\right\}_{k=1}^N

Aaren

Aaren(attention as a recurrent newral network)的结构如下:

h1(0),,hN(0)x1,,xN[h1(j+1),,hN(j+1)]Aaren(q(j),[h1(j),,hN(j)])\begin{aligned} h_1^{(0)}, \ldots, h_N^{(0)} & \leftarrow x_1, \ldots, x_N \\ {\left[h_1^{(j+1)}, \ldots, h_N^{(j+1)}\right] } & \leftarrow \operatorname{Aaren}\left(q^{(j)},\left[h_1^{(j)}, \ldots, h_N^{(j)}\right]\right) \end{aligned}

transformer的query是输入的token,而Aaren的query token qq是在训练的过程中通过bp学习的。迭代地计算yky_k只需要常数级的计算,因为它依赖hk1h_{k-1}xkx_k

transformer:

  • 使用kv cache时需要线性的内存

  • 需要保存所有之前的tokens,包括在中间层的那些

aaren:

  • 只需要常数级的内存

  • 不需要保存之前的所有tokens

Matmul-free

从LLM中完全消除矩阵乘法,效果出奇得好,10亿参数跑在FPGA上接近大脑功耗

H2O attention

H2O: Heavy-Hitter Oracle for Efficient Generative Inference of Large Language Models

TransNAR

拯救Transformer推理能力!DeepMind新研究TransNAR:给模型嵌入「算法推理大脑」

Transformers meet Neural Algorithmic Reasoners

基于:Neural Algorithmic Reasoning

softmax数学原理

通向概率分布之路:盘点Softmax及其替代品

把softmax的分母记为Z(x)Z(x),其对数是max的一个光滑近似:

logZ(x)=logj=1nexj=logsumexp(x)limτ0+τlogsumexp(x/τ)=max(x)\begin{array}{r} \log Z(\boldsymbol{x})=\log \sum_{j=1}^n e^{x_j}=\operatorname{logsumexp}(\boldsymbol{x}) \\ \lim _{\tau \rightarrow 0^{+}} \tau \operatorname{logsumexp}(\boldsymbol{x} / \tau)=\max (\boldsymbol{x}) \end{array}

τ\tau取1时,可以得到logsumexp(x)max(x)\operatorname{logsumexp}(\boldsymbol{x}) \approx \max (\boldsymbol{x})

StreamingLLM

Efficient Streaming Language Models with Attention Sinks

https://github.com/mit-han-lab/streaming-llm

集成到trt-llm里了:https://github.com/NVIDIA/TensorRT-LLM/tree/main/examples/llama#run-llama-with-streamingllm

  • trtllm-build时,加上--streamingllm enable

  • infer时,加上--sink_token_length设置sink的token数,加上--max_attention_window_size设置sliding_window

是否还要RAG?

谷歌重磅:告别RAG,长上下文的大语言模型无需检索增强

memory^3

鄂维南院士领衔新作:大模型不止有RAG、参数存储,还有第3种记忆

Memory3 : Language Modeling with Explicit Memory

TSLLM

没想到!AlphaZero式树搜索也能用来增强大语言模型推理与训练

AlphaZero-Like Tree-Search can Guide Large Language Model Decoding and Training

https://github.com/waterhorse1/LLM_Tree_Search

PEER

单一作者论文,谷歌提出百万专家Mixture,超越密集前馈、稀疏MoE

MoE也有Scaling Law,「百万专家」利用率近100%!DeepMind华人挑战MoE极限

Mixture of A Million Experts

TTT

彻底改变语言模型:全新架构TTT超越Transformer,ML模型代替RNN隐藏状态

Learning to (Learn at Test Time): RNNs with Expressive Hidden States

https://github.com/test-time-training/ttt-lm-jax

https://github.com/test-time-training/ttt-lm-pytorch

Axiomatic Training

6700万参数比肩万亿巨兽GPT-4!微软MIT等联手破解Transformer推理密码

公理训练让LLM学会因果推理:6700万参数模型比肩万亿参数级GPT-4

Teaching Transformers Causal Reasoning through Axiomatic Training

训练大模型新范式——公理框架(Axiomatic Framework),作者从头开始训练了6700万参数的模型,仅使用了简单的因果链作为训练数据。在推断复杂图表中的因果关系时,67M模型的表现超越了十亿级参数LLM,甚至可以与GPT-4相媲美。

PNN

AI大模型有望再扩1000倍!剑桥耶鲁康奈尔:PNN是变革关键

Training of Physical Neural Networks

训练框架

mfu(Model Flops Utilization)模型算力利用率是分布式训练效率的优化目标。

一个模型定义好之后,前向和反向的计算量就是固定(不考虑动态图的话)的,除以每个step的latency就是mfu。以nanoGPT中的代码为例:

def estimate_mfu(self, fwdbwd_per_iter, dt):
    """ estimate model flops utilization (MFU) in units of A100 bfloat16 peak FLOPS """
    # first estimate the number of flops we do per iteration.
    # see PaLM paper Appendix B as ref: https://arxiv.org/abs/2204.02311
    N = self.get_num_params()
    cfg = self.config
    L, H, Q, T = cfg.n_layer, cfg.n_head, cfg.n_embd//cfg.n_head, cfg.block_size
    flops_per_token = 6*N + 12*L*H*Q*T
    flops_per_fwdbwd = flops_per_token * T # 计算量(T是序列长度)
    flops_per_iter = flops_per_fwdbwd * fwdbwd_per_iter # 每个step的flops * 每一次更新梯度要多少个step
    # express our flops throughput as ratio of A100 bfloat16 peak flops
    flops_achieved = flops_per_iter * (1.0/dt) # per second 一轮的计算量/一轮的耗时
    flops_promised = 312e12 # A100 GPU bfloat16 peak flops is 312 TFLOPS
    mfu = flops_achieved / flops_promised
    return mfu

##...
def xxx():
    # timing and logging
    t1 = time.time()
    dt = t1 - t0 ## 一次gradient_accumulation_steps后 更新梯度
    t0 = t1
    if iter_num % log_interval == 0 and master_process:
        # get loss as float. note: this is a CPU-GPU sync point
        # scale up to undo the division above, approximating the true total loss
        # (exact would have been a sum)
        lossf = loss.item() * gradient_accumulation_steps
        if local_iter_num >= 5: # let the training loop settle a bit
            mfu = raw_model.estimate_mfu(batch_size * gradient_accumulation_steps, dt)
            running_mfu = mfu if running_mfu == -1.0 else 0.9*running_mfu + 0.1*mfu
        print(f"iter {iter_num}: loss {lossf:.4f}, time {dt*1000:.2f}ms, mfu {running_mfu*100:.2f}%")
    iter_num += 1
    local_iter_num += 1

一般分布式训练参数量越多->卡数越多->通信占比越高->MFU越低,所以要优化通信效率。

优化设置

  • batchsize:通常用比较大的batchsize,提高训练稳定性吞吐量。GPT-3和PaLM在训练时动态增加batshzie,最终达到百万级别,batchsize从3.2w逐渐增加到320w个token

  • 优化器:

    • Adam和AdamW:基于一阶梯度优化的低阶矩自适应估计,用于GPT-3等,超参β1=0.9,β2=0.95,ϵ=108\beta_1=0.9, \beta_2=0.95, \epsilon=10^{-8}

    • Adafactor:在训练过程中节省显存,用于PaLM、T5等,超参β1=0.9,β2=1.0k0.8\beta_1=0.9, \beta_2=1.0-k^{-0.8}

  • 学习率:

    • 预热(warm-up):在训练的初始0.1%到0.5%的steps中,用线性预热策略逐渐增加学习率到最大值(5×1055 \times 10^{-5}1×1041 \times 10^{-4}之间,GPT-3是6×1056 \times 10^{-5}

    • 衰减(decay):后续steps中余弦衰减,逐渐降低到最大值的约10%,直到收敛

  • 稳定训练:

    • 权重衰减和梯度裁剪:权重衰减率设为0.1,梯度裁剪阈值设为1.0

    • 梯度检查点:容易出现loss突增,PaLM和OPT从发生突增前的一个ckpt重新开始训练,并跳过可能有问题的数据

    • 缩减emb梯度:GLM发现emb的异常梯度通常会导致loss突增,故缩减emb梯度以缓解

混合精度训练

FP16

Mixed precision training提出了用16位float(FP16)训练,减少内存使用和通信开销。A100等GPU具有的FP16计算单元FP32的两倍,故FP16的计算效率能进一步提高。

  • 推理(预测):所有参数都是fp16,相对fp32,存储变成一半,速度提升1倍。

  • 训练:参数和梯度用fp32存储,但是在计算前转成fp16计算后转回fp32。主要为了防止溢出,loss要乘一个scale,然后在fp16的梯度要除以scale。

以adam优化器为例,对于每1个参数来说,fp16的训练占用20bytes显存,包括(详见:https://zhuanlan.zhihu.com/p/519264636

  • fp16的参数:2bytes

  • fp16的梯度:2bytes

  • 优化器状态(optimizer state):16bytes

    • fp32参数(4bytes)

    • fp32梯度(4bytes)(zero论文里提到的,用于reduce之类操作时需要的fp32内存,以1.5B的gpt2为例,需要6GB内存,倒推回来,就需要6/1.5byte=4byte)

    • fp32 variance【历史梯度平方和】(4bytes)

    • fp32 momentum【历史梯度滑动平均】(4bytes)

而在预测时只要存一个fp16的参数(2bytes)就行,所以预测的显存是训练的1/10,对应1.3B参数量的gpt2-xl,训练要占用20B×1.3×109=26GB20B\times 1.3\times 10^9=26GB,预测只要2.6GB

BF16

FP16可能导致计算精度的损失从而影响模型性能,BLOOM里用BF16(brain floating point)比FP16分配更多指数位更少的有效位,在准确性方面更好

https://blog.csdn.net/orangerfun/article/details/133106913

bf16的指数位和fp32一样多

可扩展的训练

需要提高训练吞吐量加载更大模型到显存中

3D并行

如下三种并行(数据并行、流水线并行、张量并行)的组合

数据并行(Data Parallelism)

模型参数和优化器状态复制到多个GPU上,每个GPU只处理分给它的数据,不同GPU算出的梯度进行聚合得到batch的梯度,再更新所有GPU上的模型。高度可扩展,增加GPU数就能提高训练吞吐。

torch的ddp

from torch.nn.parallel import DistributedDataParallel as DDP

ddp = int(os.environ.get('RANK', -1)) != -1 # is this a ddp run?
if ddp:
    init_process_group(backend=backend)
    ddp_rank = int(os.environ['RANK'])
    ddp_local_rank = int(os.environ['LOCAL_RANK'])
    device = f'cuda:{ddp_local_rank}'
    torch.cuda.set_device(device)
    # this process will do logging, checkpointing etc.
    master_process = ddp_rank == 0
    seed_offset = ddp_rank # each process gets a different seed

# wrap model into DDP container
if ddp:
    model = DDP(model, device_ids=[ddp_local_rank])

可以一起搞的技巧——梯度累积,当显存不够跑较大的batchsize时,训练效果可能会很差,可以先跑多个mini-batch的前向和反向,把梯度累积起来,再更新一次参数,在数学上等价于跑一个较大的batchsize

# forward backward update, with optional gradient accumulation to simulate larger batch size
# and using the GradScaler if data type is float16
for micro_step in range(gradient_accumulation_steps):
    if ddp:
        # in DDP training we only need to sync gradients at the last micro step.
        # 最后一个micro step才要sync梯度
        model.require_backward_grad_sync = (micro_step == gradient_accumulation_steps - 1)
    with ctx:
        logits, loss = model(X, Y)
    loss.backward() # 只是计算梯度,并不真的更新
optimizer.step()
optimizer.zero_grad(set_to_none=True)

也可以用torch的no_sync():

ddp = torch.nn.parallel.DistributedDataParallel(model, pg)
with ddp.no_sync():
    for input in inputs:
        ddp(input).backward()  # no synchronization, accumulate grads
ddp(another_input).backward()  # synchronize grads

流水线并行(Pipeline Parallelism)

将LLM的不同层分配到多个GPU上,一般Transformer模型中会将连续的层加载到同一GPU上,以减少在GPU间传输已计算的隐层状态或梯度的成本。简单的实现会导致GPU利用率降低,因为每个GPU要等前一个完成计算,导致不必要的气泡开销,如下方法可以提高流水线效率:

1) GPipe

Gpipe主要思想:

  • 图a:把模型不同layers顺序放在4张卡上,0->3卡流水线前向计算loss,3->0再反向计算gradients

  • 图b:从时间顺序上看,每张卡有3/4时间是空闲的,GPU利用率非常低

  • 图c:配合梯度累积,多个mini-batch可以同时跑在流水线里面,每张卡则有3/(3+4)的时间空闲(Bubble)

流水线并行的问题是中间有Bubble。当卡数KK,梯度累积次数MM,则Bubble=(K1)/(K1+M)Bubble=(K-1)/(K-1+M)

GPT里用Weight Tying提升效果,输入和输出共享vocab embedding

2) 重计算

重计算(recomputation)是对于pipeline parallelism非常重要的一个优化,最开始在Training Deep Nets with Sublinear Memory Cost一文中提到,在flash attention中也用了。

因为要做pipeline+梯度累积,前向过程中的激活值要保存,以留给反向过程使用,保存很多份的激活值对显存造成了很大压力。recomputation(也叫checkpointing)用时间来换空间(反向的时候进行一次激活值的重计算),可以缓解显存问题。

pytorch的实现。大致逻辑是包了一个autograd.Function,前向时保存一些inputs/rng_state(RNG state是Random Number Generator state的缩写,随机数生成器的状态。在深度学习和其他计算任务中,随机数生成器用于初始化参数、决定正则化技术如dropout的行为,以及在训练过程中选择样本等。RNG状态是指随机数生成器当前的内部状态,它可以用来在需要时重现或恢复特定的随机数序列,确保实验或模型训练的可重复性),反向时重新计算

深度更深的时候,一般效果更好

cpu offload:层数很深的时候,可能可以把一些计算挪到cpu上去,再搞回gpu

张量并行(Tensor Parallelism)

Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism

分解LLM的张量(参数矩阵),例如矩阵乘法Y=XAY=X AAA可以按列分成两个子矩阵A1A_1A2A_2,从而改为Y=[XA1,XA2]Y=\left[X A_1, X A_2\right],将A1A_1A2A_2放到不同GPU上,然后就可能通过跨GPU通信将两个GPU的结果merge。

参考https://zhuanlan.zhihu.com/p/622036840

原始矩阵乘法是[m,k], [k, n] -> [m, n],有如下两种矩阵分解的等效:

  • 列并行(column parallelism):第一个矩阵不变,第二个矩阵竖着劈成两半,即B=[B1,B2]B=[B_1, B_2]

    • [m,k], [k, n/2] -> [m, n/2]

    • concat([m, n/2], [m, n/2]) -> [m, n]

  • 行并行(row parallelism):两个矩阵都横着劈成两半,即A=[A1A2],B=[B1B2]A=\left[\begin{array}{l}A_1 \\A_2\end{array}\right],B=\left[\begin{array}{l}B_1 \\B_2\end{array}\right]。从2推广到k,其实就是split-k算法,把两个矩阵都分成k个小块,两两相乘后,最后reduce_sum一下。因为每个线程计算的矩阵更小了,开销小,可以通过加大线程数来提升并行效率。

    • [m, k/2], [k/2, n] -> [m, n]

    • elemwise_add([m, n], [m, n]) -> [m, n]

行并行还可以扩展到推荐里,假设user有k/2维,item也是k/2维,concat在一起,然后过一个k*d的mlp,即[1,k] * [k, d] -->[1,d],那么可以按行并行的方法,拆成2个[1, k/2][k/2,d]相乘,再相加。这样item侧的[k/2,d]可以把全库缓存过来,在线实时算user,排序时把对应item向量抽出来,和user加起来就行

megatron对transformer进行了如下优化:

  • MLP第一个nn按列分割,第二个nn按行分割,中间省了一次通信

  • Attention按照head来分割(类似列分割),后面接的nn按行分割,中间也省了一次通信

图里面的通信算子

  • ff是前向identity,反向all-reduce

  • gg是前向all-reduce,反向identity

综合来看,一层transformer layer如下

具体的计算量可以参考https://colossalai.org/docs/features/1D_tensor_parallel/#introduction

ZeRO

ZeRO: Memory Optimization Towards Training A Trillion Parameter Models

fp16那一节中,optimizer state的显存占用,在前向反向的时候都不用,只有最后optimizer step的时候才用。

===>zero的思想:把optimizer state分shard存在不同的卡上,只在最后gather时才用

ZeRO(Zero Redundancy Optimizer)在DeepSpeed库中提出,解决数据并行中的内存冗余问题。数据并行其实并不需要每个GPU都存整个模型、梯度和优化器参数,ZeRO在每个GPU仅保存部分数据,当需要其余数据时从其他GPU检索。3种解决方案:

  • 优化器状态分区:zero1,对显存最大开销的部分进行shard

  • 梯度分区:zero2

  • 参数分区:zero3

前两种方案不会增加通信开销,第三种方案增加约50%通信开销,但能节省和gpu数成比例的内存。

详见官方博客:ZeRO & DeepSpeed: New system optimizations enable training models with over 100 billion parameters

import deepspeed
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--local_rank", type=int, default=0)
deepspeed.add_config_arguments(parser)
args = parser.parse_args()

model, optimizer, _, _ = deepspeed.initialize(args=args,
                                              model=model,
                                              model_parameters=model.parameters())
X, Y = get_batch('train')
logits, loss = model(X, Y)
model.backward(loss)
model.step()

需要指定deepspeed的配置:

{
  "train_batch_size": 64,
  "gradient_accumulation_steps": 1,
  "optimizer": {
    "type": "Adam",
    "params": {
      "lr": 6e-4,
      "weight_decay": 1e-2,
      "betas": [0.9, 0.95]
    }zer
  },
  "scheduler": {
    "type": "WarmupLR",
    "params": {
        "warmup_min_lr": 6e-5,
        "warmup_max_lr": 6e-4,
        "warmup_num_steps": 2000
    }
  },
  "bf16": {
    "enabled": true
  },
  "zero_optimization": {
    "stage": 1
  }
}

启动:

deepspeed --num_gpus=8 train.py --deepspeed_config xx.json

facebook的开源库FSDP(full sharded data parallel)(Fairscale: A general purpose modular pytorch library for high performance and large scale training)里基于pytorch实现了类似ZeRO的技术。

from torch.distributed.fsdp import FullyShardedDataParallel as FSDP, ShardingStrategy
model = FSDP(model)  #, sharding_strategy=ShardingStrategy.SHARD_GRAD_OP)

还有一些paper也能降低内存,如

Reducing activation recomputation in large transformer models

Training deep nets with sublinear memory cost

序列并行

序列并行(Sequence Parallelism: Long Sequence Training from System Perspective),可以进一步分解Transformer的注意力操作。

Reducing Activation Recomputation in Large Transformer Models这个也是

对比TP:

SP:

综合对比各种并行

几个缩写:params(p)/gradients(g)/optimizer states(os)/activation(a)

并行方法显存效率计算效率限制

DP(数据并行)

p/g/os都复制在每张卡上,显存效率很低

计算和通信可以overlap,如果都在一个minipod内扩展性很好;梯度累积可以提高计算效率

batchsize不能太大,否则模型效果有损;batchsize/dp不能太小,不然打不满tensorcore

ZeRO(解决DP的显存冗余)

zero1/2/3把os/g/p分别shard到每张卡上,显存效率很高

需要做prefetch来减少通信对计算效率的影响

同DP

PP(流水线并行)

切分p,提高显存效率;a需要存多次,降低显存效率

通信次数最少,只发生在多层之间的切分点,但是有Bubble

每个Stage之间需要负载均衡,对模型结构和卡数有限制

TP(张量并行)

p/g/os/a被shard在每张卡上,显存效率也很高;有些层如layernorm是复制的,可以用sequence parallel优化

梯度不需要同步,提高计算效率;每层插入了4次通信,而且是跟计算有依赖的,会降低计算效率;每层的计算量进行了切分,也会降低计算效率

一般是单机内8卡使用nvlink时用TP

把神经网络看成是输入XX和权重WW的矩阵乘法XWXW,那么,DP和PP其实是对XX的拆分,而TP则是对WW的拆分

整体对比可以看

一般这么整合:

  • 把机器分成N组,不同组之间用DP

  • 一组机器有M台机器,不同机器之间用PP

  • 一台机器有K张卡,不同卡之间用TP

编译优化

pytorch的TorchDynamo

https://pytorch.org/docs/stable/torch.compiler_deepdive.html

最简单的用法torch.compile()

flash attention

Flashattention: Fast and memory-efficient exact attention with io-awareness

FlashAttention其实是对softmax(QKT)Vsoftmax(QK^T)V的一种加速实现。

一般的实现:需要先 用矩阵CCQKTQK^T的结果,然后对CC按行做softmax得到新的CC,再用CC乘以VV得到最后结果。

FlashAttention通过一些特殊技巧,不需要算出CC这个临时变量,通过分块计算,让临时变量总是可以放在cache里,从而

  • 减少Global Memory的大小

  • 加速attenttion的计算,因为读cache比访问Global Memory快多了。

训练稳定性

学习率+batchsize的一些经验:

https://zhuanlan.zhihu.com/p/64864995

另外,swiglu会让act_norm变大,得加一些方式让模型能训动,一种方法是把weight_decay调小:

  • loss会变高==>https://poe.com/s/Cv6lODy94INz1ozQKJYJ,正则项变大,L+norm中的L相对影响变小了,所以会变大,即为了防止过拟合,但可能eval的时候会更好

  • act_norm会降低20-30%,因为正则项更重要了,会让权重更接近0

层数加深时的稳定性调优:Transformers Get Stable: An End-to-End Signal Propagation Theory for Language Models

数据/训练策略

综述

A Survey on Data Selection for Language Models

高质量数据

Llama架构比不上GPT2?神奇token提升10倍记忆?

Physics of Language Models: Part 3.3, Knowledge Capacity Scaling Laws

制造人工合成数据,通过控制数据中知识的数量和类型,来严格调控数据中的知识比特数 (bits)。使用不同大小和架构的 LLM 在人工合成数据上进行训练,并给出数学定理,来精确计算训练好的模型从数据中学到了多少比特的知识。有如下几个发现:

  • 如果训练时间充足,不论使用何种模型架构,模型的存储效率均可以达到2bit/param(即平均每个模型参数可以存储2比特的信息)。而且发现transformer中的知识并非主要存储在MLP层,因为即便移除所有MLP层,模型仍能达到 2bit/param 的存储效率。

  • 如果训练时间不充足,GPT2模型能比LlaMA/Mistral存储超过30%的知识,主要是因为GatedMLP(MoE)会导致训练不稳定,因此对同样的知识,需要更长的训练时间

  • 压缩/量化的影响:将训练好的模型从float32/16压缩到int8,对知识的存储毫无影响。LLM可以达到“信息论极限”的1/4——因为int8只有8比特,但平均每个参数可以存储2比特的知识。

  • 高质量数据的影响:如果我们的预训练数据中,有1/8来自高质量知识库(如百度百科),7/8来自低质量数据(如common crawl或论坛对话,甚至是完全随机的垃圾数据),会发现:

    • 即使对高质量数据的训练时间保持一致,低质量数据的存在本身可能会让模型对高质量知识的存储量下降20倍,即便将高质量数据的训练时间延长 3倍,知识储量仍会降低3倍

    • 解法:只需给所有的预训练数据加上自己的网站域名token即可,模型的知识存储量可以立即回升10倍,模型不需要任何先验知识来识别哪些网站上的知识是金子,而可以在预训练过程中,自动发现高质量知识的网站,并自动为这些高质量数据腾出存储空间

DSIR

Data Selection for Language Models via Importance Resampling

https://github.com/p-lambda/dsir

大致思路:

输入语料样本ziz_i

  • 学习语料的特征分布(target data是p^\hat{p},raw data是q^\hat{q}

  • 利用语料样本衡量样本间的重要性权重wi=p^(zi)q^(zi)w_i=\frac{\hat{p}\left(z_i\right)}{\hat{q}\left(z_i\right)}

  • 根据权重进行无放回的采样,兼顾多样性和分布一致性

DoReMi

DoReMi: Optimizing Data Mixtures Speeds Up Language Model Pretraining NeurIPS2023的spotlight

https://github.com/sangmichaelxie/doremi

  • 使用初始的reference domain weights来训练一个小的reference model prefp_{ref},可以用简单的方式合并,例如用样本量加权

  • 用reference mnodel来指导一个小的proxy model的训练,proxy model使用group DRO(group distributionally robust optimization)来得到domain weights,即让最大的loss gap最小化

minθmaxαΔkL(θ,α):=i=1kαi[1xDixxDiθ(x)ref(x)]\min _\theta \max _{\alpha \in \Delta^k} L(\theta, \alpha):=\sum_{i=1}^k \alpha_i \cdot\left[\frac{1}{\sum_{x \in D_i}|x|} \sum_{x \in D_i} \ell_\theta(x)-\ell_{\mathrm{ref}}(x)\right]
  • domain weights: α\alpha

  • proxy model参数:θ\theta

  • domain语料:DD

  • θ(x)=logpθ(x)\ell_\theta(x)=-\log p_\theta(x)

  • 使用tune完的domain weights来训练大模型

  • 可以重复这个过程,用新的domain weights重新训练ref_model,迭代下去

dataset decomposition

Dataset Decomposition: Faster LLM Training with Variable Sequence Length Curriculum

LLM的训练语料大都是相同长度的sequence,一般是多篇文档concat到一起,然后再切分成等长的sequence,有可能一个sequence里有不同的毫不相关的文档,这样算attention就不太适合了。方法

  • 将数据划分为多个桶,每个桶中的序列长度均为2i2^i,保证每个序列仅来自同一个文档

  • 训练时可以给定一个固定的batch_len,即直接从某个桶里采样,也可以用特定长度策略,从多个桶里采样,组合为特定长度

RHO-1

RHO-1: Not All Tokens Are What You Need

https://github.com/microsoft/rho

把语料中的无用token从loss里删了

  • 训练ref_model,挑选少量高质量语料,建模语料的整体loss分布情况

  • 拿ref_model在整个预训练语料上计算每个token的ppl

  • 训练LLM,只关注得分比较高的tokens

infinit lr

Simple and Scalable Strategies to Continually Pre-train Large Language Models

linear warmup and cosine decay schedule:

  • linear warmup阶段:前TwarmupT_{warmup}步线性增加学习率,即直到时间步tann =Twarmup t_{\text {ann }}=T_{\text {warmup }},学习率设置为ηt=ηmaxtTwarmup \eta_t=\eta_{\max } \cdot \frac{t}{T_{\text {warmup }}}

  • annealing阶段:对于接下来的TannT_{ann}个时间步,改为cosine annealing方式,即对于时间步tend=Tann+tannt_{e n d}=T_{a n n}+t_{a n n}

ηt=ηmin+(ηmaxηmin)2(cos(πttanntend tann )+1)\eta_t=\eta_{\min }+\frac{\left(\eta_{\max }-\eta_{\min }\right)}{2} \cdot\left(\cos \left(\pi \cdot \frac{t-t_{a n n}}{t_{\text {end }}-t_{\text {ann }}}\right)+1\right)

infinit lr decay:

  • linear warmup阶段:同上

  • cool down阶段:学习率逐渐decay到一个常量ηconst \eta_{\text {const }}

  • 常数阶段:学习率保持为这个常数,该阶段结束时的ckpt可以用于新数据集的继续pretrain

  • annealing阶段:逐渐减小到最小值

ηt={ηmax tTwarmup t[0,tcd] (warm-up) fcd(t)t(tcd,tconst ] (cooldown) ηconst t(tconst ,tann ] (constant) ηconst (ηminηconst )ttann tend tann t(tann ,tend ] (annealing) \eta_t=\left\{\begin{array}{lll} \eta_{\text {max }} \cdot \frac{t}{T_{\text {warmup }}} & t \in\left[0, t_{c d}\right] & \text { (warm-up) } \\ f_{c d}(t) & t \in\left(t_{c d}, t_{\text {const }}\right] & \text { (cooldown) } \\ \eta_{\text {const }} & t \in\left(t_{\text {const }}, t_{\text {ann }}\right] & \text { (constant) } \\ \eta_{\text {const }} \cdot\left(\frac{\eta_{\min }}{\eta_{\text {const }}}\right)^{\frac{t-t_{\text {ann }}}{t_{\text {end }}-t_{\text {ann }}}} & t \in\left(t_{\text {ann }}, t_{\text {end }}\right] & \text { (annealing) } \end{array}\right.

JEST

DeepMind新方法:训练时间减少13倍,算力降低90%

Data curation via joint example selection further accelerates multimodal learning

现有的大规模预训练数据筛选方法速度慢、成本高,并且没有考虑到批次组成或训练过程中数据相关性的变化,这限制了多模态学习中的效率提升。因此,DeepMind团队研究了联合选择数据批次而非单个样本是否能够加速多模态学习。

  • 挑选好的数据批次比单独挑选数据点更为有效

  • 在线模型近似可用于更高效地过滤数据

  • 可以引导小型高质量数据集以利用更大的非精选数据集

JEST能够在仅使用10%的FLOP预算的情况下超越之前的最先进水平。

硬件的可能影响

https://zhuanlan.zhihu.com/p/701623664?utm_psn=1784500156948938753

大模型训练(如InternLM-7B)实践中,曾经遇到过在A100集群上表现正常的代码和数据,迁移到A800集群却出现了模型准确度下降和梯度范数爆炸的问题。经过调查,我们发现这与A800和A100 GPU的NVLink带宽差异有关。通过在两个集群上使用nanoGPT模型进行的对照实验,我们确认了精度差异的原因在于NCCL的Ring all-reduce算法实现。进一步实验表明,设置环境变量NCCL_ALGO=Tree或使用gloo作为backend可以解决精度对齐问题。最终,我们提出了一个解决方案:在A800集群上设置NCCL_ALGO=Tree,强制使用Tree算法进行all-reduce操作,从而避免了Ring算法带来的精度问题,使得A800集群的模型能够正常收敛,并且与A100集群的训练精度对齐。

fastpersist

DeepSpeed 最新力作:大模型CKPT速度提升116倍

FastPersist: Accelerating Model Checkpointing in Deep Learning

预测框架

量化

ZeroQuant-V2: Exploring Post-training Quantization in LLMs from Comprehensive Study to Low Rank CompensationCompression of generative pre- trained language models via quantization

PPL.LLM

高性能 LLM 推理框架的设计与实现

https://github.com/openppl-public/ppl.llm.serving

vLLM

https://github.com/vllm-project/vllm

Efficient Memory Management for Large Language Model Serving with PagedAttention

并行推理方法

Efficiently scaling transformer inference

3万字详细解析清华大学最新综述工作:大模型高效推理综述

万字综述大模型高效推理:无问芯穹与清华、上交最新联合研究全面解析大模型推理优化

A Survey on Efficient Inference for Large Language Models

LLM后端推理引擎性能大比拼

LayerSkip

LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding

speculative-decoding

Accelerating Large Language Model Decoding with Speculative Sampling

medusa

decoder的并行化: https://zhuanlan.zhihu.com/p/368592551

https://sites.google.com/view/medusa-llm

用了tree-attention

https://github.com/FasterDecoding/Medusa

CLLM

3倍生成速度还降内存成本,超越Medusa2的高效解码框架终于来了

CLLMs:Consistency Large Language Models

fasterTransformer/TensorRTLLM

https://github.com/NVIDIA/FasterTransformer

https://github.com/NVIDIA/TensorRT-LLM/

remove padding的逻辑如下,把整个batch的数据变成一行数据,加上offset标注是哪一条样本的

直接有这么个脚本:

https://github.com/NVIDIA/TensorRT-LLM/blob/main/examples/recurrentgemma/convert_checkpoint.py

https://github.com/daiwk/TensorRT-LLM/blob/main/tensorrt_llm/models/recurrentgemma/model.py

huggingface/text-generation-inference

https://huggingface.co/docs/text-generation-inference/index

https://github.com/huggingface/text-generation-inference/blob/main/server/text_generation_server/models/causal_lm.py

https://github.com/huggingface/text-generation-inference/blob/main/server/text_generation_server/models/seq2seq_lm.py

https://github.com/huggingface/text-generation-inference/blob/main/server/text_generation_server/models/mamba.py

block transformer

KAIST-AI | 提出Block Transformer架构,大幅提升推理速度和内存效率,20倍增益!

Block Transformer: Global-to-Local Language Modeling for Fast Inference

https://github.com/itsnamgyu/block-transformer

MoonCake

月之暗面kimi底层推理系统方案揭秘

Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving

https://github.com/kvcache-ai/Mooncake/tree/main

MInference

MInference 1.0: Accelerating Pre-filling for Long-Context LLMs via Dynamic Sparse Attention

各框架对比

最佳LLM推理引擎?TensorRT vs vLLM vs LMDeploy vs MLC-LLM

典型LLM简介

llm榜单:

https://huggingface.co/spaces/lmsys/chatbot-arena-leaderboard

GPT系列

GPT3

2020年的gpt3:Language models are few-shot learners,175b(1750亿)参数,当参数量到达千亿时出现了『涌现』现象,发现可以in-context learning。

CODEX

Evaluating Large Language Models Trained on Code

能够解析自然语言,并生成代码。CODEX是gpt3在github上收集的代码语料上进行finetune得到的,并且在微软的copilot中使用。

WebGPT

WebGPT: Browser-assisted question-answering with human feedback

https://openai.com/blog/webgpt/

为了回答开放性问题,使用基于文本的浏览器对gpt3进行finetune,包括如下3个步骤:

  • 学习使用人类示范(demonstration)数据来模仿人类的浏览行为

  • 学习一个reward函数来预测人类偏好

  • 用强化学习和拒绝采样来优化reward函数

注:重要性采样和拒绝采样

  • 重要性采样的关键是降低方差:因为相同的样本量,用π(x)\pi(x)分布采样得到的结果方差较大(或者是π(x)\pi(x)不好采样),而用p(x)p(x)采样的样本得到的结果方差较小,用来估计原分布π(x)\pi(x)

  • 拒绝采样:引入易于采样的分布Q(x)Q(x),然后从中随机地筛掉某些样本(根据接受概率接受或者拒绝样本),使得剩下的样本服从分布P(x)P(x)

拒绝采样的步骤:

  • 从辅助分布Q(x)Q(x)中采样得到样本xix_i

  • 计算接受概率A=P(xi)/(M×Q(xi))A = P(x_i) / (M \times Q(x_i)),其中MM是一个常数,满足P(x)M×Q(x)P(x) \leq M \times Q(x)对于所有xx成立

  • 以概率AA接受样本xix_i,即生成一个随机数uu,如果uAu \leq A,则接受样本xix_i;否则拒绝样本xix_i

重复上述步骤,直到获得足够数量的样本。

InstructGPT

Training language models to follow instructions with human feedback

sft+rm+rl,在最小性能降低的情况下,提升了生成结果的真实性,并降低了毒害性

ChatGPT&GPT-4

2022.11.30推出了ChatGPT,基于GPT3.5,即InstructGPT的兄弟

2023.3推出了GPT-4,多模态LLM,能输入图像和文本

LLaMA系列

LLaMA

2023年2月发布,LLaMA: Open and Efficient Foundation Language Models,开源的LLaMA-13B比 GPT3 175B在很多任务上都更好

参考代码: https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py

https://github.com/meta-llama/llama

之前的工作考虑的是在训练预算有限的前提下,如何提升模型性能(2022年deepmind的Training Compute-Optimal Large Language Models的Chinchilla),llama考虑在预测时的预算。例如chinchilla是一个10b的模型在200b的token上训练,但其实一个7b的模型当用了1T的token后,性能仍在提升。LLama-13b比gpt3在大多数benchmark上好,但size只有1/10,在一个GPU上就能跑。

llama只用公开数据训练,而Chinchilla、PaLM、GPT-3都有自己的未公开数据集。其他的OPT、GPT-NeoX、BLOOM、GLM虽然也只用公开数据集,但打不过PaLM-62B或者Chinchilla

预训练数据

  • English CommonCrawl(67%):使用CCNet pipeline,去重、用fasttext把非英文的页面删了,用n-gram把低质内容删了。此外,还训了一个线性模型,对页面进行分类:作为维基百科的引用 vs 随机采样的页面,最后把不属于引用这个类别的页面删了

  • C4(15%):与CCNet类似,主要区别在质量过滤是基于启发式的规则,如标点符号的存在,或者词数和句子数

  • github(4.5%):使用Google BigQuery里的公开github数据集,只用Apache、BSD和MIT证书的。低质判断是启发式规则,如字母数字占比、行的长度等,用正则删掉head等样式,最终以文件粒度进行去重。

  • wikipedia(4.5%):2022年6-8月的数据,包括20种语言

  • Gutenberg and Books3(4.5%):两个书籍数据集,对有90%以上内容重复的书籍做去重。

  • Arxiv(2.5%):拿原始的tex文件,删掉first section之前的东西,还有一些注释、宏

  • Stack Exchange(2%):高质量的问答网站,按答案的分数排序

tokenizer:BPE,使用sentencepiece的实现。将所有numbers切成单个数字,回退到字节去处理未知的utf8字符(fallback to bytes to decompose unknown UTF-8 characters)

总共有1.4T的token,对大部分训练数据,每个token在训练时只用了一次,除了维基和book大概用了两次。

附:gpt4说:当我们说"一个token只训练一次",我们其实是在说在一个epoch(一个完整遍历训练集的过程)中,我们只遍历一次完整的数据集。如果一个特定的token在数据集中出现多次,那么在一个epoch中,这个token就会被用来训练模型多次。

网络结构

说白了就是输入xx,SwiGLU激活完是swish(w1(x))w3(x)swish(w_1(x)) * w_3(x),其中swish又叫silu,是f(x)=xsigmoid(x)f(x)=x \cdot sigmoid(x)

然后再过一个w2w_2,得到w2(swish(w1(x))w3(x))w_2(swish(w_1(x)) * w_3(x))就是最终的ffn输出

以下是transformers里的实现:https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py

class LlamaMLP(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.hidden_size = config.hidden_size
        self.intermediate_size = config.intermediate_size
        self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
        self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
        self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
        self.act_fn = ACT2FN[config.hidden_act] ## 默认是silu,即swish

    def forward(self, x):
        if self.config.pretraining_tp > 1:
            slice = self.intermediate_size // self.config.pretraining_tp
            gate_proj_slices = self.gate_proj.weight.split(slice, dim=0)
            up_proj_slices = self.up_proj.weight.split(slice, dim=0)
            down_proj_slices = self.down_proj.weight.split(slice, dim=1)

            gate_proj = torch.cat(
                [F.linear(x, gate_proj_slices[i]) 
                    for i in range(self.config.pretraining_tp)], dim=-1
            )
            up_proj = torch.cat([F.linear(x, up_proj_slices[i]) 
                for i in range(self.config.pretraining_tp)], dim=-1)

            intermediate_states = (self.act_fn(gate_proj) * up_proj).split(slice, dim=2)
            down_proj = [
                F.linear(intermediate_states[i], down_proj_slices[i]) 
                    for i in range(self.config.pretraining_tp)
            ]
            down_proj = sum(down_proj)
        else:
            down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))

        return down_proj

这个是llama官方代码的实现:https://github.com/meta-llama/llama/blob/ef351e9cd9496c579bf9f2bb036ef11bdc5ca3d2/llama/model.py#L337-L345

class FeedForward(nn.Module):
    def __init__(
        self,
        dim: int,
        hidden_dim: int,
        multiple_of: int,
        ffn_dim_multiplier: Optional[float],
    ):
        """
        Initialize the FeedForward module.

        Args:
            dim (int): Input dimension.
            hidden_dim (int): Hidden dimension of the feedforward layer.
            multiple_of (int): Value to ensure hidden dimension is 
                a multiple of this value.
            ffn_dim_multiplier (float, optional): 
                Custom multiplier for hidden dimension. Defaults to None.

        Attributes:
            w1 (ColumnParallelLinear): Linear transformation for the first layer.
            w2 (RowParallelLinear): Linear transformation for the second layer.
            w3 (ColumnParallelLinear): Linear transformation for the third layer.

        """
        super().__init__()
        hidden_dim = int(2 * hidden_dim / 3)
        # custom dim factor multiplier
        if ffn_dim_multiplier is not None:
            hidden_dim = int(ffn_dim_multiplier * hidden_dim)
        hidden_dim = multiple_of * ((hidden_dim + multiple_of - 1) // multiple_of)

        self.w1 = ColumnParallelLinear(
            dim, hidden_dim, bias=False, gather_output=False, init_method=lambda x: x
        )
        self.w2 = RowParallelLinear(
            hidden_dim, dim, bias=False, input_is_parallel=True, init_method=lambda x: x
        )
        self.w3 = ColumnParallelLinear(
            dim, hidden_dim, bias=False, gather_output=False, init_method=lambda x: x
        )

    def forward(self, x):
        return self.w2(F.silu(self.w1(x)) * self.w3(x))
  • Rotary embeddings(GPTNeo):删掉原来的绝对位置编码,加上rotary positional embedding(RoPE),网络的每一层都加,参考Roformer: Enhanced transformer with rotary position embedding

  • pre-normalization(gpt3):提升训练稳定性,对每个子层的输入做norm,而非输出。此外,使用的是RMSNorm函数(Root mean square layer normalization)取代标准的layer-norm

    • layernorm计算单个样本在单层中所有激活的均值和标准差,并使用这些统计数据来归一化该层的激活。

    • RMSnorm只计算激活的平方根均值(RMS),而不是标准差。这样做的一个好处是计算上更简单,因为它省去了计算均值的步骤,只关注激活的规模(scale)而非其准确的分布。RMSNorm(xi)=xi1Hj=1Hxj2+ϵ\operatorname{RMSNorm}\left(x_i\right)=\frac{x_i}{\sqrt{\frac{1}{H} \sum_{j=1}^H x_j^2}+\epsilon},其中HH是该层的神经元个数,而且也不用求均值

class RMSNorm(torch.nn.Module):
    def __init__(self, dim: int, eps: float = 1e-6):
        """
        Initialize the RMSNorm normalization layer.

        Args:
            dim (int): The dimension of the input tensor.
            eps (float, optional): A small value added to the denominator 
                for numerical stability. Default is 1e-6.

        Attributes:
            eps (float): A small value added to the denominator 
                for numerical stability.
            weight (nn.Parameter): Learnable scaling parameter.

        """
        super().__init__()
        self.eps = eps
        self.weight = nn.Parameter(torch.ones(dim))

    def _norm(self, x):
        """
        Apply the RMSNorm normalization to the input tensor.

        Args:
            x (torch.Tensor): The input tensor.

        Returns:
            torch.Tensor: The normalized tensor.

        """
        # rsqrt(x)= 1/ sqrt(x)
        return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)

    def forward(self, x):
        """
        Forward pass through the RMSNorm layer.

        Args:
            x (torch.Tensor): The input tensor.

        Returns:
            torch.Tensor: The output tensor after applying RMSNorm.

        """
        output = self._norm(x.float()).type_as(x)
        return output * self.weight

优化器:AdamW,cosine学习率schedule,最终学习率是最大学习率的10%。0.1的weight decay和1.0的gradient cliping,使用2000steps的warmup

训练加速

LLaMA2

2023年7月,Llama 2: Open Foundation and Fine-Tuned Chat Models

  • 基于公开数据集预自监督地训练一个llama-2

  • llama-2-chat模型:

    • sft后得到初始版本

    • 使用RLHF迭代地更新(拒绝采样+ppo)

https://zhuanlan.zhihu.com/p/636784644

使用了GQA(grouped query attention)(参考Gqa: Training generalized multi-query transformer models from multi-head checkpoints),在注意力机制中对K/V进行参数共享的方案,可以在推理过程中减小KV缓存

LLaMA3

原始LLaMa3

2024年4月

开源大模型Llama 3王者归来!最大底牌4000亿参数,性能直逼GPT-4

Llama 3超大杯有何惊喜?Meta会一直开源吗?当初为何笃信元宇宙?扎克伯格新访谈回应一切

Llama 3细节公布!AI产品总监站台讲解:Llama系列超庞大生态系统

OpenAI 前创始成员、特斯拉自动驾驶前负责人 Andrej Karpathy 发表 Meta Llama 3 笔记

Karpathy称赞,从零实现LLaMa3项目爆火,半天1.5k star

Karpathy点赞,这份报告教你如何用 LLaMa 3创建高质量网络数据集

https://github.com/naklecha/llama3-from-scratch

三个版本:8B 和 70B 参数的模型,还有一个 405B 参数的密集模型(还在训练之中,但已经在逼近GPT-4的领域,例如84.8 MMLU vs. 86.5 4Turbo),8B版本基本上与Llama-2的最大版本一样强大。

Llama 3的主要亮点:

  • 训练语料:基于超过15T token训练,比Llama 2数据集(2T)的7倍还多:

    • scaling law的新发现:对于一个8B模型,Chinchilla的计算最优点将是训练约200B词汇(前面提到了10B模型,大概要205B的token来训练,以此类推),所以这里超出了75倍,而且还未收敛。可见,我们经常使用的LLMs在训练上显著不足,可能是100-1000倍或更多,远未达到它们的收敛点。

  • tokenizer:词汇数量从Llama 2的32K增加到Llama 3的128K,增加了4倍,拥有更多的词汇可以在长度上更有效地压缩序列

  • 上下文窗口:从Llama 2的4096和Llama 1的2048增加到了8192,相比GPT4的128k还差得很远

  • 训练效率:比 Llama 2 高 3 倍,做了很多工程优化;

  • 模型结构:在Llama 2中,只在更大的模型使用了分组查询注意力(GQA),但llama3的所有模型都使用了,包括最小的8B模型。

  • 新能力范畴:Llama-2 只能使用非常特定的工具,而 Llama-3 能使用好得多的工具,无需人工编程就能让其使用谷歌执行搜索,类似的功能还有编程和运行代码等。

https://github.com/meta-llama/

https://github.com/meta-llama/llama3

多模态llama3

多模态 Llama-3 它来了 !![全网首发微调教程]

https://github.com/InternLM/XTuner

中文llama3

首批中文版Llama3模型来了,解释成语、答弱智吧问题

https://github.com/CrazyBoyM/llama3-Chinese-chat

https://huggingface.co/shenzhi-wang/Llama3-8B-Chinese-Chat

LLama3.1

最强模型Llama 3.1 405B正式发布,扎克伯格:开源引领新时代

The Llama 3 Herd of Models

使用超过15万亿(15T)个token训练Llama 3.1 405B,优化了训练栈,在超过16,000个H100上训练

  • 选择了decoder only transformer with minor adaptations,而不是MOE,以最大限度地提高训练稳定性

    • 使用GQA with 8 key-value heads,提升推理速度,在decoding时降低k-v cache的大小

    • 使用attention mask,让同一序列里的不同documents不计算self-attention。在标准的pretraining中影响不大,但对于超长序列的continued pre-training非常重要

    • 128K tokens的vocab,100k的tiktoken tokenizer+28k的额外token,更好地支持非英语的语言。相比llama2,每个token能压缩的字符3.17变成3.94,压缩率更高了,即同样计算量能读更多文本,同时也能提升下游任务效果。

    • 把RoPE的base frequency超参加大到500,000,能更好地支持更长contextsEffective Long-Context Scaling of Foundation Models说这个值对32768长度的context很有效。

  • 采用iterative post-training procedure,即预训练后进行多轮对齐,每轮都使用sft、RS(拒绝采样)、直接偏好优化(DPO, Direct Preference Optimization),能够为每轮创建最高质量的合成数据,并提高每项能力(capability)的性能。

    • 使用合成数据生成(synthetic data generation)来产生绝大多数SFT示例,并多次迭代以在所有能力生成越来越高质量的合成数据。

    • 采用了多种数据处理技术来过滤这些合成数据,达到最高质量,并可以跨能力扩展微调数据量

推理:从bf16量化为fp8

参数量:

8B70B405B

Layers

32

80

126

Model Dimension

4,096

8192

16,384

FFN Dimension

6,144

12,288

20,480

Attention Heads

32

64

128

Key/Value Heads

8

8

8

Peak Learning Rate

3e-4

1.5e-4

8e-5

Activation Function

SwiGLU

SwiGLU

SwiGLU

Vocabulary Size

128,000

128,000

128,000

Positional Embeddings

RoPE (θ\theta = 500,000)

RoPE (θ\theta = 500,000)

RoPE (θ\theta = 500,000)

还开放了一个生态系统:

Alpaca

Alpaca: A Strong, Replicable Instruction-Following Model

Stanford的羊驼(Alpaca)模型,有70亿(7b)参数,没有使用RLHF,而是使用监督学习的方法,参考Self-Instruct: Aligning Language Model with Self Generated Instructions(代码https://github.com/yizhongw/self-instruct

数据集是通过查询基于GPT-3的text-davinci-003模型的结果,得到的52k的指令-输出对(instruction-output pairs)。

因此,Alpaca本质上使用的是一种弱监督(weakly supervised)或以知识蒸馏(knowledge-distillation-flavored)为主的微调,即“用 LLM 来训练 LLM”。

https://github.com/tatsu-lab/stanford_alpaca

Vicuna

通过ShareGPT收集的用户对话数据,对llama进行finetune得到的13B模型。效果接近chatgpt的92%,而且训练消耗比较低,大概只要300美元。

Guanaco

QLoRA: Efficient Finetuning of Quantized LLMs也是对llama进行微调,使用了QLoRA,能够在一台48G的GPU上微调65B的模型。只需要在单台GPU上finetune 24小时就能达到99.3%的chatgpt的效果。

https://github.com/artidoro/qlora

https://github.com/TimDettmers/bitsandbytes

QLoRA将一个固定的4 bit量化的预训练权重转成low Rank Adapters来更新梯度

Koala

Koala: A dialogue model for academic research

使用用户与闭源大模型交互的用户输入和模型返回数据进行训练

Mistral

Mistral 7b

7B参数比最好的13B模型(llama-2-13B)要更好,而且比llama-34B在reasoning、数学、代码生成都更好。

  • 使用grouped-query attention来做更快的infer

  • 使用滑动窗口attention来用更低的infer消耗来高效地处理任意长度的序列

https://mistral.ai/news/mixtral-of-experts/ 提出了moe的8x7b

Mixtral of Experts

Mixtral 8x7B(Mistral MoE) 模型解析

Mistral开源8X22B大模型,OpenAI更新GPT-4 Turbo视觉,都在欺负谷歌

https://huggingface.co/mistral-community/Mixtral-8x22B-v0.1

Mistral AI两连发:7B数学推理专用、Mamba2架构代码大模型

mathtral:https://huggingface.co/mistralai/mathstral-7B-v0.1

codestral-mamba: https://huggingface.co/mistralai/mamba-codestral-7B-v0.1,基于mamba2,可以直接用trt-llm启动

phi-3

微软发布Phi-3,性能超Llama-3,可手机端运行

Phi-3 Technical Report: A Highly Capable Language Model Locally on Your Phone

PaLM系列

PaLM

2022年4月提出了第一个PaLM:Palm: Scaling language modeling with pathways,直到2023年3月还是private的。是一个540B(5400亿)参数的模型,在包含了780B的tokens的高质量数据集上预训练。使用Pathways的6144块TPU v4进行训练。

U-PaLM

Transcending scaling laws with 0.1% extra compute提出了8B,62B和540B的U-PaLM模型,用UL2R来对PaLM进行继续训练,用的是UL2的mixture-of-denoiser objective(UL2: Unifying Language Learning Paradigms)

Flan-PaLM

Flan-PaLM(Scaling instruction-finetuned language models)是instrunction-finetuned版本的U-PaLM。使用了更多的任务、更大的模型,以及CoT数据。使用了473个数据集,146类的task,总共1836个task。

https://huggingface.co/google/flan-t5-xl

PaLM-2

PaLM 2 Technical Report是一个更计算高效型的LLM,有更好的多语种和reasoning能力,在很多任务上都比PaLM好,并且在infer上比PaLM要更快更高效。

Med-PaLM

Nature的Large language models encode clinical knowledge提出了Med-PaLM,在PaLM上用parameter-efficient方法进行instruction prompt tuning,使用少量的典型范例(exemplars)让LLM对齐到新领域。

Med-PaLM2(Towards expert- level medical question answering with large language models)通过med-domain的finetuning和ensemble refinement prompting,效果比Med-PaLM要好。

其他LLM

FLAN

Finetuned language models are zero-shot learners

通过instruction tuning,大模型能很好地提升在没见过任务上的zero-shot能力。对一个137B的预训练模型在60个NLP数据集上使用instruction template进行instruction tuning。

一些instruction template:

https://github.com/google-research/flan

Gopher

Scaling language models: Methods, analysis & insights from training gopher基于152个多样的任务,对比了从44M到208B(Gopher)的不同transformer,发现Gopher在大多数任务上均达到sota:

ModelLayersNumber HeadsKey/Value Sized_modelMax LRBatch Size

44M

8

16

32

512

6×1046 \times 10^{-4}

0.25M

117M

12

12

64

768

6×1046 \times 10^{-4}

0.25M

417M

12

12

128

1,536

2×1042 \times 10^{-4}

0.25M

1.4B

24

16

128

2,048

2×1042 \times 10^{-4}

0.25M

7.1B

32

32

128

4,096

1.2×1041.2 \times 10^{-4}

2M

Gopher 280B

80

128

128

16,384

4×1054 \times 10^{-5}

3M -> 6M

T0

Multitask Prompted Training Enables Zero-Shot Task Generalization设计了一个系统,将任意nlp任务映射成一个人类可读的prompt格式。训练了一个encoder-decoder的T0模型,输入文本,输出文本,在混合数据集上进行多任务学习。

ERNIE 3.0

ERNIE 3.0: Large-scale Knowledge Enhanced Pre-training for Language Understanding and Generation结合自回归网络和autoencoding网络,让模型能够同时做语言理解和语言生成任务,可以支持zero-shot、few-shot和finetuning。有10B参数,在4TB的文本和图谱数据上训练。

RETRO

参数量仅为4%,性能媲美GPT-3:开发者图解DeepMind的RETRO

http://jalammar.github.io/illustrated-retrieval-transformer/

Improving language models by retrieving from trillions of tokens

Retrieval Enhanced Transformer(Retro)基于与preceding(前述) tokens的相似度,从大的语料库里检索出文档段(document chunks)作为条件,增强了自回归模型的能力。通过少25%的参数,在Pile数据集上达到了与gpt3和Jurassic-1相当的效果

  • 左图:

    • 输入一个长度为12的序列,每4个token一个chunk,切成3个chunk

    • 每个chunk通过freezed的bert去语料库中拿2个相似neighbors出来,每个neighbor过bert得到向量

    • 邻居作为k和v,原来的3个chunk作为k,做attention(CCA, chunked cross attention)

  • 右图:CCA的结构

    • 保证了因果性,即chunk1的邻居只对chunk1的last token以及chunk2的所有token有影响

GLaM

Glam: Efficient scaling of language models with mixture-of-experts提出了Generalist Language Model(GLaM),用稀疏激活的MOE架构,同时能scale模型容量,也能相比dense更可观地降低训练成本。最大的模型有1.2T参数,是gpt3的7倍。但只需要GPT3的1/3的能量来训练,而且在infer时也只有一半的flops,且在29个NLP任务上都有更好的0/1/few shot效果。

如图,2 in 64的结构,每个token只会取64个experts里的top 2相关的expert,对这两个的输出加权平均输入给后面的层

LaMDA

Lamda: Language models for dialog applications,有137B的参数,在1.5T的公开对话数据和互联网文本上pretrain,用标注数据微调,以及让模型能够咨询(consult)外部知识源能够让模型在安全性和factual grounding上有很好的改进。

OPT

Chinchilla

Galactica

CodeGen

AlexaTM

Sparrow

MoD

BLOOM

GLM

ACL22 GLM: General Language Model Pretraining with Autoregressive Blank Infilling

iclr23 GLM-130B: An Open Bilingual Pre-trained Model

GLM-4

GLM-4开源版本终于来了:超越Llama3,多模态比肩GPT4V,MaaS平台也大升级

https://github.com/THUDM/GLM-4

Pythia

Orca

StarCoder

KOSMOS

Gemini

Gemini 1.0

Gemini: a family of highly capable multimodal models

Gemini 1.5

谷歌Gemini 1.5深夜爆炸上线,史诗级多模态硬刚GPT-5!最强MoE首破100万极限上下文纪录

Gemini 1.5: Unlocking multimodal understanding across millions of tokens of context

  • 更新的 Gemini 1.5 Pro,其大部分功能和基准都超过了 2 月份的版本

  • Gemini 1.5 Flash,一种更轻量级的变体,专为提高效率而设计,并且在性能方面的减益很小。

更大的上下文窗口

此前的SOTA模型能处理**20万(200K)的token,Gemini 1.5能稳定处理100万(1M)的token(极限为1000万(10M)**的token),能够处理11小时的音频、1小时的视频、超过3w行的代码库、超过70w个单词

gemma

https://blog.google/technology/developers/gemma-open-models/

Gemma: Open Models Based on Gemini Research and Technology

代码:

https://github.com/huggingface/transformers/blob/main/src/transformers/models/gemma/modeling_gemma.py

架构&训练方法

  • moe: +

codegemma

  • 专门处理代码补全和代码生成任务的 7B 预训练变体

  • 用于代码聊天和指令跟随的 7B 指令调优变体

  • 在本地计算机上运行快速代码补全的 2B 预训练变体

CodeGemma: Open Code Models Based on Gemma

RecurrentGemma

RecurrentGemma: Moving Past Transformers for Efficient Open Language Models

在infer阶段,需要检索KV cache,并加载到内存中,而KV cache会随着序列长度线性增长。Longformer: The Long-Document Transformer通过local attention来降低cache大小,但模型效果会变差。recurrent gemma将输入序列压缩到一个固定大小的state中,从而不会降低效果,对长序列能降低内存占用并高效infer。

基于Griffin架构,将门控线性递归本地滑动窗口注意力混合在一起,在生成长序列时实现快速推理,相比gemma:

  • 减少内存用量:内存要求越低,就越能在内存有限的设备(例如单个 GPU 或 CPU)上生成较长的样本。

  • 吞吐量较高:能够以明显较高的batch_size执行推理,这意味着每秒可以生成更多tokens,尤其是在生成长序列时。

相比原始griffin:

  • 对输入emb乘以一个常数(等于model width(下表中的2560)的平方根,如下代码所示)。输入和输出的emb是tied的,这个常数没有乘到output上去。gemma里也有一个类似的因子

  • recurrent layers(RG-LRU)在训练时并没有进行weight decay(本质是L2正则化,参考https://zhuanlan.zhihu.com/p/607909453),当bp到开方操作时,为了训练稳定会加最大值为1000的梯度clip

def __init__(self, ...):
    #...
    self.register_buffer(
        "normalizer", torch.tensor(self.config.hidden_size**0.5, 
            dtype=torch.bfloat16), persistent=False
    )
def forward(self, ...):
    #...
    if inputs_embeds is None:
        inputs_embeds = self.embed_tokens(input_ids)

    hidden_states = inputs_embeds

    if use_cache and inputs_embeds.shape[1] != 1:  
        # TODO let's maybe only call in the `generate`?
        self._setup_cache(self.config, hidden_states.shape[0], 
        hidden_states.device, hidden_states.dtype)

    if cache_position is None:
        cache_position = torch.arange(hidden_states.shape[1], 
        device=hidden_states.device)
    if position_ids is None:
        position_ids = cache_position.unsqueeze(0)

    causal_mask = self._update_causal_mask(attention_mask, 
        inputs_embeds, cache_position)

    ## 这里就是那个因子
    hidden_states = hidden_states * self.normalizer.type(hidden_states.dtype)

具体参数:

变量大小

总参数量

2.7b

非emb参数量

2.0b

emb参数量

0.7b

vocab size

256k

model width

2560

rnn width

2560

MLP expansion factor

3,即intermediate_size=2560*3=7680

Depth

26

Attention heads

10

local attention window size

2048

训练:

https://github.com/huggingface/transformers/blob/main/src/transformers/models/recurrent_gemma/modeling_recurrent_gemma.py

在线推理的C++实现(cpu版本)

https://github.com/google/gemma.cpp

gemma-2

单张A100全精度推理!谷歌明星开源模型Gemma 2上新9B/27B,挑战3140亿Grok-1

谷歌「诚意之作」,开源9B、27B版Gemma2,主打高效、经济!

https://huggingface.co/collections/google/gemma-2-release-667d6600fd5220e7b967f315

https://blog.google/technology/developers/google-gemma-2/

Gemma 2: Improving Open Language Models at a Practical Size

用了RoPE和GeGLU,网络结构上:

  • 局部滑动窗口全局注意力:在每隔一层中交替使用局部滑动窗口注意力(Longformer: The long-document transformer)和全局注意力(Effective Approaches to Attention-based Neural Machine Translation),局部注意力层的滑动窗口大小设置为4096个token,而全局注意力层的跨度设置为8192个token。

  • Logit软封顶:根据Gemini 1.5的方法,研究团队在每个注意力层和最终层限制logit,使得logit的值保持在soft_cap,+soft_cap−soft\_cap,+soft\_cap之间。对于9B和27B模型,注意力对数封顶设置为50.0,最终对数封顶设置为30.0。截至本文发表时,注意力logit软封顶与常见的FlashAttention实现不兼容,因此他们已从使用FlashAttention的库中移除了此功能。对模型生成进行了有无注意力logit软封顶的消融实验,发现大多数预训练和后期评估中,生成质量几乎不受影响。本文中的所有评估均使用包含注意力logit软封顶的完整模型架构。然而,某些下游性能可能仍会受到此移除的轻微影响。

 logits  soft_cap  tanh(logits / soft_cap) \text { logits } \leftarrow \text { soft\_cap } * \text { tanh(logits } / \text { soft\_cap) }
  • RMSNorm进行post-norm和pre-norm。为了稳定训练,用RMSNorm对每个变换子层、注意力层和前馈层的输入和输出进行归一化。

  • gqa:27B和9B模型均使用GQA,num_groups = 2,基于消融实验表明在保持下游性能的同时提高了推理速度。

https://github.com/huggingface/transformers/blob/v4.42.3/src/transformers/models/gemma2/modeling_gemma2.py

Claude

全球最强大模型一夜易主,GPT-4时代终结!Claude 3提前狙击GPT-5,3秒读懂万字论文理解力接近人类

The Claude 3 Model Family: Opus, Sonnet, Haiku

力压GPT-4o!新王Claude 3.5 Sonnet来了,直接免费可用

grok

马斯克开源Grok-1:3140亿参数迄今最大,权重架构全开放,磁力下载

https://github.com/xai-org/grok-1

马斯克发布Grok 1.5! 编码和数学能力大幅提升

  • 上下文窗口提升16倍,达到128k

  • 不使用通用的Python语言+Pytorch框架,采用分布式训练架构,使用Rust、JAX+Kubernetes构建。

  • 提出了自定义训练协调器,可自动检测到有问题的节点,然后剔除。

  • 优化了checkpointing、数据加载和训练重启等流程,最大限度地减少故障停机时间。

马斯克的首款多模态大模型来了,GPT-4V又被超越了一次

Grok-1.5V: https://x.ai/blog/grok-1.5v

Gecko

谷歌DeepMind发布Gecko:专攻检索,与大7倍模型相抗衡

Gecko: Versatile Text Embeddings Distilled from Large Language Models

Octopus

超越GPT-4,斯坦福团队手机可跑的大模型火了,一夜下载量超2k

Octopus v2: On-device language model for super agent

https://huggingface.co/NexaAIDev/Octopus-v2

参数量不到10亿的OctopusV3,如何媲美GPT-4V和GPT-4?

Octopus v3: Technical Report for On-device Sub-billion Multimodal AI Agent

Octopus v4: Graph of language models

Cohere Command R+

开源模型打败GPT-4!LLM竞技场最新战报,Cohere Command R+上线

https://huggingface.co/CohereForAI/c4ai-command-r-plus

https://huggingface.co/CohereForAI/c4ai-command-r-plus-4bit

1040亿的参数量,相比于Grok-1(3140亿)还差了一些,但Command R+并非Grok那种MoE架构,所以这1040亿参数是实打实的完全用于推理,而Grok-1的活跃参数为860亿。相比commend R:

  • 高级检索增强生成(RAG)与引用以减少幻觉

  • 10种主要语言的多语言覆盖,支持全球业务运营

  • 工具的运用以自动化复杂的业务流程

CT-LLM:以中文为中心的LLM

Chinese Tiny LLM: Pretraining a Chinese-Centric Large Language Model

当前,绝大多数LLM基本上都是以英文语料库训练得到的,然后经过SFT来匹配不同的语种。本文作者考虑以中文为基础的预训练模型是否可以激活对其它语言的能力。

作者从头开始训练中文大模型,在训练过程中「主要纳入中文文本数据」,最终作者得到了一个2B规模的中文Tiny LLM(CT-LLM)。结果表明,该模型在中文任务上表现出色,且通过SFT也能很好的支持英文。

OpenELM

苹果卷开源大模型,公开代码、权重、数据集、训练全过程,OpenELM亮相

OpenELM: An Efficient Language Model Family with Open-source Training and Inference Framework

https://github.com/apple/corenet

超强Siri即将到来!苹果10篇重磅AI研究全总结,iOS 18关键一瞥

苹果智能背后模型公布:3B模型优于Gemma-7B,服务器模型媲美GPT-3.5-Turbo

Arctic

仅需Llama3 1/17的训练成本,Snowflake开源128x3B MoE模型

全球最大开源模型再刷爆纪录!4800亿参数MoE击败Llama 3、Mixtral

https://huggingface.co/Snowflake/snowflake-arctic-instruct

Qwen

Qwen1.5-110B:首个国产千亿参数开源大模型

4月26日,Qwen开源了其第一个千亿参数大模型Qwen1.5-110B,这应该也是国内第一个千亿规模的开源大模型。其包含1100亿参数,更重要的是这是一个Dense模型,而非MoE模型。从各项评测来看,Qwen1.5-110B足以与Llama3-70B相抗衡,部分指标也取得了更高的水平。

deepseek

一块钱100万token,超强MoE模型开源,性能直逼GPT-4-Turbo

https://github.com/deepseek-ai/DeepSeek-V2

DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model

从MHA到MLA看Attention优化:谈谈DeepSeek拼多多级的推理价格

缓存与效果的极限拉扯:从MHA、MQA、GQA到MLA

FALCON 2

时隔一年Falcon回归!110亿参数5.5万亿token,性能超越Llama 3

MiniCPM

登顶Top2!MiniCPM-V 8B新版本:GPT-4V水准小钢炮,8G显存,4070轻松推理!

可信度超越GPT-4V,清华&面壁揭秘「小钢炮」模型背后的高效对齐技术

RLAIF-V: Aligning MLLMs through Open-Source AI Feedback for Super GPT-4V Trustworthiness

https://github.com/RLHF-V/RLAIF-V

DCFormer

彩云科技DCFormer大模型发布,效率是Transformer的两倍!

Improving Transformers with Dynamically Composable Multi-Head Attention

https://github.com/Caiyun-AI/DCFormer

小模型

权重、代码、数据集全开源,性能超越Mistral-7B,苹果小模型来了

DataComp-LM: In search of the next generation of training sets for language models

https://huggingface.co/apple/DCLM-7B

小模型卷起来了:Mistral联合英伟达开源12B小模型,128k上下文

Mistral NeMo 使用基于 Tiktoken 的新分词器 Tekken,该分词器经过 100 多种语言的训练,能比以前 Mistral 模型中使用的 SentencePiece 分词器更有效地压缩自然语言文本和源代码。在压缩源代码、中文、意大利文、法文、德文、西班牙文和俄文时,它的效率要高出约 30%。在压缩韩文和阿拉伯文时,它的效率是原来的 2 倍和 3 倍。事实证明,与 Llama 3 分词器相比,Tekken 在压缩所有语言中约 85% 的文本方面更胜一筹。

Mistral NeMO 经历了高级微调和对齐阶段。与 Mistral 7B 相比,它在遵循精确指令、推理、处理多轮对话和生成代码方面的能力大大提升。

小结

开源模型进展盘点:最新Mixtral、Llama 3、Phi-3、OpenELM到底有多好?

微调

  • 指令微调(instruct tuning):增强/解锁LLM的能力,

  • 对齐微调(alignment tuning):将LLM的行为与为类的价值观或偏好对齐。

  • 高效微调方法:用于模型快速适配

指令微调

  • 收集或构建指令格式(instruction-formatted)的实例

  • 使用这些示例进行有监督微调

详见综述Is prompt all you need? no. A comprehensive and broader view of instruction learning

数据集:https://huggingface.co/collections/davanstrien/top-10-instruction-tuning-datasets-650d91e11427d12e8542a21a

构建格式化实例

指令格式的实例包括一个任务描述(即指令)、一对输入输出和少量示例(可选)

格式化已有数据集

  • 收集来自不同领域(文本摘要、文本分类、翻译等)的实例来创建有监督的多任务训练数据集。用自然语言的任务描述来格式化这些数据集是很方便的。

  • 使用人类撰写的任务描述来增广带标的数据集,通过解释任务目标来指导LLM理解任务。

  • 众包平台(如PromptSource)有效地创建、共享和难不同数据集的任务描述

  • 通过指令微调特殊设计的任务描述,反转已有实例的输入-输出对,例如“请基于以下答案生成一个问题”,如

  • 利用启发式任务模板将大量无标注的文本转换为带标注的实例。如Learning instructions with unlabeled data for zero-shot cross-task generalization

格式化人类需求

来自公共NLP数据集的训练实例虽然进行了格式化,但任务描述缺乏多样性与人类真实需求不匹配,故InstructGPT采用真实用户提交给其API的查询作为任务描述。此外,为了丰富任务多样性,通常

  • 标注者为真实生活中的任务编写指令,如开放式生成、开放式问答、头脑风暴、聊天等

  • 另一组标注人员直接对这些指令进行回答

  • 将**指令(采集的用户查询)期望输出(人工编写的答案)**pair对作为一个训练实例

还有一些半自动化的方法将现有实例输入到LLM中生成多样的任务描述和实例来构建实例,如

构建实例的关键

指令微调策略

相比预训练而言,指令微调有多个不同:

指令微调效果

性能改进

任务泛化性

对齐微调

Training language models to follow instructions with human feedbackAlignment of language agents提出,LLM可能编造虚假信息、产生有害的、误导性的和有偏见的表达,因为LLM在预训练时没有考虑人类的价值观或偏好。

Improving alignment of dialogue agents via targeted human judgementsTraining language models to follow instructions with human feedback提出了人类对齐,使LLM的行为能够符合人类期望。

Training language models to follow instructions with human feedbackA general language assistant as a laboratory for alignmentTraining a Helpful and Harmless Assistant with Reinforcement Learning from Human Feedback发现,和适配微调(如指令微调)相比,对齐微调要考虑的标准并不同,这可能会在某种程度上损害LLM的通用能力,即对齐税

对齐的标准

  • 有用性:以简洁高效的方式帮助用户解决任务或回答问题。需要进一步阐明问题时,应该有通过提出恰当的问题获取额外信息的能力,并有合适的敏感度、洞察力和审慎度(from A general language assistant as a laboratory for alignment)。

  • 诚实性:又称为正确性,提供准确内容,传达适当的不确定性很重要,避免任何形式的欺骗或信息误传。LLM了解其能力和知识水平(知道自己不知道什么)。A general language assistant as a laboratory for alignment)认为,与有用性和无害性相比,诚实性是一个更客观的标准,故诚实性对齐依赖的人力可能更少

  • 无害性:生成的语言不得是冒犯性或者歧视性的,能检测隐蔽的出于恶意目的的请求。当被诱导去执行危险行为(如犯罪)时,应该礼貌拒绝Training a Helpful and Harmless Assistant with Reinforcement Learning from Human Feedback提出,某个行为是否有害有害程度个人社会而异。

对齐的标准很主观,难以直接作为LLM的优化目标。比较有前景的方法是Red teaming language models to reduce harms: Methods, scaling behaviors, and lessons learnedRed teaming language models with language models提出的红队攻防,用对抗的方式手动自动探测LLM,使其生成有害输出,再更新模型防止此类输出

收集人类反馈

选择标注人员

收集反馈

  • 基于排序的方法:

  • 基于问题的方法:回答研究人员设计的特定问题,这些问题覆盖不同的对齐标准以及其他对LLM的约束条件。例如WebGPT中,标注人员要回答关于检索到的文档对回答给定输入是否有帮助的选择题。

  • 基于规则的方法:

    • Sparrow不仅选择标注人员挑选的最佳回复,还设计一系列规则测试模型生成的回复是否符合有用正确无害的标准,让标注者对模型生成的回复违反规则的程度进行打分

    • GPT-4用一组基于GPT-4的zero-shot分类器作为基于规则的奖励模型自动确定模型生成的输出是否违反一组人类编写的规则

RLHF

详见RLHF章节

高效微调

全量参数都微调成本很大,有更高效的方法,称为参数高效微调parameter-efficient fine-tuning)。

适配器微调(adapter tuning)

Parameter-efficient transfer learning for NLP提出,在Transformer中引入一个小型神经网络模块适配器),LLM-Adapters: An Adapter Family for Parameter-Efficient Fine-Tuning of Large Language Models也提出了瓶颈架构:

  • 将原始特征压缩到较小维度(然后进行非线性变换)

  • 恢复到原始维度

一般是串行插入的方式,集成到每个Transformer层里,分别放到注意力层前馈层之后Towards a unified view of parameter- efficient transfer learning提出了并行适配器,即与注意力层和前馈层并行

微调时,原参数不变仅更新适配器模块参数

前缀微调(prefix tuning)

Prefix-tuning: Optimizing continuous prompts for generation

  • 在每个Transformer层前添加一系列前缀,即一组可训练的连续向量。前缀向量具有任务的特异性,可以看作虚拟的token emb

  • 重参数化技巧:

    • 学习一个将较小矩阵映射到前缀参数矩阵MLP函数,而不是直接优化前缀,有助于稳定训练

    • 优化后,舍弃映射函数,只保留派生的前缀向量以增强与特定任务相关的性能。

    • 由于只训练前缀参数,故能实现参数高效的模型优化

P-tuning v2: Prompt tuning can be comparable to fine- tuning universally across scales and tasks提出了p-tuning v2,为了自然语言理解在Transformer中引入逐层提示向量,还利用多任务学习联合优化共享的提示

提示微调(prompt tuning)

输入层加入可训练提示向量,基于离散提示方法(How can we know what language models know?Autoprompt: Eliciting knowledge from lan- guage models with automatically generated prompts),通过包含一组软提示token来扩充输入文本,再用扩充后的输入来解决特定的下游任务。将任务特定的提示emb输入文本的emb相结合,输入模型中。

  • GPT understands, too:提出了P-tuning,用自由形式来组合上下文提示目标token,用双向LSTM学习软提示token的表示,适用于自然语言理解和生成的架构。

  • The power of scale for parameter-efficient prompt tuning:提示微调,直接在输入前加入前缀提示。训练时只有提示emb会根据特定任务进行监督学习。这种方法在输入层只包含少量可训练参数,故其效果高度依赖底层语言模型的能力

低秩适配(LoRA)

Lora: Low-rank adaptation of large language models通过增加低秩约束来近似每层的更新矩阵,假设参数矩阵WRm×n\mathbf{W} \in \mathbb{R}^{m \times n},一般是

W=W+ΔW\mathbf{W}=\mathbf{W}+\Delta \mathbf{W}

冻结W\mathbf{W},通过低秩分解矩阵来近似更新

ΔW=AB\Delta \mathbf{W}=\mathbf{A} \cdot \mathbf{B}^{\top}

其中ARm×k\mathbf{A} \in \mathbb{R}^{m \times k}BRn×k\mathbf{B} \in \mathbb{R}^{n \times k}是用于任务适配的可训练参数,rmin(m,n)r \ll \min (m, n)降低后的秩

LoRA的优点:

  • 大大节省内存和存储(如VRAM,Video Random Access Memory)

  • 可以只保留一个大型模型副本,同时保留多个用于适配不同下游任务特定低秩分解矩阵

用更有原则的方法设置秩:

小结

LoRA已经有广泛的应用,如LLaMA和BLOOM,

LLM-Adapters: An Adapter Family for Parameter-Efficient Fine-Tuning of Large Language Models比较了串行适配器微调、并行适配器微调和LoRA,在GPT-J(6B)、BLOOM(7.1B)和LLaMA(7B)上评估:这些方法在困难任务上效果不如GPT-3.5,但在简单任务上表现相当LoRA表现相对较好且使用的可训练参数明显较少。

huggingface开源了Peft: State-of-the-art parameter-efficient fine-tuning methods,包括LoRA/AdaLoRA、前缀微调、P-Tuning、提示微调,支持GPT-2和LLaMA,还支持视觉Transformer如ViT和Swin Transformer。

让大模型不再「巨无霸」,这是一份最新的大模型参数高效微调综述

Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey

lora变种

DoRA

DoRA: Weight-Decomposed Low-Rank Adaptation

https://github.com/catid/dora

LoRA可以认为是对Finetune微调的一种低秩近似,通过增加Rank,LoRA可以达到类似Finetune的微调效果。因此之前多数研究都把LoRA和Finetune在微调准确性上的差异归结为二者的优化参数量不同。

但经过分析发现,lora的学习模式和FT很不一样,更偏向于大开大合,即方向幅度呈很强的正相关,可能对更精细的学习有害

dora通过同时关注权重更新时的大小方向变化,实现了比LoRA更加接近finetune微调效果:

  • w拆成magnitude(normnorm)乘以direction(1/norm×w1/norm \times w)

  • magnitude不变,direction里的1/norm1/norm用lora更新

注意,这里的norm是column-wise的norm,即输入d×kd\times k的矩阵,每一列的元素算一个norm(平方和开根号)得到一个数,最终就是1×k1\times k的矩阵

# This layer is dropped into your pre-trained PyTorch model where nn.Linear is used
class DoRALayer(nn.Module):
    def __init__(self, d_in, d_out, rank=4, weight=None, bias=None):
        super().__init__()

        if weight is not None:
            self.weight = nn.Parameter(weight, requires_grad=False)
        else:
            self.weight = nn.Parameter(torch.Tensor(d_out, d_in), requires_grad=False)

        if bias is not None:
            self.bias = nn.Parameter(bias, requires_grad=False)
        else:
            self.bias = nn.Parameter(torch.Tensor(d_out), requires_grad=False)

        # m = Magnitude column-wise across output dimension
        self.m = nn.Parameter(self.weight.norm(p=2, dim=0, keepdim=True))
        
        std_dev = 1 / torch.sqrt(torch.tensor(rank).float())
        self.lora_A = nn.Parameter(torch.randn(d_out, rank)*std_dev)
        self.lora_B = nn.Parameter(torch.zeros(rank, d_in))

    def forward(self, x):
        lora = torch.matmul(self.lora_A, self.lora_B)
        adapted = self.weight + lora
        column_norm = adapted.norm(p=2, dim=0, keepdim=True)
        norm_adapted = adapted / column_norm
        calc_weights = self.m * norm_adapted
        return F.linear(x, calc_weights, self.bias)

## 使用
def replace_linear_with_dora(model):
    for name, module in model.named_children():
        if isinstance(module, nn.Linear):
            # Get the input and output dimensions of the current nn.Linear layer
            d_in = module.in_features
            d_out = module.out_features

            # Create a new DoRALayer with the same dimensions
            setattr(model, name, DoRALayer(d_out=d_out, d_in=d_in, weight=module.weight.data.clone(), bias=module.bias.data.clone()))
        else:
            # Recursively apply this function to submodules
            replace_linear_with_dora(module)

fourierft

ICML 2024 | 脱离LoRA架构,训练参数大幅减少,新型傅立叶微调来了

https://github.com/Chaos96/fourierft

使用

上下文学习

GPT-3提出ICL,将任务描述和(或)示范(demonstration)以自然语言文本形式表达。

上下文学习形式

  • 任务描述作为开始,从任务数据集中选择一些样例作为示范

  • 以特别设计的模板形式将它们按照特定的顺序组合成自然语言提示

  • 测试样例添加到LLM的输入中以生成输出。

形式化地看,Dk={f(x1,y1),,f(xk,yk)}D_k=\left\{f\left(x_1, y_1\right), \ldots, f\left(x_k, y_k\right)\right\}表示由kk个样例组成的一组示范,f(xk,yk)f\left(x_k, y_k\right)表示把第kk任务样例转换为自然语言提示的函数。给定任务描述II、示范DkD_k和新的输入查询xk+1x_{k+1},LLM生成的输出y^k+1\hat{y}_{k+1}如下:

LLM(I,f(x1,y1),,f(xk,yk)示范 ,f(xk+1输入 ,___答案 ))y^k+1\operatorname{LLM}(I, \underbrace{f\left(x_1, y_1\right), \ldots, f\left(x_k, y_k\right)}_{\text {示范 }}, f(\underbrace{x_{k+1}}_{\text {输入 }}, \underbrace{\_\_\_}_{\text {答案 }})) \rightarrow \hat{y}_{k+1} \text {. }

真实答案yk+1y_{k+1}留白,由LLM预测。

更多的可以参考综述A survey for in-context learning

指令微调可以提高LLM执行目标任务的ICL能力,尤其是零样本场景(仅使用任务描述)。

示范设计

示范选择

An explanation of in-context learning as implicit bayesian inference提到,ICL中选择的示范样例应该包含足够的有关待解决任务的信息,并与测试查询相关

示范格式

将选择的示范进行整合以及格式化

示范顺序

LLM有时会被顺序偏差影响,例如Calibrate before use: Improving few-shot performance of language models提出LLM会倾向于重复示范结尾附近的答案===>结尾很重要!!

底层机制

预训练如何影响ICL

LLM如何实现ICL

思维链提示(CoT)

CoT是一种改进的提示策略,旨在提高LLM在复杂推理任务中的性能,如算术推理(Training verifiers to solve math word problemsAre NLP models really able to solve simple math word problems?A diverse corpus for evaluating and developing english math word problem solvers)、常识推理(Commonsenseqa: A question answering challenge targeting commonsense knowledgeDid aristotle use a laptop? A question answering benchmark with implicit reasoning strategies)、符号推理(Chain of thought prompting elicits reasoning in large language models)。

ICL只使用输入输出对来构造提示,而CoT将最终输出的中间推理步骤加入提示。

使用CoT的ICL

一般在小样本和零样本这两种设置下和ICL一起用

小样本思维链

将每个示范<输入,输出>替换为<输入,CoT,输出>。小样本CoT可以看成ICL的一种特殊提示,但相比ICL的标准提示,示范的顺序对性能影响相对较小

零样本思维链

不在提示中加入人工标注的示范,而是直接生成推理步骤,再利用生成的CoT来得出答案。Large language models are zero-shot reasoners

  • 先通过“Let’s think step by step”来提示LLM生成步骤

  • 再通过“Therefore, the answer is”来提示得到最终答案

这种方法在模型规模超过一定大小时可以显著提高性能,但在小规模的模型效果不佳,即涌现能力。

Flan-T5和Flan-PaLM(Scaling instruction-finetuned language models)进一步地使用CoT进行指令调整,有效增强了在未见任务上的零样本性能。

进一步讨论CoT

  • 思维链何时适用于LLM:

  • LLM为何能进行思维链推理:

    • 思维链能力的来源:

    • 提示中组成部分的影响:

能力评测

基础评测

语言生成

语言建模

条件文本生成

代码合成

存在问题

  • 可控生成

  • 专业化生成

知识利用

闭卷问答

开卷问答

知识补全

存在问题

  • 幻觉(Hallucination)

  • 知识实时性

复杂推理

知识推理

符号推理

数学推理

存在问题

  • 不一致性

  • 数值计算

高级评估

与人类对齐

与外部环境互动

工具使用

公开基准

LLM常用基准测试科普

  • MMLU:

  • BIG-bench:

  • HELM:

比较有用的数据集

中文glue

ChineseGLUE:为中文NLP模型定制的自然语言理解基准

超30亿中文数据首发!首个专为中文NLP打造的GLUE基准发布

https://github.com/CLUEbenchmark/CLUE

https://www.cluebenchmarks.com/

https://github.com/brightmart/nlp_chinese_corpus

http://thuctc.thunlp.org/#%E4%B8%AD%E6%96%87%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E9%9B%86THUCNews

中文阅读理解数据集

首个中文多项选择阅读理解数据集:BERT最好成绩只有68%,86%问题需要先验知识

Investigating Prior Knowledge for Challenging Chinese Machine Reading Comprehension

https://github.com/nlpdata/c3

物理常识推理任务数据集

PIQA: Reasoning about Physical Commonsense in Natural Language

「在不使用刷子涂眼影的情况下,我应该用棉签还是牙签?」类似这种需要物理世界常识的问题对现今的自然语言理解系统提出了挑战。虽然最近的预训练模型 (如 BERT) 在更抽象的如新闻文章和百科词条这种具有丰富文本信息的领域问答方面取得了进展,但在更现实的领域,由于报导的偏差,文本本质上是有限的,类似于「用牙签涂眼影是一个坏主意」这样的事实很少得到直接报道。人工智能系统能够在不经历物理世界的情况下可靠地回答物理常识问题吗?是否能够捕获有关日常物品的常识知识,包括它们的物理特性、承受能力以及如何操纵它们。

在本文中,研究者介绍了一个关于物理常识推理任务和相应的基准数据集 PIQA(Physical Interaction:Question Answering)进行评估。虽然人类应对这一数据集很容易 (95% 的准确率),但是大型的预训模型很难 (77%)。作者分析了现有模型所缺乏的知识为未来的研究提供了重要的机遇。

常识推理数据集WinoGrande

WinoGrande: An Adversarial Winograd Schema Challenge at Scale

研究者提出了 WINOGRANDE,一个有着 44k 个问题的大规模数据集。该数据集在规模和难度上较之前的数据集更大。该数据集的构建包括两个步骤:首先使用众包的方式设计问题,然后使用一个新的 AFLITE 算法缩减系统偏见(systematic bias),使得人类可以察觉到的词汇联想转换成机器可以检测到的嵌入联想(embedding association)。现在最好的 SOTA 模型可以达到的性能是 59.4 – 79.1%,比人脸性能水平(94%)低 15-35%(绝对值)。这种性能波动取决于训练数据量(2% 到 100%)。

本论文荣获了 AAAI 2020 最佳论文奖,文中提出的 WINOGRANDE 是一个很好的迁移学习资源;但同时也说明我们现在高估了模型的常识推理的能力。研究者希望通过这项研究能够让学界重视减少算法的偏见。

对话数据集

谷歌发布世界最大任务型对话数据集SGD,让虚拟助手更智能

Towards Scalable Multi-domain Conversational Agents: The Schema-Guided Dialogue Dataset

BelleGroup

https://huggingface.co/BelleGroup 里有很多中文的instruct和输出的数据集

OpenEQA

从文字模型到世界模型!Meta新研究让AI Agent理解物理世界

RLHF & InstructGPT

OpenAI魔改大模型,参数减少100倍!13亿参数InstructGPT碾压GPT-3

https://openai.com/blog/deep-reinforcement-learning-from-human-preferences/

Training language models to follow instructions with human feedback

https://huggingface.co/blog/zh/rlhf

  • 预训练一个语言模型 (LM) ;

  • 聚合问答数据并训练一个奖励模型 (Reward Model,RM),也叫偏好模型;

  • 用强化学习 (RL) 方式微调 LM。

sft

确保任务多样性的情况下,由标注人员编写prompt和一些生成式任务的期望输出。

剖析大模型Pretrain和SFT阶段的Loss差异

不管是PreTraining阶段还是SFT阶段,loss函数都是一样的,只是计算的方式存在差异,PreTraining阶段计算的是整段输入文本的loss,而SFT阶段计算的是response部分的loss

rm

接收一系列文本并返回一个标量奖励,数值上对应人的偏好。我们可以用端到端的方式用LM建模,或者用模块化的系统建模 (比如对输出进行排名,再将排名转换为奖励) 。

  • 模型选择:RM可以是另一个经过微调的LM,也可以是根据偏好数据从头开始训练的LM。Anthropic 提出了一种特殊的预训练方式,即用偏好模型预训练 (Preference Model Pretraining,PMP) 来替换一般预训练后的微调过程,PMP对样本的利用率更高

  • 训练文本:RM 的提示 - 生成对文本是从预定义数据集中采样生成的,并用初始的 LM 给这些提示生成文本。Anthropic 的数据主要是通过 Amazon Mechanical Turk 上的聊天工具生成的,并在 Hub 上 可用,而 OpenAI 使用了用户提交给 GPT API 的 prompt。

  • 训练奖励数值:人工对 LM 生成的回答进行排名。起初我们可能会认为应该直接对文本标注分数来训练 RM,但是由于标注者的价值观不同导致这些分数未经过校准并且充满噪音,通过排名可以比较多个模型各自的输出并构建更好的规范数据集,这些不同的排名结果将被归一化为用于训练的标量奖励值。

目前成功的RLHF使用了和要对齐的LM具有不同大小的LM:

  • OpenAI:175B的LM和6B的RM

  • Anthropic:使用的 LM 和 RM 从 10B 到 52B 大小不等

  • DeepMind:使用了 70B 的 Chinchilla 模型分别作为 LM 和 RM

rl

直接微调整个 10B~100B+ 参数的成本过高 ,参考低秩自适应LoRA和DeepMind的Sparrow LM。目前多个组织找到的可行方案是使用策略梯度强化学习 (Policy Gradient RL) 算法、近端策略优化 (Proximal Policy Optimization,PPO) 微调初始 LM 的部分或全部参数

  • 策略 (policy):一个接受提示并返回一系列文本 (或文本的概率分布) 的 LM

  • 行动空间(action space): LM 的词表对应的所有词元 (一般在 50k 数量级)

  • 观察空间 (observation space): 是可能的输入词元序列,也比较大 (词汇量^输入标记的数量)

  • 奖励函数:偏好模型和策略转变约束 (Policy shift constraint) 的结合。

ppo确定的奖励函数如下:

  • 提示xx输入初始LM和当前微调的LM,分别得到输出文本y1y_1y2y_2

  • 将来自当前策略的文本传给RM得到标量奖励rθr_{\theta}

  • 将两个模型的生成文本进行比较计算差异的惩罚项,一般是输出词分布间的KL散度的缩放,即r=rθλrKLr=r_{\theta}-\lambda r_{KL}

惩罚项的好处:

  • 用于惩罚策略在每个训练batch中生成大幅偏离初始模型,以确保模型输出合理连贯的文本。

  • 如果没有这一项,可能导致模型在优化中生成乱码文本,以愚弄奖励模型提供高奖励值。

根据PPO,按当前batch的奖励进行优化。PPO是置信域优化(TRO,Trust Region Optimization)算法,用梯度约束确保更新步骤不会破坏学习过程的稳定性。

DeepMind对Gopher用了类似的奖励设置,但用的是A2C来优化梯度。

rl流程概述

https://zhuanlan.zhihu.com/p/635757674

Fine-Tuning Language Models from Human Preferences

Secrets of RLHF in Large Language Models Part I: PPO

  • Rollout and Evaluation:从prompt库里抽样,使用语言模型生成response,然后使用奖励模型(Reward Model, RM)给出奖励得分。这个得分反映了生成的response的质量,比如它是否符合人类的偏好,是否符合任务的要求等。

  • Make experience:收集了一系列的“经验”,即模型的行为和对应的奖励。这些经验包括了模型生成的response以及对应的奖励得分。这些经验将被用于下一步的优化过程。

  • Optimization:使用收集到的经验来更新模型的参数。具体来说,我们使用PPO算法来调整模型的参数,使得模型生成的response的奖励得分能够增加。PPO算法的一个关键特性是它尝试保持模型的行为不会发生太大的改变,这有助于保证模型的稳定性。

官方代码example

from tqdm import tqdm

for epoch, batch in tqdm(enumerate(ppo_trainer.dataloader)):
    query_tensors = batch["input_ids"]

    #### Get response from SFTModel
    response_tensors = ppo_trainer.generate(query_tensors, **generation_kwargs)
    batch["response"] = [tokenizer.decode(r.squeeze()) for r in response_tensors]

    #### Compute reward score
    texts = [q + r for q, r in zip(batch["query"], batch["response"])]
    pipe_outputs = reward_model(texts)
    rewards = [torch.tensor(output[1]["score"]) for output in pipe_outputs]

    #### Run PPO step
    stats = ppo_trainer.step(query_tensors, response_tensors, rewards)
    ppo_trainer.log_stats(stats, batch, rewards)

#### Save model
ppo_trainer.save_model("my_ppo_model")
  • Rollout:根据策略(LM)生成轨迹(文本)。

    • 输入:Batch Prompt、LM

    • 输出:Prompt+Response

  • Evaluate:对生成的轨迹进行评估(RM)。

    • 输入:Prompt+Response、RM

    • 输出:Reward

  • Old Policy Sampling:计算并存储旧策略的概率、价值等值,

    • 输入:Ref_model、Actor、Critic、Prompt+Response

    • 输出:Ref Logprobs、Old Logprobs、Old Values

  • KL Penalty:计算当前策略原始LM之间的KL散度,用作对策略改变过快的惩罚项。

    • 输入:Ref Logprobs、Old Logprobs、Reward

    • 输出:Token Reward

  • Generalized Advantage Estimation (GAE):G。基于old value(shape是(batch_size, response_length))和reward估计优势函数A,它结合了所有可能的n-step 进行advantage估计

    • 输入:Token Reward、Old Values

    • 输出:Advantages、Returns

  • New Policy Sampling:

    • 输入ref_model、actor、critic,从新的策略中采样概率等信息,

    • 输出new logprobs、new values和logits,供actor loss、critic loss以及entropy loss用。

  • Critic Loss:Critic的目标是估计状态的价值函数,Critic loss就是价值函数预测值和实际回报之间的差距。

    • 输入:New Values、Returns

    • 输出:critic梯度更新

  • Actor Loss:Actor的目标是优化策略,Actor loss就是基于优势函数的策略梯度。

    • 输入:Old Logprobs,New Logprobs、Advantages

    • 输出:actor梯度更新

  • Entropy Loss:为了增加探索性,通常会添加一个基于策略熵的正则项,它鼓励策略保持多样性。

    • 输入:Logits

    • 输出:entropy loss

  • Policykl:这是对策略迭代过程的一个度量,它度量新策略旧策略之间的差距。

    • 输入:Old Logprobs、New Logprobs

    • 输出:是否early stop

在PPO中,策略优化的过程涉及到两个策略:一个是"旧的"策略,这是我们在开始每次优化迭代时使用的策略,另一个是"新的"策略,这是我们在优化过程中不断更新的策略。

自己整理重画的

几个重要的loss

actor & actor loss

Actor 是策略,它决定文本会被怎么样生成,是从策略网络拷贝来的模拟整个智能体在环境中行动的网络。

优势函数表示在给定的状态下采取某个行动比遵循当前策略的期望回报要好多少。

Actor Loss如下,用重要性采样比较在旧策略新策略下行动的概率(Old Logprobs,New Logprobs),然后将这个比值(也就是 Importance Sampling 的权重)与优势函数Advantages相乘,得到了对 Actor Loss 的一个估计。

L=πnew/πoldAL=\pi_{new}/\pi_{old} * A

# 计算新旧策略下概率的比值
ratio = torch.exp(logprobs - old_logprobs)

# 计算未截断的策略梯度损失
pg_losses = -advantages * ratio

# 计算截断的策略梯度损失
pg_losses2 = -advantages * torch.clamp(ratio, 1.0 - self.config.cliprange,
     1.0 + self.config.cliprange)

# 选择两者中较大的作为最终的策略梯度损失
pg_loss = masked_mean(torch.max(pg_losses, pg_losses2), mask)

# 计算因为截断导致策略梯度损失改变的比例
pg_clipfrac = masked_mean(torch.gt(pg_losses2, pg_losses).double(), mask)

critic & critic loss

critic是专门用来预测actor轨迹每一步价值的网络,actor上加几个线性层能够给每个token预测一个值。任务是估计状态的价值函数,也就是预测从当前状态开始,通过遵循某个策略,期望能得到的总回报。

Critic Loss是最小化它的预测价值与实际回报之间的差距,常用mse

通过最小化Critic Loss,Critic的预测能力会逐渐提升。因为Critic的预测结果会被用来估计每个行动的优势(Advantage),这个优势值又会被用来计算策略的更新(Actor Loss)。

# 将价值函数的预测值裁剪到一个范围内
vpredclipped = clip_by_value(
            vpreds, values - self.config.cliprange_value, values + self.config.cliprange_value
        )

# 计算裁剪前和裁剪后的价值函数损失
vf_losses1 = (vpreds - returns) ** 2
vf_losses2 = (vpredclipped - returns) ** 2

# 最终的价值函数损失是裁剪前和裁剪后损失的最大值的平均值的一半
vf_loss = 0.5 * masked_mean(torch.max(vf_losses1, vf_losses2), mask)

# 计算裁剪操作实际发生的频率
vf_clipfrac = masked_mean(torch.gt(vf_losses2, vf_losses1).double(), mask)

KL Penalty

用于保证经过强化学习后的模型(新策略actor)不会过于偏离原始预训练模型(ref model)。

# 初始化两个列表来分别存储奖励和非得分奖励
rewards, non_score_rewards = [], []

# 使用 zip 函数并行遍历输入的得分、对数概率、参考模型的对数概率以及mask
for score, logprob, ref_logprob, mask in zip(scores, logprobs, 
        ref_logprobs, masks):
    # 计算 KL 散度,即模型的对数概率与参考模型的对数概率之间的差值
    kl = logprob - ref_logprob

    # 计算非得分奖励,即 KL 散度乘以 KL 控制器值的负值
    non_score_reward = -self.kl_ctl.value * kl
    non_score_rewards.append(non_score_reward)

    # 复制非得分奖励为新的奖励
    reward = non_score_reward.clone()

    # 找到mask中最后一个非零元素的索引,这表示输入序列的实际长度
    last_non_masked_index = mask.nonzero()[-1]

    # 对于最后一个非mask部分的token,其奖励是偏好模型的得分加上 KL 散度
    reward[last_non_masked_index] += score

    # 将计算的奖励添加到奖励列表中
    rewards.append(reward)

# 返回包含所有奖励的张量以及包含所有非得分奖励的张量
return torch.stack(rewards), torch.stack(non_score_rewards)

GAE

GAE是一种多步优势估计方法。它通过引入一个权衡参数λ\lambda,在单步TD误差多步TD误差之间进行权衡,从而减小估计的方差,提高学习的稳定性。其中σt+l\sigma _{t+l}是时间步t+lt+l的TD误差。

At=l=0k1(λη)lσt+lA_t=\sum ^{k-1}_{l=0}(\lambda \eta )^{l}\sigma _{t+l}

σt+l=rt+l+1+ηV(st+l+1)V(st+l)\sigma _{t+l}=r_{t+l+1}+\eta V(s_{t+l+1})-V(s_{t+l})

# 从后往前遍历整个生成的序列
for t in reversed(range(gen_len)):
    # 计算下一个状态的价值,如果当前状态已经是最后一个状态,则下一个状态的价值为0
    nextvalues = values[:, t + 1] if t < gen_len - 1 else 0.0

    # 计算 delta,它是奖励加上衰减后的下一个状态的价值,然后减去当前状态的价值
    delta = rewards[:, t] + self.config.gamma * nextvalues - values[:, t]

    # 使用 delta 更新 lastgaelam,这是 GAE 公式的一部分
    lastgaelam = delta + self.config.gamma * self.config.lam * lastgaelam

    # 将计算的优势值添加到优势值列表中
    advantages_reversed.append(lastgaelam)

# 将优势值列表反向并转换为张量
advantages = torch.stack(advantages_reversed[::-1]).transpose(0, 1)

# 计算回报值,它是优势值加上状态值
returns = advantages + values

entropy loss

一个策略的熵越大,意味着这个策略选择各个动作的概率更加“平均”。在actor的loss里加熵,使得策略的熵尽可能大,从而有更多机会探索可能带来更好奖励的文本轨迹。

entropy = -torch.sum(logits* torch.log(logits + 1e-9), dim=-1).mean()

新实现:

    pd = torch.nn.functional.softmax(logits, dim=-1)
    entropy = torch.logsumexp(logits, axis=-1) - torch.sum(pd * logits, axis=-1)

Policy kl

在PPO中,KL散度被用作一种约束,以确保在优化过程中新策略不会偏离旧策略太远。这是为了防止过度优化,因为过度优化可能会导致策略性能的大幅下降。

我们希望在优化目标函数的同时,满足以下的KL散度约束:

KL[πθold(st),πθ(st)]δKL[\pi_{\theta_{old}}(\cdot|s_t),\pi_{\theta}(\cdot|s_t)]\le \delta

在代码中,每个mini batch都会进行early stop的判定,如果计算出的KL散度大于 δ\delta,那么就会停止这一轮的优化,以保证新策略不会偏离旧策略太远。

# 计算旧策略和新策略之间的KL散度
policykl = masked_mean(old_logprobs - logprobs, mask) 
# old_logprobs 是旧策略下行为的概率的对数,logprobs 是新策略下的对数概率
# masked_mean 函数计算差异(old_logprobs - logprobs)的平均值,
# 但只考虑mask中对应元素为True的元素

# 检查计算出的KL散度(policykl)是否大于目标KL散度(self.config.target_kl)的1.5倍
if policykl > 1.5 * self.config.target_kl: 
    self.optimizer.zero_grad()  
    # 如果实际的KL散度超过了目标的1.5倍,那么策略改变过多,这步的梯度也不更新了。
    early_stop = True  
    # 并设置early_stop标志为True,表示应提前停止优化,以防止策略从旧策略进一步偏离

两个采样

Old Policy Sampling(无bp)

make experience的过程,计算并存储旧策略的概率、价值等值,来为后面更新的过程服务。

  • Old Logprobs:从“旧的”策略[即在这个batch数据中初始的LM(initial actor)]中计算每个token在旧的策略下的概率Old Logprobs。

  • Old Values:旧策略中每个时间步(每个token的预测结果)的价值,这个值由critic网络进行预测,critic网络就是需要这个值的原因是advantage的计算依赖于Old Values。

  • Ref Logprobs:最最原始的LM对于每个时间步的概率预测,一般就是固定不变的gpt3,计算这个值的目的是限制actor的更新,防止其偏离原始gpt3太远,他的实现在下一个步骤中。

all_logprobs, _, values, masks = self.batched_forward_pass(self.model, queries, 
    responses, model_inputs)
ref_logprobs, _, _, _ = self.batched_forward_pass(self.ref_model, queries, 
    responses, model_inputs)

New Policy Sampling(有bp)

新的策略(更新后的actor)下对轨迹(文本)计算概率的过程,计算Actor Loss,即策略梯度的损失。

Old Logprobs是一次性一个batch的数据计算的,这是因为在一个batch中旧策略都是不变的;而New Logprobs是一个mini batch计算一次,这是因为新策略每个mini batch变一次。

开源rlhf库

https://iclr-blog-track.github.io/2022/03/25/ppo-implementation-details/

影响PPO算法性能的10个关键技巧(附PPO算法简洁Pytorch实现)

openai的lm-human-preferences(gpt2的finetune)

https://github.com/openai/lm-human-preferences

huggingface的TRL

https://github.com/huggingface/trl

CarperAI的trlx

https://github.com/CarperAI/trlx

allenai的RL4LMs

https://github.com/allenai/RL4LMs

RLHF workflow

仅靠开源数据复刻出LLaMA3指令学习效果,在线迭代RLHF全流程解决方案来了

Iterative Preference Learning from Human Feedback: Bridging Theory and Practice for RLHF under KL-Constraint

RLHF Workflow: From Reward Modeling to Online RLHF

对应代码:

openrlhf

这个团队做了OpenAI没Open的技术,开源OpenRLHF让对齐大模型超简单

OpenRLHF: An Easy-to-use, Scalable and High-performance RLHF Framework

https://github.com/OpenLLMAI/OpenRLHF

RLHF变种

自我奖励

Self-Rewarding Language Models

「用 AI 训 AI」这事靠谱吗?

SimPO

全面超越DPO:陈丹琦团队提出简单偏好优化SimPO,还炼出最强8B开源模型

SimPO: Simple Preference Optimization with a Reference-Free Reward

https://github.com/princeton-nlp/SimPO

TDPO

从RLHF到DPO再到TDPO,大模型对齐算法已经是「token-level」

Token-level Direct Preference Optimization

https://github.com/Vance0124/Token-level-Direct-Preference-Optimization

CriticGPT

GPT-4批评GPT-4实现「自我提升」!OpenAI前超级对齐团队又一力作被公开

LLM Critics Help Catch LLM Bugs

CriticGPT依旧是自回归模型。标注者先向ChatGPT的响应输出中人为注入一些微妙的错误,CriticGPT针对这些有错误的答案生成批评意见,之后再由人类训练师为批评意见进行打分排名。

DeRa

ICML 2024 Spotlight | 在解码中重新对齐,让语言模型更少幻觉、更符合人类偏好

Decoding-time Realignment of Language Models

https://github.com/liutianlin0121/decoding-time-realignment

Step-DPO

贾佳亚团队新作:10k数据让大模型数学能力超GPT-4

https://github.com/dvlab-research/Step-DPO

Step-DPO: Step-wise Preference Optimization for Long-chain Reasoning of LLMs

多模态(图像)

【IEEE Fellow何晓东&邓力】多模态智能论文综述:表示学习,信息融合与应用,259篇文献带你了解AI热点技

Multimodal Intelligence: Representation Learning, Information Fusion, and Applications

BERT在多模态领域中的应用

VLM导论

视觉语言模型导论:这篇论文能成为你进军VLM的第一步

An Introduction to Vision-Language Modeling

vilbert

ViLBERT: Pretraining Task-Agnostic Visiolinguistic Representations for Vision-and-Language Tasks

研究人员提出了一种名为 ViLBERT(图文 BERT)模型。这是一个可以学习任务未知的、图像内容和自然语言联合表征的模型。研究人员将流行的 BERT 架构扩展成一个 multi-modal two-stream 模型上。在这个模型上,模型用两个分开的流处理图像和文本输入,但他们彼此用联合注意力层交互。研究人员在两个代理任务上,使用 Conceptual Captions 数据集(数据集很大,而且是自动收集的数据)预训练这个模型,然后将模型秦阿姨到多个建立好的图像-文本任务上。这些任务包括图像问答、图像常识推理、引述表达、指称成分,以及基于捕捉的图像提取。这些只需要在基本架构上进行微小的补充。研究人员观察到,相比现有的针对任务的特定模型,新模型在这些任务上都有了相助的性能提升——在每个任务上都取得了 SOTA。

VLbert

Visual-Linguistic BERT,简称 VL-BERT

微软亚研提出VL-BERT:通用的视觉-语言预训练模型

此预训练过程可以显著提高下游的视觉-语言任务的效果,包含视觉常识推理、视觉问答与引用表达式理解等。值得一提的是,在视觉常识推理排行榜中,VL-BERT 取得了当前单模型的最好效果。

VL-BERT: Pre-training of Generic Visual-Linguistic Representations

之前的视觉-语言模型分别使用计算机视觉或自然语言处理领域中的预训练模型进行初始化,但如果目标任务数据量不足,模型容易过拟合从而损失性能。并且对于不同的视觉-语言任务,其网络架构一般是经过特殊设计的,由此很难通过视觉-语言联合预训练的过程帮助下游任务。

VL-BERT 的主干网络使用 TransformerAttention 模块,并将视觉与语言嵌入特征作为输入,其中输入的每个元素是来自句子中的单词、或图像中的感兴趣区域(Region of Interests,简称 RoIs)。在模型训练的过程中,每个元素均可以根据其内容、位置、类别等信息自适应地聚合来自所有其他元素的信息。在堆叠多层 TransformerAttention 模块后,其特征表示即具有更为丰富的聚合与对齐视觉和语言线索的能力。

为了更好地建模通用的视觉-语言表示,作者在大规模视觉-语言语料库中对 VL-BERT 进行了预训练。采用的预训练数据集为图像标题生成数据集,Conceptual Captions,其中包含了大约 330 万个图像标题对。

VL-BERT 的预训练主要采用三个任务:

  • 屏蔽语言模型(Masked Language Modeling),即随机屏蔽掉语句中的一些词,并预测当前位置的词是什么;

  • 屏蔽 RoI 分类(MaskedRoIClassification),即随机屏蔽掉视觉输入中的一些 RoIs,并预测此空间位置对应 RoI 的所属类别;

  • 图像标题关联预测(Sentence-Image Relationship Prediction),即预测图像与标题是否属于同一对。

在预训练结束后,使用微调来进行下游任务的训练。本文中主要在三个视觉-语言下游任务中进行微调,即视觉常识推理(VisualCommonsenseReasoning)、视觉问答(VisualQuestionAnswering)与引用表达式理解(ReferringExpressionComprehension),下面将分别介绍。

视觉常识推理任务即给定图片与相关问题,机器不仅需要回答问题,还需要提供理由来证明答案的正确性。此任务(Q->AR)被分解为两个子任务,即视觉问答(Q->A,给定图片与问题,输出正确答案),以及视觉推理(QA->R,给定图片、问题与答案,输出正确的理由)。

BEiT系列

BEiT

BEIT: BERT Pre-Training of Image Transformers

BEiT v2

BEIT V2: Masked Image Modeling with Vector-Quantized Visual Tokenizers

BEiT v3

Image as a Foreign Language: BEIT Pretraining for All Vision and Vision-Language Tasks

ViT&Swin-Transformer

SwinTransformer与Vit细节总结

An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale

对于一张224×224×3224\times 224\times 3的图像,假设每个patch是16×1616\times 16,那就分成224×22416×16=196\frac{224\times 224}{16\times 16}=196个patch(即seq_length=196seq\_length=196),每个patch的维度是16×16×3=76816\times 16\times 3=768,最后加上[CLS]这个token,就是seq_length=197seq\_length=197

像素tokenizer

Meta新研究挑战CV领域基操:ViT根本不用patch,用像素做token效果更佳

An Image is Worth More Than 16x16 Patches: Exploring Transformers on Individual Pixels

stable diffusion

High-Resolution Image Synthesis with Latent Diffusion Models

  • 输入图像,经过编码器得到z,z通过前向扩散不断加噪声得到zTz_T(正向扩散)

  • 输入条件,经过条件编码器(原文是BERT,到了DALL-E2就改成CLIP了)得到τθ\tau_\theta

  • zTz_Tτθ\tau_\theta的指导下不断去噪(反向扩散),得到新的zz,再通过解码器得到最终生成的图像

其中的正向扩散和反向扩散一般用U-Net

代码库:https://github.com/CompVis/latent-diffusion/tree/main

粗略看了下代码,带condition的训练原理大概是训练语料中有图+文本(例如imagenet的class_label,这里可以映射到一个classid也可以直接拿明文),然后condition和图片一起作为输入去训练auto-eocnder和ldm

/latent-diffusion/ldm/data/imagenet.py这个代码里,把class_label加进来了

    def _load(self):
        with open(self.txt_filelist, "r") as f:
            self.relpaths = f.read().splitlines()
            l1 = len(self.relpaths)
            self.relpaths = self._filter_relpaths(self.relpaths)
            print("Removed {} files from filelist during filtering.".format(l1 - len(self.relpaths)))

        self.synsets = [p.split("/")[0] for p in self.relpaths]
        self.abspaths = [os.path.join(self.datadir, p) for p in self.relpaths]

        unique_synsets = np.unique(self.synsets)
        class_dict = dict((synset, i) for i, synset in enumerate(unique_synsets))
        if not self.keep_orig_class_label:
            self.class_labels = [class_dict[s] for s in self.synsets]
        else:
            self.class_labels = [self.synset2idx[s] for s in self.synsets]

        with open(self.human_dict, "r") as f:
            human_dict = f.read().splitlines()
            human_dict = dict(line.split(maxsplit=1) for line in human_dict)

        self.human_labels = [human_dict[s] for s in self.synsets]

        labels = {
            "relpath": np.array(self.relpaths),
            "synsets": np.array(self.synsets),
            "class_label": np.array(self.class_labels),
            "human_label": np.array(self.human_labels),
        }

        if self.process_images:
            self.size = retrieve(self.config, "size", default=256)
            self.data = ImagePaths(self.abspaths,
                                   labels=labels,
                                   size=self.size,
                                   random_crop=self.random_crop,
                                   )
        else:
            self.data = self.abspaths

stable diffusion 3

Stable Diffusion 3论文终于发布,架构细节大揭秘,对复现Sora有帮助?

DALL-E系列

DALL-E3:

Improving Image Generation with Better Captions

现有的文本->图像模型面临的一个基本问题是:训练数据集中的文本-图像pair对中的文本质量较差

  • 学习一个图像文本生成器,可以生成详细、准确的图像描述

  • 将此文本生成器应用到数据集以生成更详细的文本

  • 在改进的数据集上训练文本 - 图像模型

PALM-E

PaLM-E: An Embodied Multimodal Language Model

InstantID

InstantID: Zero-shot Identity-Preserving Generation in Seconds

https://github.com/InstantID/InstantID

小红书开源「InstantID」效果炸裂,迅速蹿上Github热榜

用户只需上传一张照片,就能轻松定制出多种风格的 AI 写真

曾爆火的 InstantID又有了新玩法:风格化图像生成,已开源

InstantStyle: Free Lunch towards Style-Preserving in Text-to-Image Generation

https://github.com/InstantStyle/InstantStyle

VAR

GPT超越扩散、视觉生成Scaling Law时刻!北大&字节提出VAR范式

Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction

https://github.com/FoundationVision/VAR

cobra

首个基于Mamba的MLLM来了!模型权重、训练代码等已全部开源

Cobra: Extending Mamba to Multi-Modal Large Language Model for Efficient Inference

https://github.com/h-zhao1997/cobra

Hyper-SD

加速扩散模型,最快1步生成SOTA级图片,字节Hyper-SD开源了

Hyper-SD: Trajectory Segmented Consistency Model for Efficient Image Synthesis

TextSquare

8B文字多模态大模型指标逼近GPT4V,字节、华师、华科联合提出TextSquare

TextSquare: Scaling up Text-Centric Visual Instruction Tuning

neural network diffusion

用扩散模型生成网络参数,LeCun点赞尤洋团队新研究

Neural Network Diffusion

https://github.com/NUS-HPC-AI-Lab/Neural-Network-Diffusion

hunyuan-dit

首个中文原生DiT架构!腾讯混元文生图大模型全面开源,免费商用

lumina-t2x

DiT架构大一统:一个框架集成图像、视频、音频和3D生成,可编辑、能试玩

Lumina-T2X: Transforming Text into Any Modality, Resolution, and Duration via Flow-based Large Diffusion Transformers

https://github.com/Alpha-VLLM/Lumina-T2X

https://huggingface.co/Alpha-VLLM/Lumina-T2I/tree/main

Chameleon

Meta首发「变色龙」挑战GPT-4o,34B参数引领多模态革命!10万亿token训练刷新SOTA

Chameleon: Mixed-Modal Early-Fusion Foundation Models

Vision-LSTM

原作者带队,LSTM卷土重来之Vision-LSTM出世

Vision-LSTM: xLSTM as Generic Vision Backbone

https://nx-ai.github.io/vision-lstm/

CSR

零成本突破多模态大模型瓶颈!多所美国顶尖高校华人团队,联合推出自增强技术CSR

Calibrated Self-Rewarding Vision Language Models

https://github.com/YiyangZhou/CSR

ManyICL

吴恩达团队新作:多模态多样本上下文学习,无需微调快速适应新任务

Many-Shot In-Context Learning in Multimodal Foundation Models

MAR

何恺明新作再战AI生成:入职MIT后首次带队,奥赛双料金牌得主邓明扬参与

Autoregressive Image Generation without Vector Quantization

Cambrian-1

寒武纪1号诞生:谢赛宁Yann LeCun团队发布最强开源多模态LLM

Cambrian-1: A Fully Open, Vision-Centric Exploration of Multimodal LLMs

https://github.com/cambrian-mllm/cambrian

https://huggingface.co/nyu-visionx/

https://huggingface.co/datasets/nyu-visionx/CV-Bench

https://github.com/cambrian-mllm/cambrian

当前多模态学习研究的两个潜在问题:

  • 过度且过早地依赖语言,这是一个捷径,能弥补学习有效视觉表征的不足之处

  • 现有基准可能无法为真实世界场景提供足够的指导 —— 视觉定基对于稳健的多模态理解至关重要

VCR

Bengio团队提出多模态新基准,直指Claude 3.5和GPT-4o弱点

VCR: Visual Caption Restoration

https://github.com/tianyu-z/VCR

EVE

抛弃视觉编码器,这个「原生版」多模态大模型也能媲美主流方法

Unveiling Encoder-Free Vision-Language Models

https://github.com/baaivision/EVE

多模态(视频)

videobert

通过未标记视频进行跨模态时间表征学习

VideoBERT: A Joint Model for Video and Language Representation Learning,VideoBert模型。

video caption

Tarsier: Recipes for Training and Evaluating Large Video Description Models

视频tokenizer方法

先看vq的改进版:

Finite Scalar Quantization: VQ-VAE Made Simple提出了fsq,码本大小是C=Ld|C|=L^d

magvit-v2提出了LFQ,也优化了vq-vae

BSQ:Image and Video Tokenization with Binary Spherical Quantization

claude-2-100k的回答。。

  • MAGVIT: Masked Generative Video Transformer:使用了3D向量量化(3D VQ)自动编码器来将视频量化为离散token

    • 设视频VVTT帧,其形状为T×H×W×3T \times H \times W \times 3

    • 3D VQ编码器fTf_T会把视频量化为一个token序列zz,其中zZTz\in Z^T,ZZ是码本,TT是token序列长度。

    • 3D VQ解码器fT1f^{-1}_T则可以从latent token zz重构回视频像素。

  • Genie: Generative Interactive Environments:使用了2D向量量化(2D VQ)方法

    • 每一帧图像I先通过一个2D VQ编码器f编码为一个token序列zz,其中zZNz\in Z^N,ZZ是2D码本。

    • 然后,对时间序列上的token z1,z2,...,zTz_1, z_2,..., z_T应用一个1D卷积网络,以捕获时间信息。

    • 再通过2D VQ解码器f1f^{-1}解码回每一帧图像。

  • Vivit: A video vision transformer:使用tubelet-embedding

    • 均匀地在时间轴上抽样ntn_t个帧,然后把每帧处理成nh×nwn_h \times n_w个patch,最终把所有patch连接起来

SORA

OpenAI首个AI视频模型炸裂登场,彻底端掉行业饭碗!60秒一镜到底惊人,世界模型真来了?

https://openai.com/sora

https://openai.com/research/video-generation-models-as-world-simulators

一锤降维!解密OpenAI超级视频模型Sora技术报告,虚拟世界涌现了

Sora爆火48小时:杨立昆揭秘论文,参数量或仅30亿

微软37页论文逆向工程Sora,得到了哪些结论?

攻陷短视频后,Sora将需要72万块H100 GPU

Sora: A Review on Background, Technology, Limitations, and Opportunities of Large Vision Models

Sora之后,OpenAI Lilian Weng亲自撰文教你从头设计视频生成扩散模型

https://lilianweng.github.io/posts/2024-04-12-diffusion-video/

整体感觉:

  • latent diffusion的隐空间

  • vit和swin transformer的patch

现有方法

现有的视频生成方法大多只能用于少数分类的视频、比较短的视频,或者固定长度的视频。

前两类太古老了,sora把后面两个(autogressive transformers和diffusion models)结合在一起了,而且能同时处理不同时长、分辨率的视频和图像

将视频转成spacetime latent patches

Vivit

Vivit: A video vision transformer

整体受ViT的启发

先分patch,再分别过时间的transformer(temporal transformer)和空间的transformer(spatial transformer)

具体的分patch方式如上图

latent空间上的patch

参考stable-diffusion,即High-Resolution Image Synthesis with Latent Diffusion Models,把patch切分改成在latent空间上进行

  • 将视频映射成隐空间(latent space)的表示

  • 把隐空间的表示切分成spacetime patches

预估时,可以通过在一个合适大小的grid里排列随机初始化的patches(we can control the size of generated videos by arranging randomly-initialized patches in an appropriately-sized grid.)来控制生成视频的大小。估计是参考了下面这篇:

论文参考了这个Patch n'Pack: NaViT, a Vision Transformer for any Aspect Ratio and Resolution,可以使下面提到的DiT适应各种分辨率/持续时间/宽高比。

Diffusion Transformer

Scalable diffusion models with transformers提出了DiT,替换stable diffusion中的u-net

DiT=VAE编码器+ ViT + DDPM + VAE解码器

sora是一个扩散模型,输入加了噪声的patches,还可以加上一些如text prompt的条件,预测原本『干净』的patches。

之前的做法大多将视频全裁成相同长度和大小的,例如4s的256×256256\times 256,sora可以直接用原始视频

语言理解

参考DALL-E3 (Improving Image Generation with Better Captions),训练了一个highly descriptive的视频描述生成器,拿这个生成器给训练集中的所有视频重新生成描述,再拿来训练。

此外,还用上了GPT,将用户输入的短的prompt改写成更长更详细的视频描述用于生成。

使用图像/视频作为prompt

  • 图像转动画:可以让静止的图像动起来

  • 扩展视频:可以对视频进行扩展(extend),在时间轴上向前或者向后进行延展(比如同样是一个石头落地,能生成4个视频,每个视频里的石头从不同的地方飞过来,落在同一个地面上)

  • 编辑视频:输入视频和一个文本prompt,能够对视频进行编辑,例如把场景从沙漠替换成树林,类似Sdedit: Guided image synthesis and editing with stochastic differential equations

  • 连接视频:输入两个看似毫不相关的视频,能通过很自然的方式把这两个视频衔接在一起

生成图像

图像就是一帧的视频,可以通过在时间范围为一帧的空间grid中排列高斯噪声patches(arranging patches of Gaussian noise in a spatial grid with a temporal extent of one frame)来生成图像,同样能生成不同分辨率的图像,最多2048×20482048\times 2048

涌现的模拟能力

  • 3D一致性:随着镜头的移动,视频中的人物或物体在3d空间中能在移动中保持一致

  • Long-range coherence and object permanence(远程连贯性和物体持久性):sora能对短期和长期依赖关系进行建模,例如:

    • 可以保留人物体,即使它们被遮挡或离开当前帧。

    • 可以在单个样本中生成同一角色的多个镜头,并在整个视频中保持其外观的不变

  • 与世界交互:例如画家可以在画布上留下新的笔触,并随着时间的推移而持续存在,人吃东西能留下齿痕

  • 模拟数字世界:可以同时通过基本策略控制《我的世界》中的玩家,同时以高保真度渲染世界及其动态,只需要在prompt里提到“我的世界”的标题就可以实现。

存在的问题

  • 不能准确地模拟许多基本相互作用的物理过程,例如玻璃破碎。

  • 其他交互(例如吃食物)并不总是会产生对象状态的正确变化,例如长时间样本中出现的不连贯性或对象的自发出现。

open-sora(Colossal-AI)

没等来OpenAI,等来了Open-Sora全面开源

Open-Sora全面开源升级:支持16s视频生成和720p分辨率

模型架构

v1版本:https://github.com/hpcaitech/Open-Sora/blob/main/docs/report_v1.md

v2版本:https://github.com/hpcaitech/Open-Sora/blob/main/docs/report_02.md

VAE部分

sora用了spatial-temporal VAE来降低temporal的维度,但并没有开源且高质量的spatial-temporal VAE:

  • MAGVIT:的4×4×44\times 4\times 4的VAE并没有开源

  • VideoGPT:的2×4×42\times 4\times 4的VAE在实验中效果不好

因此,使用https://huggingface.co/stabilityai/sd-vae-ft-mse-original的2D VAE

对于24fps的1min视频,有24×60=144024\times 60=1440帧,用4倍的VAE下采样和2倍的patch size下采样,有大约1440×1.5M1440\times \approx 1.5M的token。对这些token算全部的attention的计算开销很大,所以参考Latte: Latent Diffusion Transformer for Video Generation(代码https://github.com/Vchitect/Latte)的方案,使用spatial-temporal attention来减小计算量。

以下是latte的4个变种

STDiT(sequential)和latte的变种3类似,STDiT(parallel)和latte的变种4类似,在16×256×25616\times 256\times 256的视频上,发现效果如下,最终采用了STDiT(sequential)。

DiT(full)>STDiT(Sequential)>STDiT(Parallel)LatteDiT (full) > STDiT (Sequential) > STDiT (Parallel) \approx Latte

生成部分

PixArt-α: Fast Training of Diffusion Transformer for Photorealistic Text-to-Image Synthesis使用T5作为条件DiT结构,能生成高质量的图像。用PixArt-α对模型初始化,并对插入的temperal attentioin用0初始化,能够让模型一开始就保留图片生成的能力。插入的attention让参数量从580M涨到了724M。

训练

参考PixArt-α和Stable Video Diffusioin(Stable Video Diffusion: Scaling Latent Video Diffusion Models to Large Datasets),采用了progressive的训练策略:

  • 大规模图像预训练:前面提到的,直接使用https://huggingface.co/stabilityai/sd-vae-ft-mse-original的2D VAE

  • 大规模视频预训练:在质量相对差的366K的预训练数据集(HD-VG-130M数据集)上训练16×256×25616\times 256\times 256,这里的16指的是16帧

  • 高质量视频数据微调:在高质量的20K的数据集(Pexels数据集)上训练16×256×25616\times 256\times 25616×512×51216\times 512\times 51264×512×51264\times 512\times 512

由于使用了scaled position embedding,这个策略极大地减少了训练消耗。此外,对于16帧的训练,每3帧降采样一次,对于64帧的训练每2帧降采样一次。

数据标注方法:抽取3帧,然后设计prompt,用LLaVA生成高质量的标题:

  • 学习率:1e-4太大了,改成了2e-5

  • batchsize比较大的时候,fp16比bf16更不稳定,而且可能导致生成错误,所以对于64×512×51264\times 512\times 512使用bf16

提供了便捷的视频数据预处理脚本,可以轻松地在自己的数据集上快速生成训练所需的视频 / 文本对,包括公开视频数据集下载,长视频根据镜头连续性分割为短视频片段,使用开源LLaVA生成精细的提示词。

open-sora(北大版)

超10秒高分辨率,北大Open Sora视频生成更强了,还支持华为芯片

MORA

Sora不开源,微软给你开源!全球最接近Sora视频模型诞生,12秒生成效果逼真炸裂

复刻Sora的通用视频生成能力,开源多智能体框架Mora来了

Mora: Enabling Generalist Video Generation via A Multi-Agent Framework

minigpt4-video

AI视频理解天花板,全新MiniGPT4-Video刷爆SOTA!宝格丽宣传片配文一绝

mini-gemini

刷爆多模态任务榜单!贾佳亚团队Mini-Gemini登热榜,代码、模型、数据全部开源

模型地址:https://huggingface.co/collections/YanweiLi/mini-gemini-6603c50b9b43d044171d0854 数据地址:https://huggingface.co/collections/YanweiLi/mini-gemini-data-660463ea895a01d8f367624e

Mini-Gemini: Mining the Potential of Multi-modalityVision Language Models

VLM(vision lm)虽然有很多,但和gemini、gpt-4等的差距还是比较大,作者认为主要原因是高分辨率视觉标记不够vision推理数据质量不高

作者利用额外的视觉编码器进行高分辨率细化,构建了一个高质量的数据集。构建了一个Mini-Gemini架构,支持一系列从2B到34B的密集和MoE LLM,在zero-shot测试集上超过了私有模型。

https://github.com/dvlab-research/MiniGemini

Vidu

当前最强国产Sora!清华团队突破16秒长视频,懂多镜头语言,会模拟物理规律

采用了和 Sora 完全一致的 Diffusion 和 Transformer 融合的架构,底层基于All are Worth Words: A ViT Backbone for Diffusion Models的 U-ViT 架构。

基于 U-ViT 架构,2023 年 3 月,团队在开源的大规模图文数据集 LAION-5B 上训练了 10 亿参数量的多模态模型 ——UniDiffuser,并将其开源(参见清华朱军团队开源首个基于 Transformer 的多模态扩散大模型,文图互生、改写全拿下)。

UniDiffuser 主要擅长图文任务,能支持图文模态间的任意生成和转换。UniDiffuser 的实现有一项重要的价值 —— 首次验证了融合架构在大规模训练任务中的可扩展性(Scaling Law),相当于将 U-ViT 架构在大规模训练任务中的所有环节流程都跑通。

这些在图文任务中积累的工程经验为视频模型的研发打下了基础。因为视频本质上是图像的流,相当于是图像在时间轴上做了一个扩增。因此,在图文任务上取得的成果往往能够在视频任务中得到复用。Sora 就是这么做的:它采用了 DALL-E 3 的重标注技术,通过为视觉训练数据生成详细的描述,使模型能够更加准确地遵循用户的文本指令生成视频。这种效应也必然会发生在「Vidu」上面。

根据此前的消息推测,「Vidu」也复用了生数科技在图文任务的很多经验,包括训练加速、并行化训练、低显存训练等等,从而快速跑通了训练流程。据悉,他们通过视频数据压缩技术降低输入数据的序列维度,同时采用自研的分布式训练框架,在保证计算精度的同时,通信效率提升 1 倍,显存开销降低 80%,训练速度累计提升 40 倍。

gen-3

Runway版Sora发布:高保真、超强一致性,Gen-3 Alpha震撼到网友了

可灵

快手「可灵」爆火:海外AI圈巨震,中国版Sora一号难求

V2A

杀疯了!谷歌卷视频到语音,逼真音效让AI视频告别无声!

https://deepmind.google/discover/blog/generating-audio-for-video/

长视频LongVA

7B最强长视频模型! LongVA视频理解超千帧,霸榜多个榜单

Long Context Transfer from Language to Vision

liveportrait

快手开源LivePortrait,GitHub 6.6K Star,实现表情姿态极速迁移

LivePortrait: Efficient Portrait Animation with Stitching and Retargeting Control

https://github.com/KwaiVGI/LivePortrait

其他

扩散模型与文生视频

多模态大模型不够灵活,谷歌DeepMind创新架构Zipper:分开训练再「压缩」

Zipper: A Multi-Tower Decoder Architecture for Fusing Modalities

LLM+推荐

综述

https://github.com/nancheng58/Awesome-LLM4RS-Papers

A Survey on Large Language Models for Recommendation How Can Recommender Systems Benefit from Large Language Models: A Survey Recommender Systems in the Era of Large Language Models (LLMs)

中科大LDS实验室的tutorial:XadC3O-large-language-models-for-recommendation-tutorial-slides.pdf

对应的datafun talk:当"狂飙"的大模型撞上推荐系统

大模型放进推荐系统怎么玩?微软亚研全面总结

生成式推荐综述:

Large Language Models for Generative Recommendation: A Survey and Visionary Discussions

A Review of Modern Recommender Systems Using Generative Models (Gen-RecSys)

大语言模型在推荐系统中的探索与应用

DSI

参考知乎:https://zhuanlan.zhihu.com/p/470182510

Transformer memory as a differentiable search index,提出的可微搜索索引(differentiable search index, DSI),拆成两个阶段:

  • indexing:建立文档doc_id一一映射

  • retrieval:根据query生成候选doc_ids

Autoregressive Entity Retrieval提出的受限beam search的GENRE(代码https://github.com/facebookresearch/GENRE,解读Transformer中PrefixConstrainedLogitsProcessor类的解读)对比:

  • GENRE生成的目标是有具体语义的实体名

  • DSI生成的目标则是无任何语义的任意doc_id

Indexing方法

  • Inputs2Target:即doc_tokens->doc_id

  • Target2Inputs:即doc_id->doc_tokens

  • bidirectional:同时用上两面两个任务,并且在开始时加一个前缀,表明任务的方向

  • span corruption:参考T5(Exploring the limits of transfer learning with a unified text-to-text transformer),将doc_id当做前缀和doc_tokens拼起来,2个好处:

    • 在索引时进行通用的预训练

    • 实现doc_id作为去噪目标和输入的平衡

文档的表示

  • Direct Indexing:直接用文档的前L个单词当做文档的表示,并且保留单词的顺序。

  • Set Indexing:去掉文档中的重复的单词及停用词,然后和Direct Indexing一样的处理。

  • Inverted Index:随机对文档中的连续的k个单词(一个文档块)进行采样,并将它们与doc_id相关联

doc_id的表示

  • 非结构化的原子标识符:直接对所有的文档使用一个随机但互不相同的的整数标识。假设一共有N篇文档需要检索,假设原来解码器输出有V个单词,现在有V+N个单词。

  • 朴素的结构化字符串标识符:也使用一个随机的整数,但将这个整数当做一个字符串输出,用受限的beam search搜索前k个文档,因为需要保证输出的是数字

  • 语义结构化的标识符:先用BERT产出每个doc的emb,然后递归10-means,第一次得到0-9作为第1个数字,第二次的0-9作为第2个数字,可以得到一个树,文档的最终标识符就是从根节点到当前结点的路径对应的编号组合。只要一个节点的文档数大于c=100c=100,就继续分裂,当叶子的文档数小于c时,每个文档随机分配一个1到c1c-1的id,拼到doc_id的最后。

训练方法

用seq2seq,即teacher forcing+交叉熵,有如下两种方式:

  • 先对indexing进行预训练(memorization),再进行将query映射为docid的微调

  • 用多任务的方式同时进行,两个任务用不同的标识符,这样做效果会好很多

后来有一篇Bridging the Gap Between Indexing and Retrieval for Differentiable Search Index with Query Generation,对应的github:https://github.com/ArvinZhuang/DSI-QG,他也同时尝试复现DSI:https://github.com/ArvinZhuang/DSI-transformers,主要有如下两个地方:

  • 准备数据,doc_id

class IndexingTrainDataset(Dataset):
    def __init__(
            self,
            path_to_data,
            max_length: int,
            cache_dir: str,
            tokenizer: PreTrainedTokenizer,
    ):
        self.train_data = datasets.load_dataset(
            'json',
            data_files=path_to_data,
            ignore_verifications=False,
            cache_dir=cache_dir
        )['train']

        self.max_length = max_length
        self.tokenizer = tokenizer
        self.total_len = len(self.train_data)


    def __len__(self):
        return self.total_len

    def __getitem__(self, item):
        data = self.train_data[item]

        input_ids = self.tokenizer(data['text'],
                                   return_tensors="pt",
                                   truncation='only_first',
                                   max_length=self.max_length).input_ids[0]
        return input_ids, str(data['text_id'])


@dataclass
class IndexingCollator(DataCollatorWithPadding):
    def __call__(self, features):
        input_ids = [{'input_ids': x[0]} for x in features]
        docids = [x[1] for x in features]
        inputs = super().__call__(input_ids)

        # label是doc_id
        labels = self.tokenizer(
            docids, padding="longest", return_tensors="pt"
        ).input_ids

        # replace padding token id's of the labels by -100 
        # according to https://huggingface.co/docs/transformers/model_doc/t5#training
        labels[labels == self.tokenizer.pad_token_id] = -100
        inputs['labels'] = labels
        return inputs
  • 训练和预测

class IndexingTrainer(Trainer):
    def __init__(self, restrict_decode_vocab, **kwds):
        super().__init__(**kwds)
        self.restrict_decode_vocab = restrict_decode_vocab

    def compute_loss(self, model, inputs, return_outputs=False):
        ## 输入文章,预测doc_id
        loss = model(input_ids=inputs['input_ids'], 
            attention_mask=inputs['attention_mask'], labels=inputs['labels']).loss
        if return_outputs:
            return loss, [None, None]  # fake outputs
        return loss

    def prediction_step(
            self,
            model: nn.Module,
            inputs: Dict[str, Union[torch.Tensor, Any]],
            prediction_loss_only: bool,
            ignore_keys: Optional[List[str]] = None,
    ) -> Tuple[Optional[torch.Tensor], Optional[torch.Tensor], Optional[torch.Tensor]]:
        model.eval()
        # eval_loss = super().prediction_step(model, inputs, True, ignore_keys)[0]
        with torch.no_grad():
            # greedy search
            doc_ids = model.generate(
                inputs['input_ids'].to(self.args.device),
                max_length=20,
                prefix_allowed_tokens_fn=self.restrict_decode_vocab,
                early_stopping=True,)
        return (None, doc_ids, inputs['labels'])
  • 对解码空间的限制:

    # docid generation constrain, we only generate integer docids.
    SPIECE_UNDERLINE = "_"
    INT_TOKEN_IDS = []
    for token, id in tokenizer.get_vocab().items():
        if token[0] == SPIECE_UNDERLINE:
            if token[1:].isdigit():
                INT_TOKEN_IDS.append(id)
        if token == SPIECE_UNDERLINE:
            INT_TOKEN_IDS.append(id)
        elif token.isdigit():
            INT_TOKEN_IDS.append(id)
    INT_TOKEN_IDS.append(tokenizer.eos_token_id)

    def restrict_decode_vocab(batch_idx, prefix_beam):
        return INT_TOKEN_IDS

vq-vae & rq-vae

vq-vae

Neural discrete representation learning

https://github.com/zalandoresearch/pytorch-vq-vae

用在推荐:

Learning Vector-Quantized Item Representation for Transferable Sequential Recommenders

https://github.com/RUCAIBox/VQ-Rec

rq-vae

Autoregressive Image Generation using Residual Quantization

TIGER

Recommender Systems with Generative Retrieval

序列推荐的一些paper:

这些方法都是学习item的向量,然后用MIPS去ANN,而TIGER(Transformer Index for GEnerative Recommenders)则是生成式地直接预测item的语义id

HSTU

如何评价Meta最新推荐论文: 生成式推荐打败深度分层架构推荐?

Actions Speak Louder than Words: Trillion-Parameter Sequential Transducers for Generative Recommendations

背景

大规模推荐系统依赖高基数(high cardinality)、异质特性(heterogeneous features),每天要处理上百亿用户行为数据。将推荐系统重新定义为生成模型框架内的序列转化任务,提出HSTU(Hierarchical Sequential Transduction Unit),专为高基数、非稳态的流式推荐数据设计。

  • 在公开数据集比基线NDCG+65.8%

  • 在8192的序列长度上的处理速度比基于flash attention2的transformer快5.3-15.2倍。

  • 1.5万亿(1.5 trillion)参数,线上ab测试指标+12.4%

Breaking the curse of quality saturation with user-centric ranking中提到了NCE(normalized cross-entropy)指标:

NCE(p,y)=CrossEntropy(p,y)Entropy(y)\operatorname{NCE}(p, y)=\frac{\operatorname{CrossEntropy}(p, y)}{\operatorname{Entropy}(y)}

可以发现,对于一个预训练好的模型来说,随着时间的变化,NCE的变化是很剧烈的,即数据分布是会漂移的,并不像nlp/cv一样有ground truth,所以传统推荐模型其实很难达到比较好的scaling能力。

需要克服的3个挑战:

  • 推荐系统中的特征缺少显式的结构。序列建模(bert4rec、S3-rec等)在小规模数据集上效果不错,但工业界则需要异构特征(高基数的id、交叉特征、统计特征、历史点击率等)。

  • 推荐系统使用十亿规模的动态词表,而nlp用的是10w的静态词表,要对上万候选进行target-aware操作(din、Cold等),训练和推理的代价很高。

  • 大规模序列模型的计算成本是瓶颈。GPT-3在300B token的数据集上用上千个GPU训练1-2个月,而在推荐场景一天就有十亿级的活跃用户和十亿级的候选进行交互,用户序列在极端情况下有近10w(Twin: Two- stage interest network for lifelong user behavior modeling in ctr prediction at kuaishou),所以推荐系统每天要处理的tokens数量甚至比语言模型1-2个月处理的数量要大几个数量级

本文将用户action看成一个新的模态,2个主要的insights:

  • 给定一个新的特征空间,核心的召回排序任务能被直接转换成生成式模型问题(序列直推任务,sequential transduction tasks)

  • 这种范式能够系统性地解决传统推荐中的特征冗余、计算冗余、推理冗余,提升效率

Sequential Transduction Tasks

transductive learning(直推式学习) vs inductive learning(归纳式学习)https://www.zhihu.com/question/68275921/answer/529156908

  • 归纳式学习:训练只使用训练集,不使用测试集,训出的模型对测试集做预测,如监督学习。

  • 直推式学习:训练时使用训练集,还使用测试集的特征,但不使用测试集的label,

异构特征的统一表示

  • 稀疏特征:itemid、类目、城市、语言、社区等

    • 先选出最长的时间序列作为主时间序列,例如用户的交互序列。

    • 剩下的特征随时间变化较慢,如关注作者的属性。对于连续出现的片段(consecutive segment),只保留最开始的入口,这样对于主时间序列而言,并不会增加太多的序列长度。

  • 数值型特征:这里指的是序列特征里每个item的统计特征,比如用户在时刻t对某个item的ctr。直接删了,因为DIN里提到随着序列长度增加,target-aware的序列建模方式能够捕捉到这种数值性特征

假设用户消费了9个item,

  • 绿色的有7个时间步,全保留,作为主序列;

  • 蓝色的有7个时间步,但只有G0和G1两种取值,所以对于连续的G0只保留第0个(出现在t1),扔到主序列的最前面去,连续的G1也只保留第0个(出现在t8),插到主序列最后一个的前面

  • 黄色的全是H0,第0个出现在t7,所以保留t7,往主序列t8前面插入

  • 将数值型特征替换为target-aware的cross attention得到causal-masked的特征

  • 通过t0、t1、t2(包括t2)的特征生成t2的样本,以此类推

召回和排序的重定义

输入token序列x0,x1,,xn1x_0, x_1, \ldots, x_{n-1},输出的token序列y0,y1,,yn1y_0, y_1, \ldots, y_{n-1}是通过mask序列m0,m1,,mn1(mi{0,1})m_0, m_1, \ldots, m_{n-1}\left(m_i \in\{0,1\}\right)得到的。

token对应的动态、非稳态词表是X\mathbb{X},用户交互的内容是XcX\mathbb{X}_c \subseteq \mathbb{X}

  • 召回:预估p(xi+1ui)p\left(x_{i+1} \mid u_i\right),通过时间步i的用户特征预估xi+1Xcx_{i+1} \in \mathbb{X}_c,一般是直接选择argmaxxXcp(xui)\arg \max _{x \in \mathbb{X}_c} p\left(x \mid u_i\right)来最大化特定的reward,和标准的自回归有两个不同:

    • xi,yix_i,y_i的label并不一定是xi+1x_{i+1},因为用户可以对xi+1x_{i+1}是负反馈

    • yiy_i可能是比如人口属性等(因为是merge的序列,可能把城市之类的merge进来当做一个时间步),这个时候yiy_i未定义的,要把它mask掉,即mi=0m_i=0

  • 排序:推荐中的排序需要在尽量早的阶段进行target-aware的交互,而标准的自回归这种交互往往比较迟,例如在encoder的输出才用上了softmax。因此,设计了一种target-aware的cross-attention

    • 把action和x穿插起来得到新序列x0,a0,x1,a1,,xn1,an1x_0, a_0, x_1, a_1, \ldots, x_{n-1}, a_{n-1}

      • 对于action的位置,mi=0m_i=0

      • 对于content位置,使用一个小的nn将预估值转换成多任务的预估值(感觉是输入0-n,第n项保留xnx_n,mask掉ana_n,拿xnx_n去多目标地预估用户会用哪个action

生成式训练

假设用户iinin_i个token,那么训练的复杂度就是ini(ni2d+nidffd)\sum_i n_i\left(n_i^2 d+n_i d_{f f} d\right),其中:

  • ni2dn_i^2 d是self-attention的复杂度,通过flash attention可以达到O(n2)O(n^2)

  • nidffdn_i d_{f f} d是FFN的复杂度

  • 因为要自回归地算,可以理解为batch_size也是nin_i,加一个下三角的mask,所以在\sum里还要乘一个nin_i

假设N=maxiniN=\max _i n_i,那复杂度就是O(N3d+N2d2)O\left(N^3 d+N^2 d^2\right),太巨大了

但其实可以发现(这段是自己的理解),假设序列长度9,要预测第4个的时候,4-9的输入是mask掉的,但他们还是要进行后面的attention+ffn计算,其实是很浪费资源的,所以如上面“异构特征的统一表示”小节的那个图(生成主序列和辅助序列)所示,该模型直接只吐出x=x1-x3,y=x4作为训练样本就行了,这样既省掉了4-9的无用计算,也更便于并行(相比不拆batch的自回归)

假设采样第ii个用户的概率是su(ni)s_u\left(n_i\right),那么总的训练消耗就是

isu(ni)ni(ni2d+nid2)\sum_i s_u\left(n_i\right) n_i\left(n_i^2 d+n_i d^2\right)

如果设置su(ni)=1/nis_u\left(n_i\right)=1/n_i,那消耗就降到了O(N2d+Nd2)O\left(N^2 d+N d^2\right)。而在工业界中要实现这种采样其实很简单,在用户请求或者session结束的时候吐出训练样本就有su^(ni)1/ni\hat{s_u}\left(n_i\right) \propto 1 / n_i

生成式推荐中的高性能自注意力编码器

HSTU的单层包括3个部分:

pointwise projection:U(X),V(X),Q(X),K(X)=Split(ϕ1(f1(X)))\text{pointwise\ projection:} U(X), V(X), Q(X), K(X)=\operatorname{Split}\left(\phi_1\left(f_1(X)\right)\right)
spatial aggregation:A(X)V(X)=ϕ2(Q(X)K(X)T+rabp,t)V(X)\text{spatial\ aggregation:} A(X) V(X)=\phi_2\left(Q(X) K(X)^T+\operatorname{rab}^{p, t}\right) V(X)
pointwise transformation:Y(X)=f2(Norm(A(X)V(X))U(X))\text{pointwise\ transformation:} Y(X)=f_2(\operatorname{Norm}(A(X) V(X)) \odot U(X))

其中,

对应到代码(https://github.com/facebookresearch/generative-recommenders/blob/main/modeling/sequential/hstu.py)里:

self._linear_dim: int = linear_hidden_dim
self._uvqk = torch.nn.Parameter(
    torch.empty((embedding_dim, linear_hidden_dim * 2 * num_heads + 
        attention_dim * num_heads * 2)).normal_(mean=0, std=0.02),
)

##...

batched_mm_output = torch.mm(normed_x, self._uvqk)
if self._linear_activation == "silu":
    batched_mm_output = F.silu(batched_mm_output)
elif self._linear_activation == "none":
    batched_mm_output = batched_mm_output
# 其实就是先乘一个大矩阵,再拆成4份,等价于乘4个小矩阵
u, v, q, k = torch.split(
    batched_mm_output,
    [self._linear_dim * self._num_heads, self._linear_dim * self._num_heads, 
    self._attention_dim * self._num_heads, self._attention_dim * self._num_heads],
    dim=1,
)

if self._normalization == "rel_bias" or self._normalization == "hstu_rel_bias":
    if delta_x_offsets is not None:
        padded_q, padded_k = cached_q, cached_k
        flattened_offsets = delta_x_offsets[1] + torch.arange(start=0, end=B * n, 
            step=n, device=delta_x_offsets[1].device, dtype=delta_x_offsets[1].dtype)
        padded_q = padded_q.view(B * n, -1).index_copy_(
            dim=0, index=flattened_offsets, source=q,
        ).view(B, n, -1)
        padded_k = padded_k.view(B * n, -1).index_copy_(
            dim=0, index=flattened_offsets, source=k,
        ).view(B, n, -1)
    else:
        padded_q = torch.ops.fbgemm.jagged_to_padded_dense(
            values=q, offsets=[x_offsets], max_lengths=[n], padding_value=0.0
        )
        padded_k = torch.ops.fbgemm.jagged_to_padded_dense(
            values=k, offsets=[x_offsets], max_lengths=[n], padding_value=0.0
        )

    qk_attn = torch.einsum(
        "bnhd,bmhd->bhnm",
        padded_q.view(B, n, self._num_heads, self._attention_dim),
        padded_k.view(B, n, self._num_heads, self._attention_dim),
    )
    if all_timestamps is not None:
        qk_attn = qk_attn + self._rel_attn_bias(all_timestamps).unsqueeze(1)
    qk_attn = F.silu(qk_attn) / n
    qk_attn = qk_attn * invalid_attn_mask.unsqueeze(0).unsqueeze(0)
    attn_output = torch.ops.fbgemm.dense_to_jagged(
        torch.einsum(
            "bhnm,bmhd->bnhd",
            qk_attn,
            torch.ops.fbgemm.jagged_to_padded_dense(v, [x_offsets], [n]).\
                reshape(B, n, self._num_heads, self._linear_dim)
        ).reshape(B, n, self._num_heads * self._linear_dim),
        [x_offsets],
    )[0]

DLRM的3部分:

  • 特征抽取:常见的基础版本是离散特征pooling,高级版本是din。HSTU本来就能做这种target-aware的attention

  • 特征交互:常见的使用FMs、DCNv2、DHEN(DHEN: A Deep and Hierarchical Ensemble Network for Large-Scale Click-Through Rate Prediction,引入残差连接)。HSTU通过Norm(A(X)V(X))U(X)\operatorname{Norm}(A(X) V(X)) \odot U(X)来实现,将attention pooled后的结果直接和其他特征算element-wise product。

    • 这个做法受Neural collaborative filtering vs. matrix factorization revisitedRevisiting neural retrieval on accelerators的启发,用MLP来近似点积是很困难的。原因大概是nn需要调超参和足够的训练数据,在线算得又慢,而且本来内积效果就不错了,nn能带来的边际收益其实不明确。

    • 因为U(X)U(X)已经用过SiLU了,所以Norm(A(X)V(X))U(X)\operatorname{Norm}(A(X) V(X)) \odot U(X)可以看成是SwiGLU的变种(参考Glu variants improve transformer),因为前面在对比LLM激活函数时讲了,SwiGLU(x1,x2)=Swish(x1)x2\operatorname{SwiGLU}\left(\mathbf{x}_1, \mathbf{x}_2\right)=\operatorname{Swish}\left(\mathbf{x}_1\right) \odot \mathbf{x}_2

  • 表示转换:常见的如MoE、PLE等,主要思想就是对不同人群用特定的子网络。HSTU里的element-wise product也能达到MoE中的门控操作,只是可能有一个正则化因子的区别。

其实就是原来一般会拆成attention+ffn,而它这3个公式,前两个是attention,第3个就是attention求个norm,然后过一个swiglu的ffn,还有一点,这里的U(x)U(x)是过attention之前的,感觉起到了类似resnet的作用

pointwise聚合的注意力

用的是pointwise聚合的注意力,而不是transformer里的softmax,主要有如下两点考虑:

  • 推荐中item的强度信息很重要,softmax会让这种强度失真,导致在预估(如时长)不准;如果只需要预估序,那其实softmax也可以,但推荐要同时预估序和值,所以要删掉softmax。

  • 虽然softmax对噪声有鲁棒性,但不太适用于流式setting下的非稳态词表。做了一个模拟流式数据的实验,发现只去掉relative attention bias比relative attention bias并加上softmax会好得多

ArchitectureHR @10HR @50

Transformers

.0442

.2025

HSTU (rabp,t-rab^{p,t}, Softmax)

.0617

.2496

HSTU (rabp,t-rab^{p,t})

.0893

.3170

增加稀疏性

使用了一种高效的attention kernel的GPU算子,类似FlashAttention,能够将融合连续的矩阵操作(fuse back-to-back GEMMs),但能够 进行fully raggified(可能是不规则,即序列长度可变的??)的attention计算,本质是将attention计算转换为不同大小的分组GEMMs。因此,HSTU变成了memory-bound,并且能够以Θ(ini2dqk2R1)\Theta\left(\sum_i n_i^2 d_{q k}^2 R^{-1}\right)进行scale,其中,nin_i是样本ii的序列长度,dqkd_{qk}是attention的维度,RR是寄存器的大小。

Deep networks with stochastic depth启发,提出了SL(stochastic length)来增加用户历史序列的稀疏性,推荐系统中的用户行为往往有周期性,并且以不同形式呈现,因此引入稀疏性可以在效果不怎么损失的情况下显著减少encoder的代价,可以scale为Θ(ini2)\Theta\left(\sum_i n_i^2\right)

定义Γ(n,L)\Gamma(n, L)为一个函数,从原序列x0,,xn1x_0, \ldots, x_{n-1}中选出长度为LL的子序列,具体方案如下:

x0,,xni1 if niNα/2Γ(ni,Nα/2) if ni>Nα/2, w/ probability 1Nα/ni2x0,,xni1 if ni>Nα/2, w/ probability Nα/ni2\begin{aligned} & x_0, \ldots, x_{n_i-1} \text { if } n_i \leq N^{\alpha / 2} \\ & \Gamma\left(n_i, N^{\alpha / 2}\right) \text { if } n_i>N^{\alpha / 2}, \text { w/ probability } 1-N^\alpha / n_i^2 \\ & x_0, \ldots, x_{n_i-1} \text { if } n_i>N^{\alpha / 2}, \text { w/ probability } N^\alpha / n_i^2 \\ & \end{aligned}

即:

  • niNα/2n_i \leq N^{\alpha / 2}时,保留原始序列

  • ni>Nα/2n_i>N^{\alpha / 2}时,有Nα/ni2<1N^\alpha / n_i^2 < 1

    • 1Nα/ni21-N^\alpha / n_i^2的概率只保留Nα/2N^{\alpha / 2}长度的子序列

    • Nα/ni2N^\alpha / n_i^2的概率保留原始序列

对于α(1,2]\alpha \in(1,2],原来的attention相关的复杂度是O(N2d)O\left(N^2 d\right),现在可以降低到O(Nα/22d)=O(Nαd)O\left({N^{\alpha /2}}^2 d\right)=O\left(N^\alpha d\right)

其中的Γ(n,L)\Gamma(n, L)经过离线实验(原文附录D里),采用了feature-weighted sampler,即以1fn,i/(j=1Lfj,i)1-f_{n, i} /\left(\sum_{j=1}^L f_{j, i}\right)的概率进行采样,其中fi=tntif_i=t_n-t_i表示用户和item xix_i交互的时间和当前的时间差。

对稀疏性的改善如下,其中稀疏性指的是1avg_seq_len/max_seq_len1-avg\_seq\_len/max\_seq\_len,越大表示短序列越多,即越稀疏(α=2\alpha=2表示不SL,即直接使用原序列):

Alpha (α\alpha)

seq_len=1,024

seq_len=2,048

seq_len=4,096

seq_len=8,192

1.6

71.5%

76.1%

80.5%

84.4%

1.7

56.1%

63.6%

69.8%

75.6%

1.8

40.2%

45.3%

54.1%

66.4%

1.9

17.2%

21.0%

36.3%

64.1%

2.0

3.1%

6.6%

29.1%

64.1%

最小化激活值的内存使用

在推荐系统中,大的batchsize很重要:

因此激活函数的内存占用就成为了主要的scaling瓶颈,这一点和llm不一样,llm一般是用小batchsize,并且内存主要由网络参数占据。HSTU设计了如下方式来减少激活函数的内存占用:

假设dd是embed size,hh是head数,dqkd_{q k}是attention的dim,dffd_{ff}是ffn的hidden size,

  • 将一些计算融合成一个op,包括ϕ1(f1())\phi_1\left(f_1(\cdot)\right)、layer_norm、optional dropout和输出MLP,将每一层的激活的内存占用减小到了2d+2d+4hdqk+4hdv+2hdv=14d2 d+2 d+4 h d_{q k}+4 h d_v+2 h d_v=14 d(以bf16计算,一个参数2字节)---没懂

自己的理解:layer_norm要存均值+方差,所以要2d×2bytes2d\times 2bytes,所以上面式子就是,U(2d2d),V(2d2d),Q和K(4hdqk4hd_{qk}),QKV的norm(因为有均值和方差,所以是4hdv4hd_v),QKV(2hdv2hd_v)

对比transformer,在attention后用了ffn和dropout,假设中间状态是3hdv3hd_v,那么ffn包括layer_norm、linear、激活、linear、dropout,中间状态占用的就是2d+4dff+2d+1d=4d+4dff2 d+4 d_{f f}+2 d+1 d=4 d+4 d_{f f},一般来说,hdvdh d_v \geq ddff=4dd_{f f}=4 d

自己的理解:输入x(2d2d),linear(2dff2d_{ff}),linear(2d2d),dropout(约等于1d1d),layernorm一般是发生在最开始吧,所以应该是第一个2d2d改成4d4d吧,感觉不是在linear那里变成4dff4d_{ff}。。

然后,加上输入的input和input的layer_norm(4d4d),和qkv的映射,总的激活状态是33d33d---没懂

所以HSTU的设计能够让scaling达到大于两倍的更深的layers(14d vs 33d)

此外,词表中的id占用了极大的内存,对于10b的词表,512维的emb,Adam优化器,用fp32来存储emb和优化器状态要60TB的内存,因此,

cost-amortization(摊销)的预估scale up

对于召回来说,已经有很多加速方法了,例如MIPS的ANN加速,或者OTM等的beam search方法。

对于排序而言,提出了M-FALCON(Microbatched-Fast Attention Leveraging Cacheable OperatioNs),用于对mm个候选,序列长度为nn的输入进行预估

  • 并行计算bmb_m个候选,修改attention masks和rabp,trab^{p,t} bias,使得这bmb_m个候选的attention操作是完全一样的。从而将cross-attention的计算从O(bmn2d)O\left(b_m n^2 d\right)缩减到了O((n+bm)2d)=O(n2d)O\left(\left(n+b_m\right)^2 d\right)=O(n^2d),因为bmb_m相比nn要小得多

  • (可选)将mm个候选分成m/bm\left\lceil m / b_m\right\rceil个microbatches,每个batch有bmb_m个候选,从而在如下两个场合利用KV caching(Efficiently scaling transformer inference):

    • 前向pass中,用于降低消耗

    • requests之间,降低长尾耗时

其他

发现了scaling-law:

Wukong

Wukong: Towards a Scaling Law for Large-Scale Recommendation

P5

Recommendation as Language Processing (RLP):A Unified Pretrain, Personalized Prompt & Predict Paradigm (P5)

llm vs ID

推荐系统范式之争,LLM vs. ID?

Exploring the Upper Limits of Text-Based Collaborative Filtering Using Large Language Models: Discoveries and Insights

知乎的讨论

SIGIR2023 | ID vs 模态: 推荐系统ID范式有望被颠覆?

Where to Go Next for Recommender Systems? ID- vs. Modality-based Recommender Models Revisited

https://github.com/westlake-repl/IDvs.MoRec

对应的ppt

agent4rec

On Generative Agents in Recommendation

word版的笔记:https://github.com/daiwk/collections/blob/master/assets/multi-agents.docx

https://github.com/LehengTHU/Agent4Rec

拿推荐语料微调LLM

谷歌: 利用推荐知识对齐大语言模型

Aligning Large Language Models with Recommendation Knowledge

快手的LEARN

https://zhuanlan.zhihu.com/p/705497209

Knowledge Adaptation from Large Language Model to Recommendation for Practical Industrial Application

过往的llm+推荐的两种思路:

上面两种方法可以看成是Rec-to-LLM,即将推荐这个target domain适配到LLM这个source domain上去,有如下缺点:

  • 将用户历史全丢给LLM不现实:一方面开源的LLM目前只支持1k(baichuan)-4k(llama),不支持这么长的序列,另一方面复杂度和序列长度呈二次关系

  • 微调的方案可能会出现灾难性遗忘(catastrophic forgetting):全参数微调,会让模型丢失在预训练过程中学到的开放世界的知识,而LoRA的效果也不好。原因:

    • domain gap:两个领域有巨大的差别(profound gap),Continual Learning of Large Language Models: A Comprehensive Survey发现了全量参数微调会导致LLM对原有知识domain的严重的灾难性遗忘。

    • 训练目标不对齐(misalignment):LLM是next token prediction,学习大语料的general知识;finetune则主要是检索类的任务,强依赖用户-item的交互行为

本文提出了LEARN(Llm-driven knowlEdge Adaptive RecommeNdation),实现了LLM-to-Rec,让LLM作为content extractor,推荐任务是训练目标

ACL2024的recgpt

RecGPT: Generative Pre-training for Text-based Recommendation

快手的recgpt

RecGPT: Generative Personalized Prompts for Sequential Recommendation via ChatGPT Training Paradigm

https://zhuanlan.zhihu.com/p/699985083

蚂蚁的SLIM

蚂蚁集团在大模型推荐上的算法和应用

Can Small Language Models be Good Reasoners for Sequential Recommendation?

  • 第一阶段:蒸馏大型 GPT模型到较小的模型(如LLAMA2/3),来增强推理能力。

    • 通过预设的 prompt,大模型生成推荐理由,这些理由基于预定义的模板。接着,

    • 使用简化的推理模板请求小模型进行推荐和理由生成。

  • 第二阶段:利用生成式Loss来微调小模型,使其具备推理能力。

    • 模型训练完成,将通过prompt为用户行为提供T+1推理。

    • 推理结果通过文本编码器(Text Encoder)转化为表征,这些表征将直接应用于线上模型。

接下来,希望将LLAMA进一步压缩至更小的序列模型。在实验中遇到几个挑战:

  • 蒸馏过程中教师模型的知识可靠性存疑

  • 从语言模型到序列模型的蒸馏跨越了不同的模型类型,带来两个主要问题:

    • 参数差距大,学生模型难以容纳教师模型的知识

    • 语义不一致,因为序列模型与原始语言模型之间存在天然差异

参考Distillation Matters: Empowering Sequential Recommenders to Match the Performance of Large Language Models

包含两个关键部分:基于Ranking的蒸馏策略(Importance-aware Ranking Distillation)和Embedding对齐(Collaborative Embedding Distillation)

核心在于排名蒸馏,采取了如下三个策略

  • 选择LLAMA2作为教师模型,认为其排名靠前的分值更高;

  • 考虑LLM生成的描述与目标物品(Target Item)的接近程度,增加其排名;

  • 若教师模型(Teacher Model)认为某物品是优质且排名靠前的,学生模型(Student Model)也会给予其更高排名。

通过这些策略,设计了Ranking Loss,用于蒸馏小型序列模型

Ld=sΓiOTwsilogσ(y^si)\mathcal{L}_d=-\sum_{s \in \Gamma} \sum_{i \in O^T} w_{s i} \log \sigma\left(\hat{y}_{s i}\right)

其中,OTO^T是teacher返回的topk结果,Γ\Gamma是训练集的序列数,wsi=γpwsip+γcwsic+γowsiow_{\mathrm{s} i}=\gamma_p \cdot w_{\mathrm{s} i}^p+\gamma_c \cdot w_{\mathrm{s} i}^c+\gamma_o \cdot w_{\mathrm{s} i}^o,包括如下3部分:

  • position-aware weight:wsipexp(ri/β)w_{\mathrm{s} i}^p \propto \exp \left(-r_i / \beta\right)rir_i是item ii在teacher返回结果里的排名,β\beta是一个超参

  • confidence-aware weight:wsicexp(dsi/β)w_{\mathrm{s} i}^c \propto \exp \left(-d_{\mathrm{s} i^*} / \beta\right),且dsi=zdszi2d_{\mathbf{s} i^*}=\left\|\mathbf{z}_{d_{\mathrm{s}}}-\mathrm{z}_{i^*}\right\|^2zds\mathbf{z}_{d_{\mathrm{s}}}是生成的item描述,zi\mathrm{z}_{i^*}是ground truth的item描述,分别通过一个llm encoder得到向量

  • consistency-aware weight:同时被teacher和student推荐的item更有可能是一个强正例

wsio={1,iOTOS0,iOTOSw_{\mathrm{s} i}^o= \begin{cases}1, & i \in O^T \cap O^S \\ 0, & i \notin O^T \cap O^S\end{cases}

推荐生态系统

Modeling Recommender Ecosystems: Research Challenges at the Intersection of Mechanism Design, Reinforcement Learning and Generative Models

发现性

Diversifying by Intent in Recommender Systems,涨了dau等指标

ILM

Item-Language Model for Conversational Recommendation

适用场景如下,{user}可以看成一种特殊的{item},{history}是若干个item

参考BLIP-2(Blip-2: bootstrapping language-image pre-training with frozen image encoders and large language models)提出的Q-former:

引入了Q-former

  • phase1:表示学习,交替训练如下两类表示学习

    • item-text表示学习:

      • query的tokens和item的cf emb过cross attn后,拿cls的输出得到v1

      • text过attn得到v2

      • v1和v2算item-text对比学习

      • v2走一个自回归的任务(item grounded text generation)

    • item-item表示学习

      • query的tokens和item的cf emb过cross attn后,拿cls的输出得到v1

      • query的tokens和item的cf emb过cross attn后,拿cls的输出得到v2

      • v1和v2算item-item的对比学习

  • phase2:item-language model训练

    • Q-former的item encoder经过一个linear输入到LLM中

    • LLM参数freeze,只tune Q-former的参数和linear

其他

WWW 2024 | 工业界大模型在搜广推场景应用

LLM+Recommendation大模型推荐近期进展|含WWW, SIGIR, AAAI等顶会文章

ClickPrompt: CTR Models are Strong Prompt Generators for Adapting Language Models to CTR Prediction

SIGIR'24 | 打破长度障碍:LLM增强的长文本用户行为CTR预测

Breaking the Length Barrier: LLM-Enhanced CTR Prediction in Long Textual User Behaviors

LLM落地淘宝电商搜索场景,显著提升长尾query改写效果

Large Language Model based Long-tail Query Rewriting in Taobao Search

recsys23的Leveraging Large Language Models for Sequential Recommendation 还有一篇Improving Sequential Recommendations with LLMs,对应的代码:https://github.com/dh-r/LLM-Sequential-Recommendation/tree/RecSys23

meta发的LLM-Rec: Personalized Recommendation via Prompting Large Language Models

生成式推荐系统近期研究工作梳理

time-LLM

谁说大象不能起舞! 重编程大语言模型实现跨模态交互的时序预测 | ICLR 2024

Time-LLM: Time Series Forecasting by Reprogramming Large Language Models

https://github.com/KimMeen/Time-LLM

时序预测任务转换成一个可以由 LLMs 有效解决的语言任务,成功激活了llm做高精度时序推理的能力。

  • 时序输入重编程

  • 提示做前缀

NoteLLM

WWW'24 | 小红书NoteLLM: 大语言模型用于I2I笔记推荐

NoteLLM: A Retrievable Large Language Model for Note Recommendation

3个任务:

  • I2I笔记推荐任务: 给定目标笔记,基于LLM从内容池中找出top-k个相似笔记。

  • 主题标签生成任务:基于笔记的标题和笔记的内容, 使用LLM生成对应的k个主题标签。

  • 类目生成任务:基于笔记的标题,内容,主题标签使用LLM生成对应的类目。

笔记压缩prompt:

[bos]<instruction><input notes>The compression word is:"[EMB]".<output guidance><output>[eos]

其中的[EMB]是一个特殊token,

生成式对比学习

生成式对比学习(Generative-Contrastive Learning,GCL)

  • 通过统计共现信息,同时打压热门,得到item pair对

  • 由于LLMs的自回归特性, 将[EMB]的前一个token对应的最后一个隐层输出经过一个linear layer得到一个d维向量

对于batchsize=B的batch来说,有B个pair对,即2B个item,那么对它们算一个对比学习的loss,其中的sim是cos相似度:

Lcl=12Bi=12Blogesim(ni,ni+)eτj[2B]\{i}esim(ni,nj)eτL_{c l}=-\frac{1}{2 B} \sum_{i=1}^{2 B} \log \frac{e^{\operatorname{sim}\left(\boldsymbol{n}_i, \boldsymbol{n}_i^{+}\right) \cdot e^\tau}}{\sum_{j \in[2 B] \backslash\{i\}} e^{\operatorname{sim}\left(\boldsymbol{n}_i, \boldsymbol{n}_j\right) \cdot e^\tau}}

协同监督微调

协同监督微调(Collaborative Supervised Fine-Tuning,CSFT)将主题标签生成任务和类目生成任务联合训练,一个batch里40%的样本执行主题标签生成任务,剩下的60%做类目预测任务,然后走正常的语言模型自回归任务:

Lgen=1Ti=1Tlog(p(oio<i,input))L_{g e n}=-\frac{1}{T} \sum_{i=1}^T \log \left(p\left(o_i \mid o_{<i}, input\right)\right)

然后将这两个loss加权求和(α=0.01\alpha = 0.01):

L=Lcl+αLgen1+α,L=\frac{L_{c l}+\alpha L_{g e n}}{1+\alpha},

世界模型

怒斥Sora之后,LeCun放出「视觉世界模型」论文,揭示AI学习物理世界的关键​

100万token,一次能分析1小时YouTube视频,「大世界模型」火了

WORLD MODEL ON MILLION-LENGTH VIDEO AND LANGUAGE WITH RINGATTENTION

https://github.com/LargeWorldModel/LWM

Sora是世界模拟器吗?全球首篇综述全面解析通用世界模型

Is Sora a World Simulator? A Comprehensive Survey on General World Models and Beyond

世界模型也扩散!训练出的智能体竟然不错

Diffusion for World Modeling: Visual Details Matter in Atari

https://github.com/eloialonso/diamond

LLM的不足

语言≠思维,大模型学不了推理:一篇Nature让AI社区炸锅了

https://www.nature.com/articles/s41586-024-07522-w

pandora

通用世界模型问世:不学习就能生成新领域视频,可实时控制

Pandora : Towards General World Model with Natural Language Actions and Video States

https://github.com/maitrix-org/Pandora

ACL 2024论文盖棺定论:大语言模型≠世界模拟器,Yann LeCun:太对了

Can Language Models Serve as Text-Based World Simulators?

Q*

这就是OpenAI神秘的Q*?斯坦福:语言模型就是Q函数

From r to Q*: Your Language Model is Secretly a Q-Function

OpenAI秘密武器「草莓」计划曝光!Q*推理能力大爆发,逼近AGI L2里程碑

5级路线图:

  • L1:聊天机器人,具有对话能力的AI。

  • L2:推理者,像人类一样能够解决问题的AI。

  • L3:智能体,不仅能思考,还可以采取行动的AI系统。

  • L4:创新者,能够协助发明创造的AI。

  • L5:组织者,可以完成组织工作的AI。

Strawberry模型的目的是为了使公司的AI不仅能生成查询答案,还能提前计划,足够自主且可靠地浏览互联网,进行OpenAI所称的「深度研究」。

类似Star: Self-taught reasoner bootstrapping reasoning with reasoning能够通过迭代创建自己的训练数据,来「自我提升」到更高的智能水平。

LLM+其他

【LLM-数学】MathScale 用于数学推理的指令调优扩展方法

MathScale: Scaling Instruction Tuning for Mathematical Reasoning

清华包揽最佳论文+时间检验奖,山大获荣誉提名,SIGIR 2024奖项出炉

SIGIR24最佳论文:Scaling Laws For Dense Retrieval

LLM常见难题

重复生成

https://www.zhihu.com/question/616130636

https://mp.weixin.qq.com/s/cSwWapqFhxu9zafzPUeVEw

幻觉

综述

OpenAI Lilian Weng万字长文解读LLM幻觉:从理解到克服

https://lilianweng.github.io/posts/2024-07-07-hallucination/

语义熵

语义熵识破LLM幻觉!牛津大学新研究登Nature

Detecting hallucinations in large language models using semantic entropy

知识冲突

深度解析RAG大模型知识冲突,清华西湖大学港中文联合发布

Knowledge Conflicts for LLMs: A Survey

llm+db

长文本杀不死RAG:SQL+向量驱动大模型和大数据新范式,MyScale AI数据库正式开源

https://github.com/myscale/myscaledb

记忆能力

Localizing Paragraph Memorization in Language Models

对应代码:https://github.com/googleinterns/localizing-paragraph-memorization

我们能否定位出语言模型中用于记忆其训练数据中整段文字的权重和机制?

  • 尽管记忆现象分布在模型的多个层级和组件中,但记忆段落的梯度在空间上有可辨别的模式,即在较低模型层级的梯度比非记忆example的梯度大

  • 通过仅微调高梯度的权重,可以使模型遗忘记忆的example

  • 定位了一个特别参与段落记忆的低层注意力头,它主要关注在语料库级单词频率分布中最不频繁出现的独特、罕见的token

  • 总的来说,相较非记忆的续写,记忆续写不仅更难以遗忘,也更难以损坏

reasoning

Reasoning or Reciting? Exploring the Capabilities and Limitations of Language Models Through Counterfactual Tasks MIT的

Do Large Language Models Latently Perform Multi-Hop Reasoning? deepmind的

How do Language Models Bind Entities in Context? UC berkeley的,ICLR2024

memorizing

Knowledge Neurons in Pretrained Transformers ACL 2022

Language Modeling Is Compression ICLR 2024 deepmind

Memorization Without Overfitting: Analyzing the Training Dynamics of Large Language Models meta NeurIPS 2022

越狱

长文本之罪:Claude团队新越狱技术,Llama 2到GPT-4无一幸免

LLM+math

ICML 2024|Transformer究竟如何推理?基于样例还是基于规则

Case-Based or Rule-Based: How Do Transformers Do the Math?

https://github.com/GraphPKU/Case_or_Rule

LLM compiler

开发者狂喜!Meta最新发布的LLM Compiler,实现77%自动调优效率

Meta Large Language Model Compiler: Foundation Models of Compiler Optimization

ProLong

2024 年了,你的长文本训练数据真的够长吗?

Long Context is Not Long at All: A Prospector of Long-Dependency Data for Large Language Models

https://github.com/October2001/ProLong

白化

在 transformer 领域里,“白化”(whitening)主要是指一种对句子嵌入进行后处理的方法,通过将句子向量的均值变为0,并将协方差矩阵变为单位矩阵,从而解决句子嵌入中的各向异性问题。这种技术能够提高句子嵌入在语义相似性任务中的表现,并且加快检索速度。

Whitening Sentence Representations for Better Semantics and Faster Retrieval

Transformer Scale Gate for Semantic Segmentation

蒸馏

Revisiting Knowledge Distillation for Autoregressive Language Models

Meta开发System 2蒸馏技术,Llama 2对话模型任务准确率接近100%

Distilling System 2 into System 1

自动搜参

用神经架构搜索给LLM瘦身,模型变小,准确度有时反而更高

LLaMA-NAS: Efficient Neural Architecture Search for Large Language Models

证明者-验证者博弈

OpenAI超级对齐团队遗作:两个大模型博弈一番,输出更好懂了

Prover-Verifier Games improve legibility of LLM outputs

参考:Learning to Give Checkable Answers with Prover-Verifier Games

多智能体

《综述:全新大语言模型驱动的Agent》——4.5万字详细解读复旦NLP和米哈游最新Agent Survey

Agent > GPT5?吴恩达最新演讲:四种 Agent 设计范式(通俗易懂版)

JAT

告别偏科,能玩转多模态、多任务、多领域的强化智能体终于来了

Jack of All Trades, Master of Some, a Multi-Purpose Transformer Agent

https://github.com/huggingface/jat

https://huggingface.co/datasets/jat-project/jat-dataset

输入的序列元素是observations, actions, 和rewards的交替组合:

[ϕ(s0,0.0),ϕ(a0),ϕ(s1,r1),ϕ(a1),]\left[\phi\left(s_0, 0.0\right), \phi\left(a_0\right), \phi\left(s_1, r_1\right), \phi\left(a_1\right), \ldots\right]

依据不同输入的数据类型,使用不同网络处理:

  • 图像:用CNN。

  • 连续向量:用线性层

  • 离散值:用线性投影层

预测任务:根据所有先前的观察和动作嵌入来预测下一个动作嵌入。

序列的构造方法:

  • 和文本相关的任务:用 GPT-2 的分词策略,将文本转换为一个整数序列,然后emb lookup映射到一个嵌入向量序列。

  • 和图像有关的任务:用ViT,将图像切割成小块后,通过线性层转换为嵌入向量序列。

  • 最终再将图像和文本的向量序列拼接在一起,形成一个统一的序列,输入到 Transformer 中。

ReadAgent

「有效上下文」提升20倍!DeepMind发布ReadAgent框架

多模态agent

一文详解多模态智能体(LMAs)最新进展(核心组件/分类/评估/应用)

Large Multimodal Agents: A Survey

https://github.com/jun0wanan/awesome-large-multimodal-agents

一些其他比较重要的工作

几篇出现频率比较高的论文

Scaling instruction-finetuned language models 引用数800+

How can we know what language models know? 引用数800+

Chain of thought prompting elicits reasoning in large language models引用1800+

Anthropic的一些工作

Training a Helpful and Harmless Assistant with Reinforcement Learning from Human Feedback

Studying Large Language Model Generalization with Influence Functions

Measuring Faithfulness in Chain-of-Thought Reasoning

从Claude 3中提取数百万特征,首次详细理解大模型的「思维」

Scaling Dictionary Learning to Claude 3 Sonnet

LLM惊现篡改代码获得奖励,欺骗人类无法根除逆转!Anthropic新作揭露惊人真相

SYCOPHANCY TO SUBTERFUGE: INVESTIGATING REWARD TAMPERING IN LANGUAGE MODELS

个性化搜索

随便找一篇Denoising Attention for Query-aware User Modeling in Personalized Search,来看看它的参考文献:

学术界:

工业界:

q-i双塔的改进

引入location+social

Embedding-based Retrieval in Facebook Search,KDD20

q-d双塔结构,在两个塔的最底层均加入:

  • location:用户所处地理位置,如城市

  • social:facebook是社交网络,通过另一个基于graph的模型训练得到的user和item emb,直接加进来

引入用户行为序列

Encoding History with Context-aware Representation Learning for Personalized Search,sigir20,人大,提出HTPS

把用户历史的q-d pair对和当前query一起,过短期transformer和长期transformer得到输出qlq^l

qlq^l加上[mask],过transoformer得到预估的intent qpq^p

然后将qlq^lqpq^p通过gate nn融合得到最终的context-aware的query表示qfq^f

最终doc和query的打分包括两部分,通过ϕ\phi(一个MLP,激活是tanh)进行融合:

p(dq,H)=ϕ(p(d,q),p(d,qH))p(d \mid q, H)=\phi\left(p(d, q), p\left(d, q^H\right)\right)
  • p(d,q)p(d, q):q和d的语义相似度,可以用正常的nlp模型得到

  • p(d,qH)p\left(d, q^H\right):q和d的个性化得分,公式如下,其中sRs^R是cos:

p(d,qH)=ϕ(sR(qs,dw),sR(ql,dw),sR(qp,dw),sR(qf,dw))p\left(d, q^H\right)=\phi\left(s^R\left(q^s, d^w\right), s^R\left(q^l, d^w\right), s^R\left(q^p, d^w\right), s^R\left(q^f, d^w\right)\right)

有两个loss:

  • pred loss:预估intent,即下一个query,拿qpq^p与下一个query中各个词向量的avg算cos

  • rank loss:依据p(dq,H)p(d \mid q, H)算lambda rank的pairwise loss

三塔+gnn邻居+mtl

A GNN-based Multi-task Learning Framework for Personalized Video Search,WSDM22,百度,提出MGNN-PVS

现有的PSM(g personalized search methods)大多使用用户反馈(如点击)进行训练,缺点:

  • 反馈信号大部分表达的是吸引力而非相关性

  • 用户的历史信号比较稀疏,很难学好PSM

两张二部图:u-q和q-d

3个塔:

  • user:

    • user自己

    • 一跳邻居(u->q)的q

    • 二跳邻居(u->q->u)的u

  • query:

    • query自己

    • 一跳邻居(q->d)的doc

    • 二跳邻居(q->d->q)的query

  • doc:

    • doc自己的title向量(训练query-正title-负title的triplet loss)和video向量(训练video-正query-负query的triplet loss)

    • 二跳邻居(d->q->d)的doc

两个task:

  • ctr预估:u和q拼一起过nn得到个性化的q,再和d过nn得到的向量算内积,得到预估值,用交叉熵

  • 相关性预估:q过另一个nn,d过另一个nn,内积,用mse

RAG

Retrieval-Augmented Generation for Large Language Models: A Survey

RAG全链路的关键模块解析

Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks

Meta提出全新文档级嵌入框架,利用LLM来增强信息检索能力

LLM-Augmented Retrieval: Enhancing Retrieval Models Through Language Models and Doc-Level Embedding

RankRAG

RAG微调Llama 3竟超越GPT-4!英伟达GaTech华人学者提出RankRAG框架

RankRAG: Unifying Context Ranking with Retrieval-Augmented Generation in LLMs

graphRAG

微软开源的GraphRAG爆火,Github Star量破万,生成式AI进入知识图谱时代?

https://github.com/microsoft/graphrag

From Local to Global: A Graph RAG Approach to Query-Focused Summarization

LLM模型融合

https://github.com/arcee-ai/mergekit

SOLAR 10.7B: Scaling Large Language Models with Simple yet Effective Depth Up-Scaling

LLM 合并新思路:进化算法+零训练->新任务

Evolutionary Optimization of Model Merging Recipes

https://github.com/SakanaAI/evolutionary-model-merge

prompt engineering

万字长文总结提示词技巧!新加坡首届GPT-4提示工程大赛冠军最新分享

吴恩达:四个步骤,让大模型变得更好

Can Generalist Foundation Models Outcompete Special-Purpose Tuning? Case Study in Medicine

让gpt4生成cot和答案的模板

看着是借助GPT4+COT+RAG+投票

  • 拿一坨question得到他们的向量,并按照上图的模板让gpt生成COT和答案,人工判断,对的存进知识库里

  • 预测阶段:

    • 拿测试question的向量从知识库里查出5个最像(cos距离)的(q, cot, answer)作为context

    • 循环5次: shuffle测试question的答案选项,让LLM回答

    • 对生成的答案投票,选票数最多的

可解释AI

XAI有什么用?探索LLM时代利用可解释性的10种策略

Usable XAI: 10 Strategies Towards Exploiting Explainability in the LLM Era

https://github.com/JacksonWuxs/UsableXAI_LLM

TransformerLens

Neel Nanda(deepmind)的项目

https://transformerlensorg.github.io/TransformerLens/

ecco

https://www.eccox.io/

https://jalammar.github.io/explaining-transformers/

https://jalammar.github.io/hidden-states/

interpretability in the wild

Interpretability in the Wild: a Circuit for Indirect Object Identification in GPT-2 small

https://github.com/redwoodresearch/Easy-Transformer

activation engineering

Activation Addition: Steering Language Models Without Optimization

representation engineering

Representation Engineering: A Top-Down Approach to AI Transparency

transformer-debugger

https://github.com/openai/transformer-debugger/tree/main

LLM应用

autogpt

GitHub星标超16万,爆火AutoGPT进阶版来了:定制节点、多智能体协同

https://github.com/Significant-Gravitas/AutoGPT

其他

一些比较好的模型

文本匹配

大多是基于sentence-bert的,m3e-base在电商语料上试过,效果不错

https://huggingface.co/moka-ai/m3e-base

https://huggingface.co/shibing624/text2vec-base-chinese

本地知识库

https://github.com/chatchat-space/Langchain-Chatchat

llm应用合辑

swiftsage

大语言模型在开放世界中的推理能力探索实践

SwiftSage: A Generative Agent with Fast and Slow Thinking for Complex Interactive Tasks

达摩院大模型技术交流

https://developer.aliyun.com/live/248332

ppt:链接 密码:5yyf

回译

通过单语数据提升 NMT 模型最高效的方法之一是回译(back-translation)。如果我们的目标是训练一个英语到德语的翻译模型,那么可以首先训练一个从德语到英语的翻译模型,并利用该模型翻译所有的单语德语数据。然后基于原始的英语到德语数据,再加上新生成的数据,我们就能训练一个英语到德语的最终模型。

Understanding Back-Translation at Scale

nan问题

解决pytorch半精度amp训练nan问题

时间序列

LLM用于时序预测真的不行,连推理能力都没用到

Are Language Models Actually Useful for Time Series Forecasting?

其他

小模型性能饱和、表现不佳,根源是因为Softmax?

Why do small language models underperform? Studying LM Saturation via the Softmax Bottleneck

Ilya Sutskever的推荐清单

2024年大模型LLM还有哪些可研究的方向?

Hinton万字访谈:用更大模型「预测下一个词」值得全力以赴

ChatGPT如何「思考」?心理学和神经科学破解AI大模型,Nature发文

适应多形态多任务,最强开源机器人学习系统「八爪鱼」诞生

Octo: An Open-Source Generalist Robot Policy

LeCun新作:神经网络在实践中的灵活性到底有多大?

Just How Flexible are Neural Networks in Practice?

最后更新于