大语言模型技术相关知识-笔记整理

系列文章目录

这个系列攒了很久。主要是前段之间面试大语言模型方面的实习(被拷打太多次了),然后每天根据面试官的问题进行扩展和补充的这个笔记。内容来源主要来自视频、个人理解以及官方文档中的记录。方便后面的回顾。

2024-12-7: 对公式进行了重新编辑,更正了部分图片。


文章目录

  • 系列文章目录
  • 1 基本知识
    • 1. 1 归一化
      • (1)层归一化(LN)
      • (2)批量归一化(BN)
      • (3)均方根归一化RMSNorm
      • (4)DeepNorm
    • 1.2 归一化的位置
      • (1)Post-Norm(transformer)
      • (2)Pre-Norm
      • (3)Sandwish-Norm
      • 参考资料
    • 1.3 激活函数
      • (1)ReLU(Transformer,Rectified Linear Unit)
      • (2)Swish/silu激活函数和GELU激活函数 (Gaussian Error Linear Unit)
      • (3)GLU激活函数(Gated Linear Units)
      • (4)swiGLU激活函数(llama)
      • (5)tanh 激活函数
    • 1.4 位置编码
      • 1.4.1 绝对位置编码(Absolute Position Encoding)
        • (1)正余弦位置编码 (Transformer)
        • (2)可学习的嵌入表示(BERT)
      • 1.4.2 相对位置编码(Relative Position Encoding)
      • (1)旋转位置编码(Rotary Position Encoding)
    • 1.5 注意力机制代码
      • (1)基本python函数
      • (2)注意力机制代码
      • (3)多头注意力机制
  • 2 Transformer
    • 2.1 介绍:
    • 2.2 模型结构:
      • (1) 输入部分
      • (2) 输出部分
  • 3 llama系列
    • 3.1 llama1
    • 3.2 llama2
    • 3.3 llama3
    • 3.4 PPO的概念
    • 3.5 llama3.1
    • 3.6 KV Cache
    • 3.7 Group query attention
    • 3.8 reward model
  • 4 分布式基础知识
    • 4.1 进程,线程和协程
    • 4.2 DP 和 DDP
      • (1) DP的定义
      • (2) DP 和 DDP 的区别:
      • (3) DDP 的代码
    • 4.3 DeepSeed zero
  • 5 微调
    • 5.1 Lora
      • (1) 为什么叫低秩矩阵?
      • (2) lora的优点
      • (3) 方法:
      • (4)代码:


1 基本知识

1. 1 归一化

(1)层归一化(LN)

  • 计算均值: μ = 1 d ∑ i = 1 d x i \mu = \frac{1}{d} \sum_{i=1}^{d} x_i μ=d1i=1dxi

  • 计算方差: σ 2 = 1 d ∑ i = 1 d ( x i − μ ) 2 \sigma^2 = \frac{1}{d} \sum_{i=1}^{d} (x_i - \mu)^2 σ2=d1i=1d(xiμ)2

  • 归一化: x ^ = [ x 1 − μ σ 2 + ϵ , x 2 − μ σ 2 + ϵ , … , x d − μ σ 2 + ϵ ] \mathbf{\hat{x}} = \left[ \frac{x_1 - \mu}{\sqrt{\sigma^2 + \epsilon}}, \frac{x_2 - \mu}{\sqrt{\sigma^2 + \epsilon}}, \ldots, \frac{x_d - \mu}{\sqrt{\sigma^2 + \epsilon}} \right] x^=[σ2+ϵ x1μ,σ2+ϵ x2μ,,σ2+ϵ xdμ]
    其中 ϵ \epsilon ϵ 是一个很小的正数(例如 1 0 − 5 10^{-5} 105),用于防止除以零的情况发生。

  • 缩放和平移: y = γ x ^ + β \mathbf{y} = \gamma \mathbf{\hat{x}} + \beta y=γx^+β
    这里 γ \gamma γ β \beta β 是可学习的参数,通常初始化为 γ = 1 \gamma = 1 γ=1 β = 0 \beta = 0 β=0

(2)批量归一化(BN)

  • 批量归一化与层归一化不同,批量归一化是在每个小批量上进行归一化

  • 假设有一个小批量数据 X = x 1 , x 2 , … , x m \mathbf{X} = { \mathbf{x}_1, \mathbf{x}_2, \ldots, \mathbf{x}_m } X=x1,x2,,xm,其中 x i ∈ R d \mathbf{x}_i \in \mathbb{R}^d xiRd 表示第 i i i 个样本的特征向量, m m m 是小批量的大小, d d d 是特征的维度。然后分别对每个批量的每个特征向量进行归一化。

  • 计算均值: μ b = 1 m ∑ i = 1 m x i \mu_b = \frac{1}{m} \sum_{i=1}^{m} \mathbf{x}_i μb=m1i=1mxi

  • 计算方差: σ b 2 = 1 m ∑ i = 1 m ( x i − μ b ) 2 \sigma^2_b = \frac{1}{m} \sum_{i=1}^{m} (\mathbf{x}_i - \mu_b)^2 σb2=m1i=1m(xiμb)2

  • 归一化: x ^ i = x i − μ b σ b 2 + ϵ \mathbf{\hat{x}}_i = \frac{\mathbf{x}_i - \mu_b}{\sqrt{\sigma^2_b + \epsilon}} x^i=σb2+ϵ xiμb

  • 缩放和平移: $\mathbf{y}_i = \gamma_i \mathbf{\hat{x}}_i + \beta_i $,其中 γ i \gamma_i γi β i \beta_i βi 是可学习的参数,通常初始化为 γ i = 1 \gamma_i = 1 γi=1 β i = 0 \beta_i = 0 βi=0

(3)均方根归一化RMSNorm

  • 计算RMS: 1 d ∑ i = 1 d x i 2 \sqrt{\frac{1}{d} \sum_{i=1}^{d} x_i^2} d1i=1dxi2
  • 归一化: x ^ = x R M S ( x ) \mathbf{\hat{x}} = \frac{x}{RMS(x)} x^=RMS(x)x
  • 优点: 对数据进行归一化,使得数据具有统一的分布,便于模型训练。不需要计算均值和方差,可以减少计算量。
  • 缺点:对数据进行归一化,可能会导致梯度消失或爆炸。

(4)DeepNorm

  • 基于LN,在残差块中,将输入和输出进行归一化,以保持梯度不消失或爆炸。
  • 公式: D e e p N o r m ( x ) = L N ( γ ∗ x + s u b l a y e r ( x ) ) DeepNorm(x)=LN(\gamma*x+sublayer(x)) DeepNorm(x)=LN(γx+sublayer(x)),其中 γ \gamma γ 是可学习参数,sublayer() 是其注意力或前馈神经网络的子层。
  • 优点:结合了Post-LN的良好性能和Pre-LN的训练稳定性。

1.2 归一化的位置

(1)Post-Norm(transformer)

  • 作用
  1. 加快收敛速度
  2. 降低对初始超参数的敏感性(为什么:通过层归一化,可以消除不同层之间由于权重尺度变化带来的影响。这意味着即使某些超参数设置得不是最佳,网络仍然能够更好地应对这些变化,因为层归一化提供了一种机制来自动调整输入的尺度。)
  3. 具有不稳定性,一般搭配其他策略(例如DeepNorm)

(2)Pre-Norm

  • 作用
  1. 减少梯度消失和爆炸
  2. 保持训练的稳定性(例如 LLama)
  3. 收敛慢,性能低于Post-Norm

(3)Sandwish-Norm

  • 公式: y = x + N o r m ( S u b l a y e r ( N o r m ( x ) ) ) \mathbf{y} = x+ Norm(Sublayer(Norm(x))) y=x+Norm(Sublayer(Norm(x)))
  • 理论上应该具有更加灵活的表达能力,但是对于大语言模型来说,甚至会引发训练崩溃的问题。

参考资料

  • 论文:《On Layer Normalization in the Transformer Architecture》对比了Pre—Nore和Post-Norm。
  • https://zhuanlan.zhihu.com/p/480783670

1.3 激活函数

(1)ReLU(Transformer,Rectified Linear Unit)

在这里插入图片描述

  • 公式:ReLU(x)=max(0,x)
  • 缺点:被设置为0的学不到任何信息,导致神经元失活

(2)Swish/silu激活函数和GELU激活函数 (Gaussian Error Linear Unit)

  • 公式:
  • S w i s h ( x ) = x ∗ s i g m o i d ( x ) Swish(x)=x*sigmoid(x) Swish(x)=xsigmoid(x)
  • GELU利用标准高斯积累分布函数作为激活函数
  • G E L U ( x ) = 0.5 ∗ x ∗ ( 1 + e r f ( x / ( 2 ) ) ) GELU(x)=0.5*x*(1+erf(x/\sqrt(2))) GELU(x)=0.5x(1+erf(x/( 2))), e r f ( x ) = 2 π ∫ 0 x e − t 2 d t erf(x)=\frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} dt erf(x)=π 20xet2dt
  • 这些激活函数可以带来更好的性能并且收敛性更好,但是计算过程更为复杂。

(3)GLU激活函数(Gated Linear Units)

  • 引入两个不同的线性层,其中一个线性层的输入被输入到激活函数中,然后将其结果和另一个线性层的输出进行元素相乘得到最终的输出。可以带来更高的提升。

(4)swiGLU激活函数(llama)

第一个线性层的输出被输入到swih激活函数中,然后和第二个线性层的输出进行逐元素相乘

在这里插入图片描述

self.w1,self.w2和self.w3都是线性层。

(5)tanh 激活函数

  • 函数公式: t a n h ( x ) = e x − e − x e x + e − x tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} tanh(x)=ex+exexex

  • 在这里插入图片描述

  • 缺点:过大或过小导致梯度消失;指数运算和指数函数的计算开销大;输出范围在-1到1之间,可能会限制神经网络的表达能力。

  • 优点:

    1. 零中心性质:tanh函数的输出范围在-1到1之间,具有零中心性质,即均值为0,这有助于减少梯度消失问题,使得神经网络的训练更加稳定和快速。
    2. 非线性特性:tanh函数是一种非线性函数,引入了非线性变换,使得神经网络能够学习和表示更复杂的非线性函数关系。
    3. 平滑性:tanh函数是光滑且连续的,在整个定义域上都具有可导性,这对于基于梯度的优化方法(如梯度下降)非常重要。
    4. 加速神经网络训练。

1.4 位置编码

1.4.1 绝对位置编码(Absolute Position Encoding)

  • 绝对位置编码基于绝对位置信息,每个位置都对应一个唯一的向量,用于表示该位置在序列中的位置信息。只能局限于样本中见过的位置,但是建模训练中未见过的位置。限制了长文本的能力。
(1)正余弦位置编码 (Transformer)
  • 在Transformer模型中,正余弦位置编码的计算公式如下:
    对于位置 ( pos ) 和维度 ( i ),位置编码 ( PE(pos, i) ) 定义为:
    P E ( p o s , 2 k ) = s i n ( p o s 1000 0 2 k / d ) PE(pos, 2k) = sin\left(\frac{pos}{10000^{2k/d}}\right) PE(pos,2k)=sin(100002k/dpos)
    P E ( p o s , 2 k + 1 ) = c o s ( p o s 1000 0 2 k / d ) PE(pos, 2k+1) = cos\left(\frac{pos}{10000^{2k/d}}\right) PE(pos,2k+1)=cos(100002k/dpos)
    pos表示位置索引,k表示维度索引。
  • x i = x + P E ( p o s , i ) x_i=x+PE(pos, i) xi=x+PE(pos,i)
  • 其中d和embedding的维度是一样的。那么模型最长只能为d,超过长度的需要截断。
  • 这种编码方式能够为每个位置生成一个唯一的向量,并且相邻位置之间的向量差异较小,随着位置间隔增大,向量差异也逐渐增大。
(2)可学习的嵌入表示(BERT)

1.4.2 相对位置编码(Relative Position Encoding)

  • 相对位置编码是根据键和查询之间的偏移量计算得来的。
  • 旋转位置编码通过将位置编码旋转一定角度,来模拟位置编码的相对位置信息。
  • 注意力机制公式: A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d ) V Attention(Q, K, V)=softmax(\frac{QK^T}{\sqrt{d}})V Attention(Q,K,V)=softmax(d QKT)V
  • Q = W Q ∗ X , K = W K ∗ X , V = W V ∗ X Q=W_Q*X, K=W_K*X, V=W_V*X Q=WQX,K=WKX,V=WVX,如果没有 W Q W_Q WQ, W K W_K WK, W V W_V WV,那么就是绝对位置编码。但是如果字的顺序不一样的话,字级别的embedding还是一样的。因此需要一个位置信息将其融合进去。

(1)旋转位置编码(Rotary Position Encoding)

在这里插入图片描述
在这里插入图片描述

  • 推导公式:
    - 在这里插入图片描述

在这里插入图片描述

  • 代码
def precompute_freqs_cis(dim: int, seq_len: int, theta: float = 10000.0):
    # 计算词向量元素两两分组之后,每组元素对应的旋转角度
    freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
    # 生成 token 序列索引 t = [0, 1,..., seq_len-1]
    t = torch.arange(seq_len, device=freqs.device)
    # freqs.shape = [seq_len, dim // 2] 
    freqs = torch.outer(t, freqs).float()
    # torch.polar 的文档
    # https://pytorch.org/docs/stable/generated/torch.polar.html
    # 计算结果是个复数向量
    # 假设 freqs = [x, y]
    # 则 freqs_cis = [cos(x) + sin(x)i, cos(y) + sin(y)i]
    freqs_cis = torch.polar(torch.ones_like(freqs), freqs)
    return freqs_cis

def apply_rotary_emb(
    xq: torch.Tensor,
    xk: torch.Tensor,
    freqs_cis: torch.Tensor,
) -> Tuple[torch.Tensor, torch.Tensor]:
    # xq.shape = [batch_size, seq_len, dim]
    # xq_.shape = [batch_size, seq_len, dim // 2, 2]
    xq_ = xq.float().reshape(*xq.shape[:-1], -1, 2)
    xk_ = xk.float().reshape(*xk.shape[:-1], -1, 2)
    
    # 转为复数域
    xq_ = torch.view_as_complex(xq_)
    xk_ = torch.view_as_complex(xk_)
    
    # 应用旋转操作,然后将结果转回实数域
    # xq_out.shape = [batch_size, seq_len, dim]
    xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(2)
    xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(2)
    return xq_out.type_as(xq), xk_out.type_as(xk)

class Attention(nn.Module):
    def __init__(self, args: ModelArgs):
        super().__init__()

        self.wq = Linear(...)
        self.wk = Linear(...)
        self.wv = Linear(...)
        
        self.freqs_cis = precompute_freqs_cis(dim, max_seq_len * 2)

    def forward(self, x: torch.Tensor):
        bsz, seqlen, _ = x.shape
        xq, xk, xv = self.wq(x), self.wk(x), self.wv(x)

        xq = xq.view(batch_size, seq_len, dim)
        xk = xk.view(batch_size, seq_len, dim)
        xv = xv.view(batch_size, seq_len, dim)

        # attention 操作之前,应用旋转位置编码
        xq, xk = apply_rotary_emb(xq, xk, freqs_cis=freqs_cis)
        
        # scores.shape = (bs, seqlen, seqlen)
        scores = torch.matmul(xq, xk.transpose(1, 2)) / math.sqrt(dim)
        scores = F.softmax(scores.float(), dim=-1)
        output = torch.matmul(scores, xv)  # (batch_size, seq_len, dim)
  # ......

1.5 注意力机制代码

(1)基本python函数

unsqueeze:在某个维度上添加张量
repeat/expend:对某个维度的列进行复制
resheap:对矩阵的维度进行重组

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

(2)注意力机制代码

import torch
from torch import nn
import math
class self_attention1(nn.Module):
    def __init__(self,hidden_demision):
        super().__init__()
        self.hidden_demision=hidden_demision
        self.q=nn.Linear(hidden_demision,hidden_demision)
        self.k=nn.Linear(hidden_demision,hidden_demision)
        self.v=nn.Linear(hidden_demision,hidden_demision)

        self.softmax=nn.Softmax(dim=-1)

    def forward(self,X):
        # X:batch*seq_len*hidden_demision
        # Q: batch*seq_len*hidden_demision
        Q=self.q(X)
        K=self.k(X)
        V=self.v(X)

        # batch*seq_len*seq_len
        attention_value=(Q@K.transpose(-1,-2)) / math.sqrt(self.hidden_demision) #转置
        
        
        # batch*seq_len*hidden_demision
        output=self.softmax(attention_value) @V 

        return output

输出结果:
在这里插入图片描述

优化版本:

import torch
from torch import nn
import math
class self_attention1(nn.Module):
    def __init__(self,hidden_demision):
        super().__init__()
        self.hidden_demision=hidden_demision
        self.qkv=nn.Linear(hidden_demision,hidden_demision*3)
        self.softmax=nn.Softmax(dim=-1)

    def forward(self,X):
        # X:batch*seq_len*hidden_demision
        # Q: batch*seq_len*hidden_demision
        Q,K,V=torch.split(self.qkv(X),self.hidden_demision,dim=-1)

        # batch*seq_len*seq_len
        attention_value=(Q@K.transpose(-1,-2)) / math.sqrt(self.hidden_demision) #转置
        
        
        # batch*seq_len*hidden_demision
        output=self.softmax(attention_value) @V 

        return output
# 完整版 mask_attention
import torch
from torch import nn
import math
class self_attention3(nn.Module):
    def __init__(self,hidden_demision):
        super().__init__()
        self.hidden_demision=hidden_demision
        self.q=nn.Linear(hidden_demision,hidden_demision)
        self.k=nn.Linear(hidden_demision,hidden_demision)
        self.v=nn.Linear(hidden_demision,hidden_demision)
        self.attention_dropout=nn.Dropout(0.1)

        self.softmax=nn.Softmax(dim=-1)

    def forward(self,X,mask_attention=None):
        # X:batch*seq_len*hidden_demision
        # Q: batch*seq_len*hidden_demision
        Q=self.q(X)
        K=self.k(X)
        V=self.v(X)

        # batch*seq_len*seq_len
        attention_value=(Q@K.transpose(-1,-2)) / math.sqrt(self.hidden_demision) #转置
        
        if mask_attention is not None:
            attention_value=attention_value.masked_fill(
                mask_attention==0,float("-1e20")
            )
        print("attention_value:",attention_value)
        # batch*seq_len*hidden_demision
        output=self.softmax(attention_value) @V
        print("not dopout_output:",self.softmax(attention_value))
        # 使得小于0的值的神经元可以被去除 
        output=self.attention_dropout(output)
        print("dopout_output:",output)

        return output


X=torch.rand([3,4,2])
mask_attention=torch.tensor(
    [
        [1,1,1,0],
        [1,1,0,0],
        [1,0,0,0]
    ]
)


mask_attention.size()

在这里插入图片描述

(3)多头注意力机制

多头注意力机制是Transformer架构中的核心组件,它允许模型同时关注多个位置的输入,从而捕获更复杂的依赖关系。


import torch
from torch import nn
import math
class self_Multi_Head_Attention(nn.Module):
    def __init__(self,hidden_demision,head_num):
        super().__init__()
        self.hidden_demision=hidden_demision
        self.head_dim=hidden_demision//head_num
        self.head_num=head_num
        self.q=nn.Linear(self.hidden_demision,self.hidden_demision)
        self.k=nn.Linear(self.hidden_demision,self.hidden_demision)
        self.v=nn.Linear(self.hidden_demision,self.hidden_demision)
        self.attention_dropout=nn.Dropout(0.1)

        self.softmax=nn.Softmax(dim=-1)

    def forward(self,X,mask_attention=None):
        batch,seq_len,_=X.size()
        # X:batch*seq_len*hidden_demision
        # Q: batch*seq_len*hidden_demision
        Q=self.q(X)
        K=self.k(X)
        V=self.v(X)

        # batch*head_num*seq_len*hidden_demision
        q_state=Q.view(batch,seq_len,self.head_num,self.head_dim).transpose(1,2)
        k_state=K.view(batch,seq_len,self.head_num,self.head_dim).transpose(1,2)
        v_state=V.view(batch,seq_len,self.head_num,self.head_dim).transpose(1,2)
       
        # batch*head_num*seq_len*hidden_demision
        attention_value=(q_state@k_state.transpose(-1,-2)) / math.sqrt(self.hidden_demision) #转置
        
        if mask_attention is not None:
            attention_value=attention_value.masked_fill(
                mask_attention==0,float("-1e20")
            )
        print("attention_value:",attention_value)
        # batch*head_num*seq_len*hidden_demision
        output=self.softmax(attention_value) @v_state
        print("not dopout_output:",self.softmax(attention_value))
        # 使得小于0的值的神经元可以被去除 
        output=self.attention_dropout(output)
        print("dopout_output:",output)

        output=output.transpose(1,2).contiguous()
        output=output.view(batch,seq_len,self.hidden_demision)

        return output


X=torch.rand([3,4,128])
# mask_attention=torch.tensor(
#     [
#         [1,1,1,0],
#         [1,1,0,0],
#         [1,0,0,0]
#     ]
# )
X.size()
attention=self_Multi_Head_Attention(128,8)
output=attention.forward(X)

2 Transformer

2.1 介绍:

  1. 可以利用分布式GPU进行训练,提升模型训练效率
  2. 在分析预测更长文本时,捕捉间隔较长的语义关联性更好
    在这里插入图片描述

2.2 模型结构:

(1) 输入部分

源文件和目标文件的词嵌入+位置编码(正余弦位置编码)

(2) 输出部分

线性层+softmax层

3 llama系列

3.1 llama1

关键词:

  • ROPE旋转位置编码

  • pre-Norm
    在这里插入图片描述

  • RMS Norm

  • wishGLU激活函数

3.2 llama2

  1. llama 2中在较大的模型上使用了group 注意力机制。即将K和V进行分组,同时对应一个Q进行计算。
  2. 使用了更多的数据集,微调阶段加入了100万人工标注的数据集
  3. llama chat出现,使用模型输出不同的结果然后人工进行排序,进行强化学习。
  4. 上下文长度从2k扩充到了4k
  5. KV Cache,在预测下一个token的时候,kv中含有重复的计算。比如预测1-n个token的时候,每预测一个token,q中的每一个向量的所有数据都要和k,v重新进行计算。因此可以将计算后的k和v进行存储。然后只选取第i个词的q,然后将存储的k进行相加和q进行计算,v也是一样。
  6. 使用sentencePiece进行标记

3.3 llama3

  • 使用三种并行化类型(数据,模型和流水线)进行训练
  • 强化学习方法进行安全微调,SFT+拒绝采样+PPO+DPO流程
  • llama 3中所有的模型都用了分组注意力机制。
  • 上下文序列从4k到8k
  • token数量从2t到15t
  • 使用Tikton及逆行标记

3.4 PPO的概念

  1. 一个是打分模型,一个是奖励机制。此外还有一个基模型和经过基模型在进行强化后的模型
  2. 打分模型:即在模型的最后一层加一个全连接层,size为hidden_dim*1
  3. 流程:首先对将数据输入到基模型中进行Q&A问答输出其答案,然后将答案输入到评分模型中进行评分,评分的结果通过人工进行纠正后输入到奖励机制中对比评分结果和评分模型的一致性从而对基模型进行纠正生成新的基模型。然后计算基模型和经过强化后基模型之间的KL 散度。

3.5 llama3.1

  • 使用了更多的数据集

  • 还是使用的dense transformer结果。区分MOE

  • 支持更长的上下文序列,其模型参数8b 70b和405b

  • 语言方面,支持八种多语言

  • 148k上下文序列

  • 增加了function call的功能。(tool calling)

  • llama3.1 instruct 通过指令微调,微调数据都是英文。因此对中文的效果并不是很好。

3.6 KV Cache

加速推理过程:将之前的K和V存储起来作为KV chache。 将其作为一个矩阵,开始初始化为0. 然后不断追加新的值。

  • 初始化过程

在这里插入图片描述

  • 计算过程

在这里插入图片描述
在这里插入图片描述

3.7 Group query attention

#n_local_heads (int): Number of local query heads.
#n_local_kv_heads (int): Number of local key and value heads.
#n_rep (int): Number of repetitions for local heads
self.n_rep = self.n_local_heads // self.n_local_kv_heads
# repeat k/v heads if n_kv_heads < n_heads
keys = repeat_kv(keys, self.n_rep)  # (bs, cache_len + seqlen, n_local_heads, head_dim)
values = repeat_kv(values, self.n_rep)  # (bs, cache_len + seqlen, n_local_heads, head_dim)

def repeat_kv(x: torch.Tensor, n_rep: int) -> torch.Tensor:
    """torch.repeat_interleave(x, dim=2, repeats=n_rep)"""
    bs, slen, n_kv_heads, head_dim = x.shape
    if n_rep == 1:
        return x
    return (
        x[:, :, :, None, :]
        .expand(bs, slen, n_kv_heads, n_rep, head_dim)
        .reshape(bs, slen, n_kv_heads * n_rep, head_dim)
    )

在这里插入图片描述
在这里插入图片描述

n_kv_head=8
在这里插入图片描述

3.8 reward model

训练一个打分或者回归模型。

  • 损失函数(源自instructGPT)

  • ρ表示sigmoid函数,即希望 y c h o s e n y_{chosen} ychosen y r e j e c t e d y_{rejected} yrejected的差距越大越好。
    在这里插入图片描述

  • 通过casual lm输出多个数据进行人工评估,然后形成偏序对(相对答案)输入到reward model中进行训练。
    在这里插入图片描述

4 分布式基础知识

4.1 进程,线程和协程

进程:操作系统分配资源的基本单位
线程:操作系统调度的基本单元
内存角度来说:进程分配了独立的虚拟地址空间。
通信角度:线程的通信比较方便,可以直接在堆上面进行通信。进程之间的通信需要IPC(进程间通信 )相关技术。
安全性来说:如果线程挂了则进程挂了,如果进程挂了,其他进程不会受到影响,因为虚拟地址空间是独立的。

  1. 进程适合CPU密集型任务。线程适合IO密集型任务。
  2. 多进程中,每个进程可以包含多线程。每一个线程共享进程中所有的内存。比如qq,微信,就是一个进程,里面可以包含多个线程。
  3. 在python中,由于GIL(Global interpreter)的存在会导致伪多线程。多个线程无法同时执行python字节码。导致多线程在CPU密集型任务中无法提高性能,一般是在执行IO操作(如文件读写、网格请求时),线程会释放GIL。因此多进程的中的线程也是串行。

IO密集型任务主要是受限于IO操作的速度,任务执行的时间主要取决于外部设备(如磁盘、网络)的响应速度。

  • 需要频繁的磁盘读写、网络请求或其他外部设备交互
  • CPU大部分时间处于等待状态,等待IO操作完成。
  • 性能瓶颈在于IO设备的速度而非CPU

CPU密集型任务

  • 主要效果CPU的计算资源,任务的执行时间主要取决于CPU的运算速度
  • 需要大量的数学计算或数据处理
  • 任务中很少或者没有IO的读写操作
  • 性能瓶颈在于CPU 的处理能力

在这里插入图片描述

在这里插入图片描述

4.2 DP 和 DDP

官方文档:https://pytorch.org/tutorials/intermediate/ddp_tutorial.html

(1) DP的定义

DistributedDataParallel (DDP) implements data parallelism at the module level which can run across multiple machines. Applications using DDP should spawn multiple processes and create a single DDP instance per process. DDP uses collective communications in the torch.distributed package to synchronize gradients and buffers. More specifically, DDP registers an autograd hook for each parameter given by model.parameters() and the hook will fire when the corresponding gradient is computed in the backward pass. Then DDP uses that signal to trigger gradient synchronization across processes. Please refer to DDP design note for more details(一个数据假如是128个,batchsize为24,一共有8组数据。那么DDP可以在多个GPU中运行不同的数据组,即创建了多个进程。主要实现过程是在分布式数据并行时,DDP会在每个GPU 上对模型参数或优化器进行拷贝。然后通过HPC(high performance calculate)算法或ring all-reduce 算法保持每个GPU 上的数据是一致的)

  • 多进程,多线程

  • Ring-ALLReduce:多个GPT,每个GPU有多个参数,然后里面的参数可以互相传递,分发和累计,然后同步到一个GPU。同时发送和接收,可以最大限度利用每个显卡的上下行带宽。

(2) DP 和 DDP 的区别:

  • First, DataParallel is single-process, multi-thread, and only works on a single machine, while DistributedDataParallel is multi-process and works for both single- and multi- machine training. DataParallel is usually slower than DistributedDataParallel even on a single machine due to GIL contention across threads, per-iteration replicated model, and additional overhead introduced by scattering inputs and gathering outputs.
    (DP: 单进程多线程,由于GIL锁其实还是串行的。DDP是多进程)

  • Recall from the prior tutorial that if your model is too large to fit on a single GPU, you must use model parallel to split it across multiple GPUs. DistributedDataParallel works with model parallel; DataParallel does not at this time. When DDP is combined with model parallel, each DDP process would use model parallel, and all processes collectively would use data parallel.
    (DDP可以进行模型的并行,即每个进程中都有一个模型,然后就可以将数据分别输入到模型中进行数据的并行。DP不能实现不同模型的并行)

  • If your model needs to span multiple machines or if your use case does not fit into data parallelism paradigm, please see the RPC API for more generic distributed training support.

(如果你需要内联多个机器或者数据并不符合并行的要求,可以使用RPC)

(3) DDP 的代码

  • 参数解释:
    rank:某个device中GPU的编号
    localrank:所有device的GPU编号
    world_size: GPU的总数量
    例子:假如2个device,每个device中有3个GPU
    rank[0,1,2,3,4,5] localrank[0,1,2] [0,1,2]
    world_size:2*3=6

  • 优化
    比如进程中断,可以通过torchrun运行DDP。防止中断后需要重新训练。

在这里插入图片描述

4.3 DeepSeed zero

  • 每个GPU只存储一份优化器状态,消除冗余。
  • 每个GPU只存储部分网络状态,然后在更新的时候将所需的参数传递给所需的GPU。

5 微调

5.1 Lora

代码:https://github.com/microsoft/LoRA.

论文:https://arxiv.org/pdf/2106.09685

在这里插入图片描述

机制:LoRA 是在预训练模型的每一层中插入额外的低秩矩阵。LoRA 在训练时不需要保存原始参数的梯度,仅需对低秩子空间参数进行优化即可。

(1) 为什么叫低秩矩阵?

参考: https://blog.csdn.net/weixin_43332715/article/details/131177583

  1. 秩可以度量矩阵自身相关性。如果各行各列都是线性无关的,矩阵就是满秩。
  2. 如果矩阵之间各行的相关性很强,那么就表示这个矩阵实际可以投影到更低维的线性子空间,也就是用几个向量就可以完全表达了,它就是低秩的。

(2) lora的优点

  1. 即插即用
  2. 节省资源
  3. no inference latency
  4. 正交性
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(3) 方法:

在这里插入图片描述

参数解释:
在这里插入图片描述

训练过程中,w0的参数不更新,A和B是学习的参数。A和B进行随机高斯初始化,使得BA的乘机在开始训练的时候为0.

(4)代码:

  1. 初始化:可以对应到上面的公式。
    输入参数:
    in_features/out_features: 输入输出维度。

r:秩,用于构造lora_B 和lora_A 的矩阵。

lora_alpha:越高意味着对模型行为的调整越大,值越低则相反

 if r > 0:
            self.lora_A = nn.Parameter(self.weight.new_zeros((r, in_features)))
            self.lora_B = nn.Parameter(self.weight.new_zeros((out_features, r)))
            self.scaling = self.lora_alpha / self.r
            # Freezing the pre-trained weight matrix
            self.weight.requires_grad = False

lora_alpha的作用:

# 定义了一个 self.scaling
 self.scaling = self.lora_alpha / self.r

# 这里的T(self.lora_B @ self.lora_A)的结果是一个矩阵,矩阵的维度是[in_features,out_features]。
self.weight.data += T(self.lora_B @ self.lora_A) * self.scaling
 # 这里的构造了一个新的线性层。
 result = F.linear(x, T(self.weight), bias=self.bias) 

LoRA 的权重更新。首先,self.lora_dropout(x) 应用了一个 dropout 层到输入 x,这有助于防止过拟合。然后,这个经过 dropout 处理的输入与两个 LoRA 矩阵 self.lora_A 和 self.lora_B 进行矩阵乘法运算。self.lora_A.transpose(0, 1) 和 self.lora_B.transpose(0, 1) 分别表示 LoRA 矩阵的转置,这是为了确保矩阵乘法的维度匹配。最后,结果乘以一个缩放因子 self.scaling,这个因子用于控制 LoRA 更新的强度,避免对原模型权重造成过大影响。(值得注意的是self.weight.data 被冻结了,因此上面的result 里面的参数并不会被更新。下面附加的lora模块继续进行参数更新。)

 result += (self.lora_dropout(x) @ self.lora_A.transpose(0, 1) @ self.lora_B.transpose(0, 1)) * self.scaling

  1. 使用示例:

假如PyTorch 模型或具有两个线性层的模块:在这里插入图片描述

在使用 LoRA 时,通常会将 LoRA 更新添加到这些线性层的输出中,又得到代码如下:
在这里插入图片描述

部分图片来自视频截图,侵权删。未完待续~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/933252.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【开源免费】基于SpringBoot+Vue.JS中小型医院网站(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 078 &#xff0c;文末自助获取源码 \color{red}{T078&#xff0c;文末自助获取源码} T078&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

哈希知识详解

一、哈希 以前&#xff0c;在面对海量数据的查找时&#xff0c;最快就是红黑树 logN&#xff0c;无法满足需求。 于是探索出了另一种用关键字 key 值与其存储位置建立映射的思想&#xff0c;让查找效率提升到 O(1) &#xff0c;这个就是哈希。 二、哈希函数 1、直接定值法 ①…

红日靶场vulnstark 4靶机的测试报告[细节](一)

目录 一、测试环境 1、系统环境 2、注意事项 3、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、漏洞利用Getshell ①Struts 2 s2-045漏洞 手工利用s2-45漏洞 Msf综合利用 ②Tomcat框架(CVE-2017-12615) ③phpMyAdmin(CVE-2018-12613) 构造语句写入冰蝎木…

D92【python 接口自动化学习】- pytest基础用法

day92 pytest的skip和skipif用法 学习日期&#xff1a;20241208 学习目标&#xff1a;pytest基础用法 -- pytest的skip和skipif用法 学习笔记&#xff1a; 测试用例跳过 skip和skipif用法&#xff0c;测试用例跳过 pytest.mark.skip 跳过标记的用例 pytest.mark.skipif(1 …

【Java】类似王者荣耀游戏

r77683962/WangZheYouDianRongYao 运行效果图&#xff1a; 类似王者荣耀游戏运行效果图_哔哩哔哩_bilibili

【数字电路与逻辑设计】实验二 数值比较器

文章总览&#xff1a;YuanDaiMa2048博客文章总览 【数字电路与逻辑设计】实验二 数值比较器 一、实验内容二、设计过程&#xff08;一&#xff09;真值表&#xff08;二&#xff09;设计思路 三、源代码&#xff08;一&#xff09;代码说明&#xff1a;&#xff08;二&#xff…

探索十个 AI 对话提示词网站,提升交互体验

learning prompt 网址&#xff1a;Hello from Learning Prompt | Learning Prompt 简介&#xff1a;这是一个学习 提示词 的网站&#xff0c;有 ChatGPT&#xff0c;Midjourney 的提示词教程、技巧等&#xff0c;他在右上角有中文语言的选择&#xff0c;教程非常详尽 LangCha…

C# Decimal

文章目录 前言1. Decimal 的基本特性2. 基本用法示例3. 特殊值与转换4. 数学运算示例5. 精度处理示例6. 比较操作示例7. 货币计算示例8. Decimal 的保留小数位数9. 处理 Decimal 的溢出和下溢10. 避免浮点数计算误差总结 前言 decimal 是 C# 中一种用于表示高精度十进制数的关键…

数据库-mysql(基本语句)

演示工具&#xff1a;navicat 连接&#xff1a;mydb 一.操作数据库 1.创建数据库 ①create database 数据库名称 //普通创建 ②create database if not exists 数据库名称 //创建数据库&#xff0c;判断不存在&#xff0c;再创建&#xff1a; 使用指定数据库 use 数据库…

使用Tesseract进行图片文字识别

Tesseract介绍 Tesseract 是一个开源的光学字符识别&#xff08;OCR&#xff09;引擎&#xff0c;最初由 HP 在 1985 年至 1995 年间开发&#xff0c;后来被 Google 收购并开源。Tesseract 支持多种语言的文本识别&#xff0c;能够识别图片中的文字&#xff0c;并将其转换为可…

智慧营区解决方案

1. 数据处理与服务封装 该智慧化解决方案注重数据的全面采集与处理&#xff0c;包括网页数据、图片、视频等非结构化数据&#xff0c;以及系统数据、文本、关系型数据库等结构化数据。通过数据抽取、稽核、规整、解析、清洗等流程&#xff0c;实现数据的入库与存储&#xff0c…

信号level 1:信号的产生

目录 引言 基础知识&#xff08;背景&#xff09; 信号的产生 方法一&#xff1a;通过终端按键产生信号&#xff08;键盘按键输入&#xff09; 方式二&#xff1a;通过kill指令 方法3&#xff1a;系统调用 方法四&#xff1a;硬件异常 方法五&#xff1a;软件产生异常 进…

国城杯-misc-Tr4ffIc_w1th_Ste90 [WP]

打开流量包&#xff0c;发现主要是UDP流量&#xff0c;然后还有H264的视频数据 右击&#xff0c;UDP追踪流 然后更换为原始数据 另存为.ts的文件&#xff0c;打开就看到密码 !t15tH3^pAs5W#RD*f0RFL9 打开压缩包是一个文件和一个图片 import numpy as np import cv2 import …

【SpringMVC】参数传递 重定向与转发 REST风格

文章目录 参数传递重定向与转发REST风格 参数传递 ModelAndView&#xff1a;包含视图信息和模型数据信息 public ModelAndView index1(){// 返回页面ModelAndView modelAndView new ModelAndView("视图名");// 或// ModelAndView modelAndView new ModelAndView(…

Minio使用教程

Minio介绍 Minlo是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等&#xff0c;而一个对象文件可以是任意大小&#xf…

新手前端开发入职公司全流程

作为一名前端开发新手&#xff0c;进入一家公司开启职业生涯是既兴奋又充满挑战的旅程。今天就来和大家分享一下这个过程中的各个环节。 一、入职准备 在收到心仪公司的offer后&#xff0c;可别只顾着高兴啦。首先要准备好入职资料&#xff0c;像身份证、学历证明这些是必不可…

那智机器人报警白屏

那智机器人内存太多白屏报警&#xff01;&#xff01;&#xff01;下面来说说如何消除该报警吧&#xff01;&#xff01;&#xff01; 白屏报警的处理办法 解决办法&#xff1a;&#xff08;外部内存清理&#xff09; 升级操作者权限 &#xff08;当我们在维修见面不能看见我…

rk3568之mpp开发笔记mpp移植到开发板

前言&#xff1a; 大家好&#xff0c;今天给大家介绍的内容是rk平台的mpp编解码这块的内容&#xff0c;在rk目前看到有三套框架涉及到编解码内容&#xff1a; 1、rkmedia 2、rockit 3、mpp 这三种不同形式的编解码方式&#xff0c;后面再做详细的框架对比&#xff0c;今天我…

【设计模式】结构型设计模式总结之代理模式、装饰模式、外观模式、享元模式

文章目录 代理模式示例结构分类动态代理 装饰模式示例结构使用场景与代理模式区别Context 外观模式结构示例使用场景Context 享元模式结构示例使用场景Message 代理模式 代理模式&#xff08;Proxy Pattern&#xff09; 是一种结构型设计模式&#xff0c;它提供了一个代理对象…

CSS一些小点 —— 12.7

1. box-sizing: border-box box-sizing 属性&#xff0c;默认值为 content-box box-sizing: border-box 使padding和border的值不会再影响元素的宽高&#xff1b;padding和border的值算在指定宽高的内部&#xff08;但是外边距依然算做外部&#xff09; 2. overflow: hidden …