add code comments
This commit is contained in:
+66
-36
@@ -18,12 +18,12 @@ from transformers.cache_utils import Cache, DynamicCache, SlidingWindowCache, St
|
|||||||
logger = logging.get_logger(__name__)
|
logger = logging.get_logger(__name__)
|
||||||
class DollyRMSNorm(nn.Module):
|
class DollyRMSNorm(nn.Module):
|
||||||
'''
|
'''
|
||||||
DollyRMSNorm code from Qwen3
|
输入的形状为batch_size*heads*seq_len*heads_dim,
|
||||||
可训练参数量为: hidden_size
|
仅在最后一个维度进行归一化,
|
||||||
|
参数量为heads_dim
|
||||||
'''
|
'''
|
||||||
def __init__(self, hidden_size, eps=1e-6):
|
def __init__(self, hidden_size, eps=1e-6):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
# 也是RMSNorm可学习的参数,参数量为hidden_size
|
|
||||||
self.weight = nn.Parameter(torch.ones(hidden_size))
|
self.weight = nn.Parameter(torch.ones(hidden_size))
|
||||||
#添加一个非零值,防止除零
|
#添加一个非零值,防止除零
|
||||||
self.variance_epsilon = eps
|
self.variance_epsilon = eps
|
||||||
@@ -74,6 +74,7 @@ class DollyRotaryEmbedding(nn.Module):
|
|||||||
self.rope_type = config.rope_scaling.get("rope_type", config.rope_scaling.get("type"))
|
self.rope_type = config.rope_scaling.get("rope_type", config.rope_scaling.get("type"))
|
||||||
else:
|
else:
|
||||||
self.rope_type = "default"
|
self.rope_type = "default"
|
||||||
|
# self.rope_type = getattr(config, "rope_type", "default")
|
||||||
self.original_max_seq_len = config.max_position_embeddings
|
self.original_max_seq_len = config.max_position_embeddings
|
||||||
self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
|
self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
|
||||||
#得到频率倒数,基础版本公式如下:
|
#得到频率倒数,基础版本公式如下:
|
||||||
@@ -113,7 +114,7 @@ def rotate_half(x):
|
|||||||
|
|
||||||
def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
||||||
'''
|
'''
|
||||||
对q和k使用RoPE
|
对q和k分别使用RoPE
|
||||||
'''
|
'''
|
||||||
#由batch_size*seq_len*128增加一个维度变为batch_size*1*seq_len*128
|
#由batch_size*seq_len*128增加一个维度变为batch_size*1*seq_len*128
|
||||||
cos = cos.unsqueeze(unsqueeze_dim)
|
cos = cos.unsqueeze(unsqueeze_dim)
|
||||||
@@ -126,10 +127,16 @@ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
|||||||
|
|
||||||
|
|
||||||
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
||||||
|
'''
|
||||||
|
在GQA中, k和v的heads数量小于q的heads数量,
|
||||||
|
所以在进行attention计算前需要进行repeat_kv操作,
|
||||||
|
保持第2维度的数量相等,n=config.num_attention_heads // config.num_key_value_heads
|
||||||
|
'''
|
||||||
|
#GQA中num_key_value_heads的数量小于attention heads数量
|
||||||
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
||||||
if n_rep == 1:
|
if n_rep == 1:
|
||||||
return hidden_states
|
return hidden_states
|
||||||
|
#在第3维度[index=2]进行扩充
|
||||||
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
||||||
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
||||||
|
|
||||||
@@ -143,49 +150,63 @@ def eager_attention_forward(
|
|||||||
dropout: float = 0.0,
|
dropout: float = 0.0,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
|
#repeat kv,确保形状和query一致
|
||||||
key_states = repeat_kv(key, module.num_key_value_groups)
|
key_states = repeat_kv(key, module.num_key_value_groups)
|
||||||
value_states = repeat_kv(value, module.num_key_value_groups)
|
value_states = repeat_kv(value, module.num_key_value_groups)
|
||||||
|
#计算attention score
|
||||||
attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
|
attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
|
||||||
|
#casual attention
|
||||||
if attention_mask is not None:
|
if attention_mask is not None:
|
||||||
|
#causal_mask应当为下三角为0,上三角为负无穷
|
||||||
causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
|
causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
|
||||||
attn_weights = attn_weights + causal_mask
|
attn_weights = attn_weights + causal_mask
|
||||||
|
# sofmax计算
|
||||||
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
||||||
|
# 训练时给attn_weights的随机位置置零
|
||||||
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
||||||
|
#乘value过程
|
||||||
attn_output = torch.matmul(attn_weights, value_states)
|
attn_output = torch.matmul(attn_weights, value_states)
|
||||||
|
#最后转置,形状变为batch_size*seq_len*num_heads*head_dim
|
||||||
attn_output = attn_output.transpose(1, 2).contiguous()
|
attn_output = attn_output.transpose(1, 2).contiguous()
|
||||||
|
|
||||||
return attn_output, attn_weights
|
return attn_output, attn_weights
|
||||||
|
|
||||||
|
|
||||||
class DollyAttention(nn.Module):
|
class DollyAttention(nn.Module):
|
||||||
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
"""
|
||||||
|
Attention in transformer
|
||||||
|
"""
|
||||||
def __init__(self, config: DollyConfig, layer_idx: int):
|
def __init__(self, config: DollyConfig, layer_idx: int):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.config = config
|
self.config = config
|
||||||
self.layer_idx = layer_idx
|
self.layer_idx = layer_idx
|
||||||
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
||||||
|
#num_key_value_groups即repeat kv的n
|
||||||
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
||||||
|
#attention socre的缩放系数
|
||||||
self.scaling = self.head_dim**-0.5
|
self.scaling = self.head_dim**-0.5
|
||||||
self.attention_dropout = config.attention_dropout
|
self.attention_dropout = config.attention_dropout
|
||||||
self.is_causal = True
|
self.is_causal = True
|
||||||
|
#Q权重矩阵
|
||||||
self.q_proj = nn.Linear(
|
self.q_proj = nn.Linear(
|
||||||
config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias
|
config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias
|
||||||
)
|
)
|
||||||
|
#K权重矩阵
|
||||||
self.k_proj = nn.Linear(
|
self.k_proj = nn.Linear(
|
||||||
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
||||||
)
|
)
|
||||||
|
#V权重矩阵
|
||||||
self.v_proj = nn.Linear(
|
self.v_proj = nn.Linear(
|
||||||
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
||||||
)
|
)
|
||||||
|
#Attention的最后一步,线性连接层
|
||||||
self.o_proj = nn.Linear(
|
self.o_proj = nn.Linear(
|
||||||
config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias
|
config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias
|
||||||
)
|
)
|
||||||
self.q_norm = DollyRMSNorm(self.head_dim, eps=config.rms_norm_eps) # unlike olmo, only on the head dim!
|
#给输入q和k进行归一化操作,使用RMSNom,注意仅在最后一个维度进行归一化,参数量为head_dim
|
||||||
self.k_norm = DollyRMSNorm(self.head_dim, eps=config.rms_norm_eps) # thus post q_norm does not need reshape
|
self.q_norm = DollyRMSNorm(self.head_dim, eps=config.rms_norm_eps)
|
||||||
|
self.k_norm = DollyRMSNorm(self.head_dim, eps=config.rms_norm_eps)
|
||||||
|
#支持滑动窗口
|
||||||
self.sliding_window = config.sliding_window
|
self.sliding_window = config.sliding_window
|
||||||
if not (
|
if not (
|
||||||
self.config.use_sliding_window
|
self.config.use_sliding_window
|
||||||
@@ -203,18 +224,22 @@ class DollyAttention(nn.Module):
|
|||||||
cache_position: Optional[torch.LongTensor] = None,
|
cache_position: Optional[torch.LongTensor] = None,
|
||||||
**kwargs: Unpack[FlashAttentionKwargs],
|
**kwargs: Unpack[FlashAttentionKwargs],
|
||||||
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
||||||
|
#input_shape: batch_size* seq_len
|
||||||
input_shape = hidden_states.shape[:-1]
|
input_shape = hidden_states.shape[:-1]
|
||||||
|
#hidden_shape: batch_size* seq_len*-1* head_dim
|
||||||
hidden_shape = (*input_shape, -1, self.head_dim)
|
hidden_shape = (*input_shape, -1, self.head_dim)
|
||||||
|
#将输入经过Q矩阵变为query,然后调整形状为batch_size* seq_len*-1* head_dim,然后进行归一化,再调整形状batch_size* -1*seq_len* head_dim
|
||||||
query_states = self.q_norm(self.q_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
|
query_states = self.q_norm(self.q_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
|
||||||
|
#将输入经过K矩阵变为key,然后调整形状为batch_size* seq_len*-1* head_dim,然后进行归一化,再调整形状batch_size* -1*seq_len* head_dim
|
||||||
key_states = self.k_norm(self.k_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
|
key_states = self.k_norm(self.k_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
|
||||||
|
#将输入经过V矩阵变为value,然后调整形状为batch_size* seq_len*-1* head_dim,再调整形状batch_size* -1*seq_len* head_dim
|
||||||
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
||||||
|
#得到嵌入旋转位置编码信息后的query和key
|
||||||
cos, sin = position_embeddings
|
cos, sin = position_embeddings
|
||||||
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
||||||
|
|
||||||
if past_key_value is not None:
|
if past_key_value is not None:
|
||||||
# sin and cos are specific to RoPE models; cache_position needed for the static cache
|
# KVCache的cache更新位置信息和kv值
|
||||||
cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
|
cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
|
||||||
key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
|
key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
|
||||||
|
|
||||||
@@ -227,7 +252,7 @@ class DollyAttention(nn.Module):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
|
attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
|
||||||
|
#attention的具体计算,返回结果和中间的attention score
|
||||||
attn_output, attn_weights = attention_interface(
|
attn_output, attn_weights = attention_interface(
|
||||||
self,
|
self,
|
||||||
query_states,
|
query_states,
|
||||||
@@ -236,11 +261,12 @@ class DollyAttention(nn.Module):
|
|||||||
attention_mask,
|
attention_mask,
|
||||||
dropout=0.0 if not self.training else self.attention_dropout,
|
dropout=0.0 if not self.training else self.attention_dropout,
|
||||||
scaling=self.scaling,
|
scaling=self.scaling,
|
||||||
sliding_window=self.sliding_window, # diff with Llama
|
sliding_window=self.sliding_window,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
#将batch_size*seq_len*num_heads*head_dim 变为 batch_size*seq_len*hiddent_size
|
||||||
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
||||||
|
#attention的线性层
|
||||||
attn_output = self.o_proj(attn_output)
|
attn_output = self.o_proj(attn_output)
|
||||||
return attn_output, attn_weights
|
return attn_output, attn_weights
|
||||||
|
|
||||||
@@ -252,13 +278,9 @@ class DollyDecoderLayer(nn.Module):
|
|||||||
self.mlp = DollyMLP(config.hidden_size, config.intermediate_size, config.hidden_act)
|
self.mlp = DollyMLP(config.hidden_size, config.intermediate_size, config.hidden_act)
|
||||||
self.input_layernorm = DollyRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
self.input_layernorm = DollyRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
||||||
self.post_attention_layernorm = DollyRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
self.post_attention_layernorm = DollyRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
||||||
if (
|
#仅flash_attention_2支持滑动窗口
|
||||||
config.sliding_window and config._attn_implementation != "flash_attention_2"
|
if config.sliding_window and config._attn_implementation != "flash_attention_2":
|
||||||
): # diff with Llama is this warning
|
config.sliding_window = None
|
||||||
logger.warning_once(
|
|
||||||
f"Sliding Window Attention is enabled but not implemented for `{config._attn_implementation}`; "
|
|
||||||
"unexpected results may be encountered."
|
|
||||||
)
|
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
@@ -269,14 +291,15 @@ class DollyDecoderLayer(nn.Module):
|
|||||||
output_attentions: Optional[bool] = False,
|
output_attentions: Optional[bool] = False,
|
||||||
use_cache: Optional[bool] = False,
|
use_cache: Optional[bool] = False,
|
||||||
cache_position: Optional[torch.LongTensor] = None,
|
cache_position: Optional[torch.LongTensor] = None,
|
||||||
position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, # necessary, but kept here for BC
|
position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
|
||||||
**kwargs: Unpack[FlashAttentionKwargs],
|
**kwargs: Unpack[FlashAttentionKwargs],
|
||||||
) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
|
) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
|
||||||
|
#保留最开始的值,后面做残差网络
|
||||||
residual = hidden_states
|
residual = hidden_states
|
||||||
|
#step1:归一化
|
||||||
hidden_states = self.input_layernorm(hidden_states)
|
hidden_states = self.input_layernorm(hidden_states)
|
||||||
|
|
||||||
# Self Attention
|
#step2: Self Attention
|
||||||
hidden_states, self_attn_weights = self.self_attn(
|
hidden_states, self_attn_weights = self.self_attn(
|
||||||
hidden_states=hidden_states,
|
hidden_states=hidden_states,
|
||||||
attention_mask=attention_mask,
|
attention_mask=attention_mask,
|
||||||
@@ -288,21 +311,23 @@ class DollyDecoderLayer(nn.Module):
|
|||||||
position_embeddings=position_embeddings,
|
position_embeddings=position_embeddings,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
#step3:残差
|
||||||
hidden_states = residual + hidden_states
|
hidden_states = residual + hidden_states
|
||||||
|
|
||||||
# Fully Connected
|
|
||||||
residual = hidden_states
|
residual = hidden_states
|
||||||
|
#step4:归一化
|
||||||
hidden_states = self.post_attention_layernorm(hidden_states)
|
hidden_states = self.post_attention_layernorm(hidden_states)
|
||||||
|
#step5:MLP
|
||||||
hidden_states = self.mlp(hidden_states)
|
hidden_states = self.mlp(hidden_states)
|
||||||
|
#step6:残差
|
||||||
hidden_states = residual + hidden_states
|
hidden_states = residual + hidden_states
|
||||||
|
|
||||||
outputs = (hidden_states,)
|
outputs = (hidden_states,)
|
||||||
|
#是否输出attention weights
|
||||||
if output_attentions:
|
if output_attentions:
|
||||||
outputs += (self_attn_weights,)
|
outputs += (self_attn_weights,)
|
||||||
|
|
||||||
return outputs
|
return outputs
|
||||||
|
|
||||||
class KwargsForCausalLM(FlashAttentionKwargs, LossKwargs): ...
|
class KwargsForCausalLM(FlashAttentionKwargs, LossKwargs): ...
|
||||||
|
|
||||||
class DollyPreTrainedModel(PreTrainedModel):
|
class DollyPreTrainedModel(PreTrainedModel):
|
||||||
config_class = DollyConfig
|
config_class = DollyConfig
|
||||||
base_model_prefix = "model"
|
base_model_prefix = "model"
|
||||||
@@ -320,10 +345,12 @@ class DollyPreTrainedModel(PreTrainedModel):
|
|||||||
def _init_weights(self, module):
|
def _init_weights(self, module):
|
||||||
std = self.config.initializer_range
|
std = self.config.initializer_range
|
||||||
if isinstance(module, nn.Linear):
|
if isinstance(module, nn.Linear):
|
||||||
|
#初始线性层化权重参数
|
||||||
module.weight.data.normal_(mean=0.0, std=std)
|
module.weight.data.normal_(mean=0.0, std=std)
|
||||||
if module.bias is not None:
|
if module.bias is not None:
|
||||||
module.bias.data.zero_()
|
module.bias.data.zero_()
|
||||||
elif isinstance(module, nn.Embedding):
|
elif isinstance(module, nn.Embedding):
|
||||||
|
#初始化embedding层参数
|
||||||
module.weight.data.normal_(mean=0.0, std=std)
|
module.weight.data.normal_(mean=0.0, std=std)
|
||||||
if module.padding_idx is not None:
|
if module.padding_idx is not None:
|
||||||
module.weight.data[module.padding_idx].zero_()
|
module.weight.data[module.padding_idx].zero_()
|
||||||
@@ -333,15 +360,18 @@ class DollyModel(DollyPreTrainedModel):
|
|||||||
super().__init__(config)
|
super().__init__(config)
|
||||||
self.padding_idx = config.pad_token_id
|
self.padding_idx = config.pad_token_id
|
||||||
self.vocab_size = config.vocab_size
|
self.vocab_size = config.vocab_size
|
||||||
|
#embedding层
|
||||||
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
||||||
|
#transformer层
|
||||||
self.layers = nn.ModuleList(
|
self.layers = nn.ModuleList(
|
||||||
[DollyDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
[DollyDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
||||||
)
|
)
|
||||||
|
#RMSNorm层
|
||||||
self.norm = DollyRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
self.norm = DollyRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
||||||
|
#RoPE层
|
||||||
self.rotary_emb = DollyRotaryEmbedding(config=config)
|
self.rotary_emb = DollyRotaryEmbedding(config=config)
|
||||||
self.gradient_checkpointing = False
|
self.gradient_checkpointing = False
|
||||||
|
#进行模型初始化
|
||||||
self.post_init()
|
self.post_init()
|
||||||
|
|
||||||
def get_input_embeddings(self):
|
def get_input_embeddings(self):
|
||||||
@@ -610,7 +640,7 @@ class DollyModel(DollyPreTrainedModel):
|
|||||||
return causal_mask
|
return causal_mask
|
||||||
|
|
||||||
|
|
||||||
class Qwen3ForCausalLM(DollyPreTrainedModel, GenerationMixin):
|
class DollyForCausalLM(DollyPreTrainedModel, GenerationMixin):
|
||||||
_tied_weights_keys = ["lm_head.weight"]
|
_tied_weights_keys = ["lm_head.weight"]
|
||||||
_tp_plan = {"lm_head": "colwise_rep"}
|
_tp_plan = {"lm_head": "colwise_rep"}
|
||||||
_pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
|
_pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
|
||||||
|
|||||||
Reference in New Issue
Block a user