CVDL-Transformer

2025-05-28

CVDL

primitive:基本的结构单元(例如 cnn, 全连接, attention)

假如我们现在有输出的句子的当前隐藏状态 \(s_i\),那么对于输入序列的第 \(t\) 个时间步,用一个全连接层算出是一个 alignment score \(e_{i,t}=f(s_i,h_t)\),然后做 softmax 后得到 \(t\to i\) 的一个注意力,将所有 \(h\) 带权相加得一个综合的 \(c_{i}\). 然后将 \(y_i,c_i,s_i\) 三个再通过 RNN 得到 \(y_{i+1}\).

这巧妙地将 skip link 用到 seq2seq 问题上. 这个算注意力的 FC 不是通过监督学习的,而是因为整个过程是可微的所以直接反向传递得到.

将这个东西化做一个更加抽象的但更加底层的东西. \(h_t\) 为存储了数据的 data vector,而我们用 \(s_i\) 去找哪些 \(h_t\) 应该被注意,称为 query vector,最终得到 \(c_i\) 为 output vector.

将这个问题抽象出来,并且做一个化简:有维度为 \(D_q=D_x\) 的 query vector \(q\),维度为 \(N\times D_X\) 的 data vector \(X\),计算过程为计算出维度为 \(N_X\) 的 alignment score \(e_i=q\cdot X_i/\sqrt{D_X}\),然后求得注意力 \(a=softmax(e)\),然后算出 \(y=\sum a_iX_i\).

注意到我们把 \(f\) 优化掉了. \(f\) 本质可以看作求两个向量的相似程度,那么不妨用更简单的 cos similarity:\(\frac{a\cdot b}{|a||b|}\). 那么化到 \(e\) 上就是 \(q\cdot X_i/\sqrt{D_q}\).

但是注意到我们这里擅自把 \(D_Q=D_X\). 实际上并不是这样. 考虑引入一个 Key Matrix \(W_K\),大小为 \(D_X\times D_Q\),那么得到 \(N_X\times D_Q\)\(K=XW_K\). 于是得到 \(E=QK^{T}/\sqrt{D_Q}\),其中 \(E_{i,j}=Q_i\cdot K_j/\sqrt{D_Q}\). 然后做 softmax 过后得到 \(A\).

然后我们其实也可能希望输出的维数不一样,设为 \(D_V\),那么还是考虑引入 Value Matrix \(W_V\),大小为 \(D_X\times D_V\),那么得到 \(N_X\times D_V\)\(V=XW_V\). 然后就可以得到输出 \(Y=AV\).

这就是 cross-attention 机制,将两个不同的东西融合在了一起. 里面每个 cell 都对 data 有全局的 receptive field,而对 query 只能看到自己.

self attention:加入一个 \(W_Q\),并将 \(X\) 通过 \(XW_Q\) 来获得 \(Q\). 并同一一下 \(D_Q=D_V=D_{out}\),然后 \(D_x=D_{in}\).

我们发现这个东西输入为 \(N\times D_{in}\),并输出为 \(N\times D_{out}\). 其本质是新的,对一族 vector 进行了一次加工,其 receptive field 为全局.


考虑 cross-attetion,其对 data vector \(X\) 是 permutation invariance 的,而对于 query vector \(Q\) 是 permutation equivariance 的. 而对于 self-attention,则对 \(X\) 是 permutation invariance 的.

然后从某个角度讲,每个 query 生成 \(y\) 和 pointnet 有所相似性:每个东西内部做一个 FC 然后某种方式 pool 一下就好了.

当然这带来了一个问题. self attention 根本不知道序列的位置信息. 解决这个也很简单,搞一个位置函数,将位置 \(n\) 通过这个函数得到一个 positional embedding 然后 concat 到 \(X\) 上.

但是对于一个预测下一个词的任务,我们无法知道完整序列信息直接运用 self-attention.

于是引入 Masked self-attention Layer(Causal Mask,因果 mask,不能让未来的事情被过去的事情看到). 我们只需要在 所有 \(i<j\) 的地方强制 \(E_{i,j}=-\infty\),这样注意力就为 \(0\).

于是我们就得到了一个 RNN 的替代. 这相比于 RNN 来说,一个优势是 RNN 是 sequential 的,而上述的训练可以并行地训练!


Multiheaded Self Attention Layer:\(m\) 个独立的 attention 可以独立运作,形成 \(m\) 个 head,输出 \(m\)\(y\),然后再合并起来.

令输入维数=最终输出维数= \(D\) 维. 令 \(D_H=D/H\),每个 attention 都是 \(D_{H}\) 维的,然后 最后将 \(H\times N\times D_{H}\)\(Y\) 叠成 \(N\times D\) 的 size 之后有 output \(O=YW_{O}\).

Self Attention 本质上就是 四次矩阵乘法.

第一次矩阵乘法是 QKV Projoection,\([N\times D]\times [D\times 3HD_{H}]\) 得到 \(N\times 3HD_H\) 然后 split and reshape 之后 \(Q,K,V\).

第二次矩阵乘法是做 \(QK\) similarity,即计算 \(QK^{T}\).

第三次是作用上 \(V\). \([H\times N\times N][H\times N\times D_H]\to [H\times N\times D_H]\).

第四次则是最后做 \([N\times D][D\times D]\to [D\times D]\) 的 output projection.

多头注意力在计算上计算量并没有怎么减少,但是表达能力是更强的.

上述的一个问题就是需要存 \(N\times N\) 的大矩阵,memory 无法承受.

Flash Attention:将第二三步化作同一步,获得 \(O(N)\) 的存储复杂度. 这样就能加大 \(N\).


对比三种 process sequence 的方法:RNN 理论上是线性的可以处理比较长的东西,但是并不那么靠谱并且不并行化;而 CNN 要建立大 receptive field layer 要叠太多了;而 Self Attention 并行化并且有全局的 receptive field,但是复杂度很大,很贵.

Transformer:完全使用 Attention 搭网络.

Transformer Block:\(x\) 通过 multiheaded self attention 得到 \(y\),加 residual connection。然后做 Layer Normalization,这使得每个 token 的参数都对应相同的分布. 然后对于每个 vector 单独做 MLP(称为 FFN 层),然后加 residual connection,加 layer norm.

不同 token 间交流的时间只有 self-attention,而剩下的 layernorm 和 FFN 都是每个 token 单独完成的.

上面的计算只有来自 self-attention 的 4 个 MatMul,然后 FNN 有两个 MatMul. 很并行化.

online / offline processing:前者的任务需要 causal mask 而后者就不需要了. 训练和推理的时候 causal mask 必须同时用/不用.

处理语言任务的时候要学习一个 Embedding matrix(将词映成 vector) 和 Projection matrix(将 vector 映成词).


ViT:将图片切成若干个大小为 \(16\times 16\times 3\) 的 patches,然后每个 patch 提一个特征,然后 256 个 token 喂给 transformer. 对于提特征,由于图很小,所以直接 MLP 也没啥. 跑完之后做一个 global average pooling 然后过 linear layer 做 classification. 需要 positional embedding 以及不需要 causal mask.

一些改进:Pre-Norm. 在 residual link 之后做 norm 还是不是很好学到 identity function. 所以考虑如下的形式:把 layer norm 放到 self attention / MLP 之前,被 residual link 包裹. 这样训练更加稳定.

RMS Norm(Root Mean Square):要学一个 \(\gamma\),然后令 RMS 为 \(\sqrt{\frac{1}{n}\sum x_i^2+\epsilon}\),然后 \(y_i=\frac{x_i}{RMS}\gamma\). 这会使得最终的 RMS 为 \(\gamma\).

还有一个对 FFN 做优化的 SwiGLU.

MoE(混合专家模型). 考虑原本是一个 \(W_1=D\times 4D\)\(W_2=4D\times D\) 的矩阵,然后现在我们扩展成有 \(E\)\(W_1\)\(E\)\(W_2\). 每个 MLP 被称为 Expert. 然后每个 token 会被 route 到 \(A\) 个 Expert(\(A<E\)). 那么当参数量 \(E\) 增加了并不会增加计算量,而只有 \(A\) 会控制 Foward 的计算量. Routing 的学习挺困难的,因为是否选择由 Top-A 决定,这是不可导的.


参考讲义:Lecture 14 - Transformer