llama网络结构及源码
目录
模型初始化
config
lm_head
transformer
wte
h
rms_1/rms_2
attn
c_attn
c_proj
线性层mlp
ln_f
rope_cache
mask_cache
kv_caches
tokenizer
tokenizer初始化
tokennizer.encoder
位置编码和mask
确定最大文本长度
建立rope_cache
建立mask_cache
确定RoPE和mask
模型前向传播
生成词嵌入
隐藏层计算
确定kv_cache
进入transformer的隐藏层
attention模块计算
RMSNorm前向
计算q,k,v
词嵌入+位置编码
更新kv_cache
计算注意力
再次经过RMSNorn归一化
经过MLP层
编辑
RMSNorm归一化
网络输出
生成下一分词的循环过程
temperature
选取前topk
torch.topk(input, num)
torch.where(condition, x, y)
选择当前时刻网络生成的分词
torch.nn.functional.softmax(input, dim)
torch.multinomial(input, num_samples)
将新生成的索引加入到输入文本中
更新input_pos
idx.index_copy(dim, index, source)
第二次循环
更新输入
更新旋转位置编码
更新mask
更新词嵌入
进入transfomer隐藏层
对新生成的分词进行RMSNorm
生成新的q,k,v
更新k,v及kv_cache
生成当前位置的注意力分数
生成第二次循环的隐藏层输出
一、模型初始化
代码地址,首先模型初始化,确定模型属性
class LLaMA(nn.Module):def __init__(self, config: LLaMAConfig) -> None:super().__init__()assert config.padded_vocab_size is not Noneself.config = configself.lm_head = nn.Linear(config.n_embd, config.padded_vocab_size, bias=False)self.transformer = nn.ModuleDict(dict(wte=nn.Embedding(config.padded_vocab_size, config.n_embd),h=nn.ModuleList(Block(config) for _ in range(config.n_layer)),ln_f=RMSNorm(config.n_embd),))self.rope_cache: Optional[RoPECache] = Noneself.mask_cache: Optional[MaskCache] = Noneself.kv_caches: List[KVCache] = []
config
确定模型参数,config使用默认的LLaMAConfig类
class LLaMAConfig:block_size: int = 2048vocab_size: int = 32000padded_vocab_size: Optional[int] = Nonen_layer: int = 32n_head: int = 32n_embd: int = 4096def __post_init__(self):if self.padded_vocab_size is None:self.padded_vocab_size = find_multiple(self.vocab_size, 64)@classmethoddef from_name(cls, name: str) -> Self:return cls(**llama_configs[name])llama_configs = {"7B": dict(n_layer=32, n_head=32, n_embd=4096),"13B": dict(n_layer=40, n_head=40, n_embd=5120),"30B": dict(n_layer=60, n_head=52, n_embd=6656),"65B": dict(n_layer=80, n_head=64, n_embd=8192),
}
对于所有类型的网络,不变的超参数为:
block_size: 模型处理的最大文本块的大小为2048。
vocab_size: 词汇表的大小,即模型能识别的词汇总数为32000。
padded_vocab_size经过find_multiple函数确定,用于确保词汇表大小是指定数值(64)的倍数
vocab_size=32000/64=500,词汇表大小是指定数值(64)的倍数
padded_vocab_size为32000
def find_multiple(n: int, k: int) -> int:if n % k == 0:return nreturn n + k - (n % k)
根据网络的参数量不同,模型层数、维度和自主意力头数不同:选择7B模型的情况下,
n_layer: 模型的层数。32
n_head: 自注意力机制中的头数。32
n_embd: 词嵌入的维度或隐藏层的维度。4096
lm_head
线性层:输入维度为4096,输出维度为32000,没有偏置
self.lm_head = nn.Linear(config.n_embd, config.padded_vocab_size, bias=False)
transformer
nn.ModuleDict():和python字典一样存在键值对,可根据key选取网络
包括有嵌入层wte,隐藏层h和归一化层ln_f
self.transformer = nn.ModuleDict(dict(wte=nn.Embedding(config.padded_vocab_size, config.n_embd),h=nn.ModuleList(Block(config) for _ in range(config.n_layer)),ln_f=RMSNorm(config.n_embd),))
wte
嵌入层生成词向量,输入维度为填充后词典的大小padded_vocab_size(32000),输出维度为词嵌入维度n_embd(4096)
h
nn.ModuleList():可以通过迭代的方式创建网络,和list的用法一致
有n_layer(32)层网络块Block
其中网络块Block,包括前后两层归一化层RMSNorm,一层自主意力层CausalSelfAttention和一层线性层MLP
class Block(nn.Module):def __init__(self, config: LLaMAConfig) -> None:super().__init__()self.rms_1 = RMSNorm(config.n_embd)self.attn = CausalSelfAttention(config)self.rms_2 = RMSNorm(config.n_embd)self.mlp = MLP(config)
rms_1/rms_2
RMSNorm 详解三种常用标准化 Batch Norm & Layer Norm & RMSNorm_layernorm rmsnorm-CSDN博客
Llama改进之——均方根层归一化RMSNorm-CSDN博客
BatchNorm是对一个 batch 单个特征的所有样本做归一化
LayerNorm是对单个样本的所有特征做归一化
class RMSNorm(nn.Module):"""Root Mean Square Layer Normalization.Derived from https://github.com/bzhangGo/rmsnorm/blob/master/rmsnorm_torch.py. BSD 3-Clause License:https://github.com/bzhangGo/rmsnorm/blob/master/LICENSE."""def __init__(self, size: int, dim: int = -1, eps: float = 1e-5) -> None:super().__init__()self.scale = nn.Parameter(torch.ones(size))self.eps = epsself.dim = dimdef forward(self, x: torch.Tensor) -> torch.Tensor:# NOTE: the original RMSNorm paper implementation is not equivalent# norm_x = x.norm(2, dim=self.dim, keepdim=True)# rms_x = norm_x * d_x ** (-1. / 2)# x_normed = x / (rms_x + self.eps)norm_x = torch.mean(x * x, dim=self.dim, keepdim=True)x_normed = x * torch.rsqrt(norm_x + self.eps)return self.scale * x_normed
attn
CausalSelfAttention
首先声明嵌入层/隐藏层可以被注意力头数整除
包括c_attn层、c_proj层
注意力头数n_head(32),隐藏层维度n_embd(4096) ,最大文本块的大小block_size(2048)
c_attn
Q,K,V对应的线性层,输入维度为隐藏层维度n_embd(4096),输出维度为3倍的隐藏层维度n_embd(4096)*3分别对应Q,K,V,没有偏置
c_proj
当前模块Block的输出映射,输入维度为隐藏层维度n_embd(4096),输出维度为隐藏层维度n_embd(4096),没有偏置
线性层mlp
hidden_dim(4*4096=16384) ,n_hidden(int(2 * hidden_dim / 3)=10922)
判断是否能被256整除,对n_hidden进行修正,(n + k - (n % k))结果为11008
两个全连接层输入维度为4096,输出维度为11008
映射层输入维度为11008,输出维度为4096
class MLP(nn.Module):def __init__(self, config: LLaMAConfig) -> None:super().__init__()hidden_dim = 4 * config.n_embdn_hidden = int(2 * hidden_dim / 3)n_hidden = find_multiple(n_hidden, 256)self.c_fc1 = nn.Linear(config.n_embd, n_hidden, bias=False)self.c_fc2 = nn.Linear(config.n_embd, n_hidden, bias=False)self.c_proj = nn.Linear(n_hidden, config.n_embd, bias=False)def forward(self, x: torch.Tensor) -> torch.Tensor:x = F.silu(self.c_fc1(x)) * self.c_fc2(x)x = self.c_proj(x)return x
ln_f
为RMSNorm,归一化维度为n_embd(4096)
rope_cache
存储或缓存与RoPE(旋转位置编码)相关的数据。Optional[RoPECache]
表示它可以是 RoPECache
类型的对象,也可以是 None
self.rope_cache: Optional[RoPECache] = None
mask_cache
用于缓存与掩码相关的数据。Optional[MaskCache]
表示它可以是 MaskCache
类型的对象,也可以是 None
。
self.mask_cache: Optional[MaskCache] = None
kv_caches
用于存储多个 KVCache
类型的缓存对象,初始化为空列表
self.kv_caches: List[KVCache] = []
二、tokenizer
tokenizer初始化
class Tokenizer:"""Tokenizer for LLaMA."""def __init__(self, model_path: Path) -> None:self.processor = SentencePieceProcessor(model_file=str(model_path))self.bos_id = self.processor.bos_id()self.eos_id = self.processor.eos_id()self.pad_id = self.processor.pad_id()
tokennizer.encoder
tokenizer.encode(prompt, bos=True, eos=False, device=fabric.device)
def encode(self,string: str,bos: bool = True,eos: bool = False,max_length: int = -1,pad: bool = False,device: Optional[torch.device] = None) -> torch.Tensor:tokens = self.processor.encode(string)if bos:tokens = [self.bos_id] + tokensif eos:tokens = tokens + [self.eos_id]if max_length > 0:tokens = tokens[:max_length]if pad and len(tokens) < max_length:tokens += [self.pad_id] * (max_length - len(tokens))return torch.tensor(tokens, dtype=torch.int, device=device)
三、位置编码和mask
logits = model(x, max_seq_length, input_pos)
输入参数包括输入文本对应词库的idx,最大序列长度,现在输入文本的位置
def forward(self, idx: torch.Tensor, max_seq_length: Optional[int] = None, input_pos: Optional[torch.Tensor] = None) -> Union[torch.Tensor, Tuple[torch.Tensor, List[KVCache]]]:B, T = idx.size()block_size = self.config.block_sizeif max_seq_length is None:max_seq_length = block_sizeassert T <= max_seq_length, f"Cannot forward sequence of length {T}, max seq length is only {max_seq_length}"assert max_seq_length <= block_size, f"Cannot attend to {max_seq_length}, block size is only {block_size}"assert T <= block_size, f"Cannot forward sequence of length {T}, block size is only {block_size}"if self.rope_cache is None:self.rope_cache = self.build_rope_cache(idx)if self.mask_cache is None:self.mask_cache = self.build_mask_cache(idx)if input_pos is not None:rope = self.rope_cache.index_select(0, input_pos)mask = self.mask_cache.index_select(2, input_pos)mask = mask[:, :, :, :max_seq_length]else:rope = self.rope_cache[:T]mask = self.mask_cache[:, :, :T, :T]# forward the model itselfx = self.transformer.wte(idx) # token embeddings of shape (b, t, n_embd)if input_pos is None: # proxy for use_cache=Falsefor block in self.transformer.h:x, _ = block(x, rope, mask, max_seq_length)else:if not self.kv_caches:head_size = self.config.n_embd // self.config.n_headcache_shape = (B, self.config.n_head, max_seq_length, head_size)self.kv_caches = [(torch.zeros(cache_shape, device=x.device, dtype=x.dtype), torch.zeros(cache_shape, device=x.device, dtype=x.dtype))for _ in range(self.config.n_layer)]for i, block in enumerate(self.transformer.h):x, self.kv_caches[i] = block(x, rope, mask, max_seq_length, input_pos, self.kv_caches[i])x = self.transformer.ln_f(x)logits = self.lm_head(x) # (b, t, vocab_size)return logits
确定最大文本长度
将输入文本长度,本次文本的最大文本长度,模型能够处理的最长文本块大小进行对比,确定本次的最大文本长度
建立rope_cache
建立位置缓存
def build_rope_cache(seq_len: int, n_elem: int, dtype: torch.dtype, device: torch.device, base: int = 10000
) -> RoPECache:"""Enhanced Transformer with Rotary Position Embedding.Derived from: https://github.com/labmlai/annotated_deep_learning_paper_implementations/blob/master/labml_nn/transformers/rope/__init__.py. MIT License:https://github.com/labmlai/annotated_deep_learning_paper_implementations/blob/master/license."""# $\Theta = {\theta_i = 10000^{\frac{2(i-1)}{d}}, i \in [1, 2, ..., \frac{d}{2}]}$theta = 1.0 / (base ** (torch.arange(0, n_elem, 2, dtype=dtype, device=device) / n_elem))# Create position indexes `[0, 1, ..., seq_len - 1]`seq_idx = torch.arange(seq_len, dtype=dtype, device=device)# Calculate the product of position index and $\theta_i$idx_theta = torch.outer(seq_idx, theta).float()cache = torch.stack([torch.cos(idx_theta), torch.sin(idx_theta)], dim=-1)# this is to mimic the behaviour of complex32, else we will get different resultsif dtype in (torch.float16, torch.bfloat16, torch.int8):cache = cache.half()return cache
输入的参数:模型能够处理的最大文本块大小,embeddiing维度/注意力头数
步骤:
1.计算
2.计算和最大文本块各个位置的乘积
3.计算sin(idx_theta)和cos(idx_theta)
建立mask_cache
def build_mask_cache(self, idx: torch.Tensor) -> MaskCache:ones = torch.ones((self.config.block_size, self.config.block_size), device=idx.device, dtype=torch.bool)return torch.tril(ones).unsqueeze(0).unsqueeze(0)
步骤:
1.建立最大文本块大小*最大文本块大小的全1(True,布尔型)矩阵
2.取对角线,在增加0,1维度,mask的size为(1,1,模型处理的最大文本块大小,模型处理的最大文本块大小)
确定RoPE和mask
根据输入文本位置确定旋转位置编码和mask
if input_pos is not None:rope = self.rope_cache.index_select(0, input_pos)mask = self.mask_cache.index_select(2, input_pos)mask = mask[:, :, :, :max_seq_length]else:rope = self.rope_cache[:T]mask = self.mask_cache[:, :, :T, :T]
根据输入文本位置确定旋转位置编码
根据输入文本位置和本次的最大文本长度确定mask,size为(1,1,输入文本长度,本次输入的最大文本长度)
四、模型前向传播
生成词嵌入
x = self.transformer.wte(idx)
embedding层生成词嵌入
隐藏层计算
if input_pos is None: # proxy for use_cache=Falsefor block in self.transformer.h:x, _ = block(x, rope, mask, max_seq_length)else:if not self.kv_caches:head_size = self.config.n_embd // self.config.n_headcache_shape = (B, self.config.n_head, max_seq_length, head_size)self.kv_caches = [(torch.zeros(cache_shape, device=x.device, dtype=x.dtype), torch.zeros(cache_shape, device=x.device, dtype=x.dtype))for _ in range(self.config.n_layer)]for i, block in enumerate(self.transformer.h):x, self.kv_caches[i] = block(x, rope, mask, max_seq_length, input_pos, self.kv_caches[i])
确定kv_cache
步骤:
1.确定注意力头的维度
embedding维度/注意力头数
2.k,v的维度为(batch_size,注意力头数,本次的最大文本长度,各注意力头的维度)3.对n_layer(32)层自注意力层,生成全0的k,v
进入transformer的隐藏层
for i, block in enumerate(self.transformer.h):x, self.kv_caches[i] = block(x, rope, mask, max_seq_length, input_pos, self.kv_caches[i])
每一层循环的输入包括:
词嵌入,位置嵌入,mask,本次的最大文本长度,输入位置,本次循环对应的kv_cache
def forward(self,x: torch.Tensor,rope: RoPECache,mask: MaskCache,max_seq_length: int,input_pos: Optional[torch.Tensor] = None,kv_cache: Optional[KVCache] = None,) -> Tuple[torch.Tensor, Optional[KVCache]]:h, new_kv_cache = self.attn(self.rms_1(x), rope, mask, max_seq_length, input_pos, kv_cache)x = x + hx = x + self.mlp(self.rms_2(x))return x, new_kv_cache
attention模块计算
更新kv_cache,计算自注意力
输入包括:
归一化层,位置编码,mask,本次的最大文本长度,输入位置,kv_cache
RMSNorm前向
def forward(self, x: torch.Tensor) -> torch.Tensor:# NOTE: the original RMSNorm paper implementation is not equivalent# norm_x = x.norm(2, dim=self.dim, keepdim=True)# rms_x = norm_x * d_x ** (-1. / 2)# x_normed = x / (rms_x + self.eps)norm_x = torch.mean(x * x, dim=self.dim, keepdim=True)x_normed = x * torch.rsqrt(norm_x + self.eps)return self.scale * x_normed
计算q,k,v
def forward(self,x: torch.Tensor,rope: RoPECache,mask: MaskCache,max_seq_length: int,input_pos: Optional[torch.Tensor] = None,kv_cache: Optional[KVCache] = None,) -> Tuple[torch.Tensor, Optional[KVCache]]: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 dimq, k, v = self.c_attn(x).split(self.n_embd, dim=2)head_size = C // self.n_headk = k.view(B, T, self.n_head, head_size)q = q.view(B, T, self.n_head, head_size)v = v.view(B, T, self.n_head, head_size)q = apply_rope(q, rope)k = apply_rope(k, rope)k = k.transpose(1, 2) # (B, nh, T, hs)q = q.transpose(1, 2) # (B, nh, T, hs)v = v.transpose(1, 2) # (B, nh, T, hs)if kv_cache is not None:cache_k, cache_v = kv_cache# check if reached token limitif input_pos[-1] >= max_seq_length:input_pos = torch.tensor(max_seq_length - 1, device=input_pos.device)# shift 1 position to the leftcache_k = torch.roll(cache_k, -1, dims=2)cache_v = torch.roll(cache_v, -1, dims=2)k = cache_k.index_copy(2, input_pos, k)v = cache_v.index_copy(2, input_pos, v)kv_cache = k, v# causal self-attention; Self-attend: (B, nh, T, hs) x (B, nh, hs, T) -> (B, nh, T, T)# att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))# att = att.masked_fill(mask[:,:,:T,:T] == 0, float('-inf'))# att = F.softmax(att, dim=-1)# y = att @ v # (B, nh, T, T) x (B, nh, T, hs) -> (B, nh, T, hs)# efficient attention using Flash Attention CUDA kernelsy = F.scaled_dot_product_attention(q, k, v, attn_mask=mask, dropout_p=0.0)y = y.transpose(1, 2).contiguous().view(B, T, C) # re-assemble all head outputs side by side# output projectiony = self.c_proj(y)return y, kv_cache
经过线性层生成q,k,v,并分配到不同的注意力头
q,k,v的size均为(B,输入文本长度,注意力头数,各注意力头的维度)
词嵌入+位置编码
针对q,k,将词嵌入和位置编码结合到一起
q = apply_rope(q, rope)
k = apply_rope(k, rope)
两个步骤一样,只看一个步骤就行
def apply_rope(x: torch.Tensor, rope_cache: RoPECache) -> torch.Tensor:# truncate to support variable sizesT = x.size(1)rope_cache = rope_cache[:T]# cast because the reference doesxshaped = x.float().reshape(*x.shape[:-1], -1, 2)rope_cache = rope_cache.view(1, xshaped.size(1), 1, xshaped.size(3), 2)x_out2 = torch.stack([xshaped[..., 0] * rope_cache[..., 0] - xshaped[..., 1] * rope_cache[..., 1],xshaped[..., 1] * rope_cache[..., 0] + xshaped[..., 0] * rope_cache[..., 1],],-1,)x_out2 = x_out2.flatten(3)return x_out2.type_as(x)
输入:词嵌入,位置编码
词嵌入维度:(B,输入文本长度,注意力头数,各注意力头的维度)
位置编码维度:(输入文本长度,theta长度,sin/cos)
词嵌入和位置编码分别review
词嵌入:(B,输入文本长度,注意力头数,各注意力头的维度)-->
(B,输入文本长度,注意力头数,各注意力头的维度/2(theta长度),2(sin/cos))
位置编码:(输入文本长度,theta长度,sin/cos)-->
(1(不是batch_size,单单强制为1),输入文本长度,1(强制为1),各注意力头的维度/2(theta长度),2(sin/cos))
提取正弦和余弦:xshaped[..., 0]
和 xshaped[..., 1]
分别表示 xshaped
中正弦和余弦的值。rope_cache[..., 0]
和 rope_cache[..., 1]
同样表示 rope_cache
中的正弦和余弦值。
计算旋转:通过旋转公式实现了在 xshaped
的每个元素上应用 rope_cache
中存储的旋转信息。
实部 = xshaped[...,0] ∗ ropecache[...,0] − xshaped[...,1] ∗ ropecache[...,1]
虚部 = xshaped[...,1] ∗ ropecache[...,0] + xshaped[...,0] ∗ ropecache[...,1]
Stack 操作:最终的 torch.stack
操作将计算得到的实部和虚部按最后一个维度(-1)组合成一个新的张量。这样,输出张量 x_out2
的大小将是 (B,输入文本长度,注意力头数,各注意力头的维度/2(theta长度),2(sin/cos))
xshaped = x.float().reshape(*x.shape[:-1], -1, 2)
rope_cache = rope_cache.view(1, xshaped.size(1), 1, xshaped.size(3), 2)
x_out2 = torch.stack([xshaped[..., 0] * rope_cache[..., 0] - xshaped[..., 1] * rope_cache[..., 1],xshaped[..., 1] * rope_cache[..., 0] + xshaped[..., 0] * rope_cache[..., 1],],-1,)
最后,将x_out2
resize为(B,输入文本长度,注意力头数,各注意力头的维度),和输入向量x的形状一致
更新kv_cache
k = k.transpose(1, 2) # (B, nh, T, hs)
q = q.transpose(1, 2) # (B, nh, T, hs)
v = v.transpose(1, 2) # (B, nh, T, hs)if kv_cache is not None:cache_k, cache_v = kv_cache# check if reached token limitif input_pos[-1] >= max_seq_length:input_pos = torch.tensor(max_seq_length - 1, device=input_pos.device)# shift 1 position to the leftcache_k = torch.roll(cache_k, -1, dims=2)cache_v = torch.roll(cache_v, -1, dims=2)k = cache_k.index_copy(2, input_pos, k)v = cache_v.index_copy(2, input_pos, v)kv_cache = k, v
1.将k,v resize为和kv_cache相匹配的形状(B,注意力头数,输入文本长度,各注意力头的维度)
2.将 k或v
的值放入 cache_k
中 input_pos
指定的索引位置,更新kv_cache (B,注意力头数,本次的最大文本长度,各注意力头的维度)
计算注意力
y = F.scaled_dot_product_attention(q, k, v, attn_mask=mask, dropout_p=0.0)
# causal self-attention; Self-attend: (B, nh, T, hs) x (B, nh, hs, T) -> (B, nh, T, T)
# att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))
# att = att.masked_fill(mask[:,:,:T,:T] == 0, float('-inf'))
# att = F.softmax(att, dim=-1)
# y = att @ v # (B, nh, T, T) x (B, nh, T, hs) -> (B, nh, T, hs)
计算缩放点积注意力(Scaled Dot-Product Attention),利用了高效的 Flash Attention CUDA 内核以加速计算
q的size为(B,注意力头数,输入文本长度,各注意力头的维度)
k,v的size为(B,注意力头数,本次的最大文本长度,各注意力头的维度)
mask的size为(1,1,输入文本长度,本次输入的最大文本长度)
y = y.transpose(1, 2).contiguous().view(B, T, C)
转换维度,将各注意力头的维度连接到一起后,输出维度为(B,输入文本长度,embedding维度)
经过线性层维度不变,返回本次循环Block的自注意力计算结果y和kv_cache
y = self.c_proj(y)
return y, kv_cache
残差连接
x = x + h
x = x + self.mlp(self.rms_2(x))
x是进入隐藏层之前的向量,即由文本对应索引经过embedding后的词嵌入
h是经过隐藏层计算注意力分数后,由x更新的隐藏层输出
由词嵌入和隐藏层输出残差连接后,再和反馈层进行残差连接
经过MLP层
经过RMSNorn归一化,作为MLP层的输入
def forward(self, x: torch.Tensor) -> torch.Tensor:# NOTE: the original RMSNorm paper implementation is not equivalent# norm_x = x.norm(2, dim=self.dim, keepdim=True)# rms_x = norm_x * d_x ** (-1. / 2)# x_normed = x / (rms_x + self.eps)norm_x = torch.mean(x * x, dim=self.dim, keepdim=True)x_normed = x * torch.rsqrt(norm_x + self.eps)return self.scale * x_normed
输出zise为 (B,输入文本长度,embedding维度)
x = F.silu(self.c_fc1(x)) * self.c_fc2(x)
分为F.silu(self.c_fc1(x))和self.c_fc2(x)两个部分相乘
维度大小的选取查看前面模型初始化的mlp
激活函数ReLU和SiLU的区别-CSDN博客
激活函数 Relu,Gelu,Mish,SiLU,Swish,Tanh,Sigmoid_gelu和silu-CSDN博客
大模型基础|激活函数|从ReLU 到SwiGLU
torch.nn.functional.silu — PyTorch 2.4 documentation
,其中
*: 这里的乘法是元素级的,即逐元素相乘。这意味着 F.silu(self.c_fc1(x)) 和 self.c_fc2(x) 的每个对应元素相乘,产生一个新的张量。
最后经过线性层后将11008维,还原为4096维(embedding维度)
本次循环的transfomer Block结束,进入下一次循环
RMSNorm归一化
x = self.transformer.ln_f(x)
经过32层transfomer Block后,再经过RMSNorm层进行归一化
def forward(self, x: torch.Tensor) -> torch.Tensor:# NOTE: the original RMSNorm paper implementation is not equivalent# norm_x = x.norm(2, dim=self.dim, keepdim=True)# rms_x = norm_x * d_x ** (-1. / 2)# x_normed = x / (rms_x + self.eps)norm_x = torch.mean(x * x, dim=self.dim, keepdim=True)x_normed = x * torch.rsqrt(norm_x + self.eps)return self.scale * x_normed
网络输出
logits = self.lm_head(x)输出维度为词库的大小,将输出的logits经过归一化计算选择词库中各个词的概率
五、生成下一分词的循环过程
temperature
温度越低,结果的差距越大,会使概率分布更加尖锐,从而使得模型更倾向于选择最高概率的类别。
选取前topk
if top_k is not None:v, _ = torch.topk(logits, min(top_k, logits.size(-1)))logits = torch.where(logits < v[[-1]], -float("Inf"), logits)
torch.topk(input, num)
返回input中指定的前num个值和对应的索引
torch.where(condition, x, y)
根据条件张量选择输出。对于每个位置,condition
为 True
时取 x
,为 False
时取 y
。v[[-1]]
选择 v
中的最后一个值,这个值是第 k
大的值。使用双重方括号是为了保持 v[[-1]]
的维度与 logits
相匹配。
选择当前时刻网络生成的分词
probs = torch.nn.functional.softmax(logits, dim=-1)
idx_next = torch.multinomial(probs, num_samples=1).to(dtype=dtype)
torch.nn.functional.softmax(input, dim)
对 input
张量的指定维度 dim
应用 softmax 操作
将 logits
转化为一个概率分布,每个值在 [0, 1] 之间,总和为 1。这样,模型的输出可以解释为各类别的预测概率
torch.multinomial(input, num_samples)
这个函数从 input
张量中根据给定的概率分布进行随机采样。input
: 在这里是 probs
,是一个概率分布张量,通常表示每个类别的预测概率。num_samples
: 设定要从概率分布中采样的数量。num_samples=1
表示只需要采样一个类别
将新生成的索引加入到输入文本中
input_pos = input_pos[-1:] + 1if idx.device.type == "xla":xm.mark_step()# concatenate the new generation
idx = idx.index_copy(0, input_pos, idx_next)
# if <eos> token is triggered, return the output (stop generation)
if idx_next == eos_id:return idx[:input_pos] # include the EOS token
更新input_pos
idx.index_copy(dim, index, source)
dim
: 这个参数指定了要更新的维度。在这里,dim=0
表示更新张量的第一维。index
: 这是一个包含索引的张量,指示 source
张量的值应该被复制到 idx
张量的哪些位置。source
: 这是一个包含要插入值的张量。在这里是 idx_next
,它是一个表示新值的张量
第二次循环
更新输入
根据更新的input_pos更新输入
更新旋转位置编码
rope_cache已经保存了可处理最大数据块大小对应的各个位置的旋转位置编码
根据位置直接选取,对应位置的旋转位置编码即可
更新mask
mask_cache已经保存各个位置对应的mask
根据位置直接选取对应的mask,然后根据本次的最大文本长度对mask进行截取即可
更新词嵌入
根据文本对应索引经过embedding,生成新分词对应的词嵌入
进入transfomer隐藏层
对新生成的分词进行RMSNorm
生成新的q,k,v
size均为(B,注意力头数,文本长度,各注意力头的维度)
更新k,v及kv_cache
size:(B,注意力头数,本次的最大文本长度,各注意力头的维度)
生成当前位置的注意力分数
生成第二次循环的隐藏层输出
残差连接
相关文章:

llama网络结构及源码
目录 模型初始化 config lm_head transformer wte h rms_1/rms_2 attn c_attn c_proj 线性层mlp ln_f rope_cache mask_cache kv_caches tokenizer tokenizer初始化 tokennizer.encoder 位置编码和mask 确定最大文本长度 建立rope_cache 建立mask_cache …...

828华为云征文|Flexus云服务器X实例部署宝塔运维面板
本次华为云Flexus云服务器X实例部署宝塔运维面板教学,这次是推陈出新啊 之前的云耀云服务器L实例已经很不错了,大力赞叹华为云的 同时感谢华为云提供优惠卷,只能说白嫖真是太棒了 华为云近期正在筹办华为云828企业节活动,90款免…...

计算机网络 8.*结构化布线
第八章 结构化布线 第一节 结构化布线基础 一、认识结构化布线 1.定义:在建筑物或楼宇内安装的传输线路,是一个用于语音、数据、影像和其他信息技术的标准结构化布线系统。 2.任务:使语音和数据通信设备、交换设备和其他信息管理系统彼此相…...

c#的委托、事件
程序目的:实现对一个bool型变量的监视,当数据变化时,调用某一个函数,引申出委托、事件等基础概念。 方法一、在form1的类定义中,定义如下代码,这样定义是最直接的,也非常简单,没有涉…...

Day23笔记-Day21和Day22作业讲解单例类
Day22作业讲解 学生类Student:属性:学号,姓名,年龄,性别,成绩 班级类 Grade:属性:班级名称,班级中的学生 【使用列表存储学生】 方法:1.查看该班级中的所有学生的信息2.查看指定学号的学生信息3.查看班级中成绩不…...

k8s中的存储
目录 一 configmap 1.1 configmap的功能 1.2 configmap的使用场景 1.3 configmap创建方式 1.3.1 字面值创建 1.3.2 通过文件创建 1.3.3 通过目录创建 1.3.4 通过yaml文件创建 1.3.5 configmap的使用方式 1.3.5.1 使用configmap填充环境变量 1.3.5.2 通过数据卷使用c…...

【Linux进程控制】进程程序替换
目录 进程程序替换 替换函数 看现象 替换原理 多进程替换 exec*函数使用(部分),并且认识函数参数的含义 1.execl 2.execv 3.execvp 4.execvpe execlp 和execlpe 替换函数总结 进程程序替换 替换函数 有六种以exec开头的函数&am…...

02 ETH
以太坊与比特币有什么不同? 以太坊立足比特币创新之上,于 2015 年启动,两者之间有一些显著不同。 比特币就仅仅是比特币;以太坊包括以太币,以太币才是和比特币对等的存在。以太坊是可编程的,所以你可以在…...

web渗透—RCE
一:代码执行 相关函数 1、eval()函数 assert()函数 (1)原理:将用户提交或者传递的字符串当作php代码执行 (2)passby:单引号绕过:闭合注释;开启GPC的话就无法绕过(GPC就是将单引号转换为"反斜杠单引号"&a…...

HomeAssistant显示节假日
先看效果 步骤: 新建卡片时选择“Markdown 卡片”代码在文章最下方,当然你也可以自己修改 点击保存/完成 ### {% if now().hour > 6 and now().hour < 9 -%} 早上好, {%- elif now().hour > 9 and now().hour < 12 -%} 上午好…...

AI问答-HTTP:理解 Content-Disposition
本文背景 在下载arraybuffer文件时,想要获取文件名,这时引入本文内容Content-Disposition,我们在Content-Disposition获取到文件名就可以在下载后的文件以该文件名命名了。 一、简介 Content-Disposition是HTTP协议中的一个响应头字段&…...

kubernetes架构
kubernetes cluster由master和node组成,节点上运行着若干kubernetes服务Master节点: master是kubernetes cluster的大脑,运行着的Daemon服务包括kube-apiserver,kube-scheduler,kube-controller-manager,etcd和Pod网络…...

【隐私计算篇】中国剩余定理解释以及Paillier解密加速应用
1. 背景介绍 本篇主要关注中国剩余定理的原理以及在paillier同态加密系统中的应用。在很多工作中,都可以看到中国剩余定理的影子,特别是同态加密提升计算效率的优化工作中,将paillier与中国剩余定理进行结合,能够实现在加密状态下…...

保护您的隐私:隐藏 IP 地址的重要性
在当今的数字时代,我们的在线隐私和安全变得比以往任何时候都更加重要。浏览互联网时保护自己的一种方法是隐藏您的 IP 地址。 但是为什么要隐藏您的 IP 地址以及如何有效地做到这一点? 隐藏您的 IP 地址有助于保护您的在线匿名性。您的 IP 地址就像您的…...

nodejs 007:错误npm error Error: EPERM: operation not permitted, symlink
完整错误信息 npm error Error: EPERM: operation not permitted, symlink npm warn cleanup Failed to remove some directories [ npm warn cleanup [ npm warn cleanup C:\\Users\\kingchuxing\\Documents\\IPFS\\orbit-db-set-master\\node_modules\\ipfs-cli, npm…...

Rsync未授权访问漏洞复现及彻底修复
一、什么是 Rsync? Rsync 是一种广泛使用的文件传输工具,它允许系统管理员和用户通过局域网(LAN)或广域网(WAN)在计算机之间同步文件和目录。Rsync 支持通过本地或远程 shell 访问,也可以作为守…...

影刀RPA实战:网页爬虫之携程酒店数据
1.实战目标 大家对于携程并不陌生,我们出行定机票,住酒店,去旅游胜地游玩,都离不开这样一个综合性的网站为我们提供信息,同时,如果你也是做旅游的公司,那携程就是一个业界竞争对手,…...

【UCB CS61C】Lecture 5 - Floating Point
目录 引入浮点数(Floating Point)定点表示法(Fixed-Point Model)科学记数法(Scientific Notation)记数法间的转换 IEEE 754 二进制浮点数算术标准实现目标单精度浮点编码阶码字段(The Exponent …...

【Binlog实战】:基于Spring监听Binlog日志
【Binlog实战】:基于Spring监听Binlog日志 binlog的三种模式 MySQL 的二进制日志(binlog)有三种不同的格式,通常被称为 binlog 模式。这三种模式分别是 Statement 模式、Row 模式和Mixed 模式。 Statement 模式: 在 …...

鸿蒙OpenHarmony【轻量系统芯片移植】轻量系统STM32F407芯片移植案例
轻量系统STM32F407芯片移植案例 介绍基于STM32F407IGT6芯片在拓维信息[Niobe407]开发板上移植OpenHarmony LiteOS-M轻量系统,提供交通、工业领域开发板解决方案。移植架构采用Board与SoC分离方案,使用arm gcc工具链Newlib C库,实现了lwip、l…...

基于SpringBoot+定时任务实现地图上绘制车辆实时运动轨迹图
目录 1. 项目结构 2. Maven依赖配置 (pom.xml) 3. 实现后端服务 4. 配置文件 (application.properties) 5. 启动项目 6. 访问页面 实现基于北斗卫星的车辆定位和轨迹图的Maven工程(使用模拟数据),我们将使用以下技术: Spri…...

Rasa对话模型——做一个语言助手
1、Rasa模型 1.1 模型介绍 Rasa是一个用于构建对话 AI 的开源框架,主要用于开发聊天机器人和语音助手。Rasa 提供了自然语言理解(NLU)和对话管理(DM)功能,使开发者能够创建智能、交互式的对话系统。 1.2…...

golang学习笔记19——golang做服务发现与注册的深度剖析
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...

ROS和ROS2借助智能大模型的学习和研究方法
机器人相关知识的本身和价值-CSDN博客 知识本身在智能时代毫无价值,需要基于知识应用和创新才有价值。 学历报废并非来自扩招,而是智能模型的快速发展。-CSDN blink-领先的开发者技术社区 2024年中秋,智能模型实力已经如此,但还…...

弹性负载均衡ELB 详解和设置方法
一、弹性负载均衡ELB 详解 1. 定义与概念 弹性负载均衡(Elastic Load Balancing,简称ELB)是一种将访问流量自动分发到多台云服务器的流量分发控制服务。它通过在多个后端服务器之间均衡分配请求,提高应用程序的可用性、可扩展性…...

Python3网络爬虫开发实战(15)Scrapy 框架的使用(第一版)
文章目录 一、Scrapy 框架介绍1.1 数据流1.2 项目结构1.3 Scrapy 入门 二、Selector 解析器2.1 XPath 和 CSS 选择器2.2 信息提取2.3 正则提取 三、Spider 的使用3.1 Spider 运行流程3.2 Spider 类分析3.3 Request3.4 Response 四、Download Middleware 的使用4.1 process_requ…...

大众点评代发排名骗局
大众点评代发排名骗局 不诋毁同行,不贬低对手,请各位老板擦亮眼睛,认真看完这篇文章,以防上当受骗#网络宣传#企业推广#企业推广 大众点评代发排名:一场精心编织的骗局 在这个美食如云的时代&…...

硬件基础知识
驱动开发分为:裸机驱动、linux驱动 嵌入式:以计算机技术为基础,软硬结合的、可移植、可剪裁的专用计算机 单片机最小单元:vcc gnd reset 晶振 cpu --- soc :system on chip 片上外设 所有的程序都是在soc(cpu&…...

使用gitee如何回滚上一个版本,简单操作方式-gitee自带功能无需使用代码
使用gitee如何回滚上一个版本,简单操作方式-gitee自带功能无需使用代码,很多朋友使用代码的话容易出错,gitee自带了本功能: 找到gitee代码仓库,找到对应的想要回滚的版本点击进去 点击revert,选择自己对应的…...

独立站技能树之建站33项自检清单 1.0丨出海笔记
很多时候大家建好站之后很嗨,但过一会就开始担忧各种纠结我是不是还有什么点没做好,或者我的站漏了什么东西,那么接下来以下这个独立站自检清单能很好的帮到你。其实对于新手我还是建议大家直接用一些模板,因为模板上面基本该有的…...