diff --git a/.gitignore b/.gitignore index f0246d5..616afb3 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ corpus/wikipedia-cn-20230720-filtered.json corpus/wikipedia.txt -corpus/*.jsonl +corpus/*/*.jsonl dolly_env_local llm_dolly.egg-info -src_llm/__pycache__ \ No newline at end of file +src_llm/__pycache__ +weights_MoE +weights_llm +weights_tokenizer/* \ No newline at end of file diff --git a/__init__.py b/__init__.py index b3c06d4..6713a8e 100755 --- a/__init__.py +++ b/__init__.py @@ -1 +1,5 @@ -__version__ = "0.0.1" \ No newline at end of file +__version__ = "0.0.1" +from src_llm_moe.configuration_dollyMoE import DollyMoEConfig +from src_llm_moe.modeling_dollyMoE import DollyMoEModel, DollyMoEPreTrainedModel +from src_llm.configuration_dolly import DollyConfig +from src_llm.modeling_dolly import DollyModel, DollyPreTrainedModel \ No newline at end of file diff --git a/src_llm/configuration_dolly.py b/src_llm/configuration_dolly.py index 1b76682..3367a96 100755 --- a/src_llm/configuration_dolly.py +++ b/src_llm/configuration_dolly.py @@ -28,11 +28,11 @@ class DollyConfig(PretrainedConfig): def __init__( self, vocab_size=151936, - hidden_size=4096, - intermediate_size=22016, - num_hidden_layers=32, - num_attention_heads=32, - num_key_value_heads=32, + hidden_size=1024, + intermediate_size=3072, + num_hidden_layers=28, + num_attention_heads=16, + num_key_value_heads=8, head_dim=128, hidden_act="silu", max_position_embeddings=32768, @@ -40,7 +40,7 @@ class DollyConfig(PretrainedConfig): rms_norm_eps=1e-6, use_cache=True, tie_word_embeddings=False, - rope_theta=10000.0, + rope_theta=1000000.0, rope_scaling=None, attention_bias=False, use_sliding_window=False, diff --git a/src_llm_moe/__init__.py b/src_llm_moe/__init__.py new file mode 100644 index 0000000..67e2dfd --- /dev/null +++ b/src_llm_moe/__init__.py @@ -0,0 +1,2 @@ +from .configuration_dollyMoE import DollyMoEConfig +from .modeling_dollyMoE import DollyMoEModel, DollyMoEPreTrainedModel \ No newline at end of file diff --git a/src_llm_moe/__pycache__/__init__.cpython-312.pyc b/src_llm_moe/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..b72ac68 Binary files /dev/null and b/src_llm_moe/__pycache__/__init__.cpython-312.pyc differ diff --git a/src_llm_moe/__pycache__/configuration_dollyMoE.cpython-312.pyc b/src_llm_moe/__pycache__/configuration_dollyMoE.cpython-312.pyc new file mode 100644 index 0000000..c71d156 Binary files /dev/null and b/src_llm_moe/__pycache__/configuration_dollyMoE.cpython-312.pyc differ diff --git a/src_llm_moe/__pycache__/modeling_dollyMoE.cpython-312.pyc b/src_llm_moe/__pycache__/modeling_dollyMoE.cpython-312.pyc new file mode 100644 index 0000000..682d2fb Binary files /dev/null and b/src_llm_moe/__pycache__/modeling_dollyMoE.cpython-312.pyc differ diff --git a/src_llm_moe/configuration_dollyMoE.py b/src_llm_moe/configuration_dollyMoE.py new file mode 100644 index 0000000..423f74f --- /dev/null +++ b/src_llm_moe/configuration_dollyMoE.py @@ -0,0 +1,95 @@ +from transformers import PretrainedConfig +from transformers import logging +from transformers.modeling_rope_utils import rope_config_validation +logger = logging.get_logger(__name__) + + +class DollyMoEConfig(PretrainedConfig): + model_type = "dolly_moe" + keys_to_ignore_at_inference = ["past_key_values"] + base_model_tp_plan = { + "layers.*.self_attn.q_proj": "colwise", + "layers.*.self_attn.k_proj": "colwise", + "layers.*.self_attn.v_proj": "colwise", + "layers.*.self_attn.o_proj": "rowwise", + "layers.*.mlp.experts.*.gate_proj": "colwise", + "layers.*.mlp.experts.*.up_proj": "colwise", + "layers.*.mlp.experts.*.down_proj": "rowwise", + "layers.*.mlp.gate_proj": "colwise", + "layers.*.mlp.up_proj": "colwise", + "layers.*.mlp.down_proj": "rowwise", + } + base_model_pp_plan = { + "embed_tokens": (["input_ids"], ["inputs_embeds"]), + "layers": (["hidden_states", "attention_mask"], ["hidden_states"]), + "norm": (["hidden_states"], ["hidden_states"]), + } + + def __init__( + self, + vocab_size=151936, + hidden_size=1024, + intermediate_size=3072, + num_hidden_layers=28, + num_attention_heads=16, + num_key_value_heads=8, + hidden_act="silu", + max_position_embeddings=32768, + initializer_range=0.02, + rms_norm_eps=1e-6, + use_cache=True, + tie_word_embeddings=False, + rope_theta=1000000.0, + rope_scaling=None, + attention_bias=False, + use_sliding_window=False, + sliding_window=4096, + max_window_layers=28, + attention_dropout=0.0, + decoder_sparse_step=1, + moe_intermediate_size=768, + num_experts_per_tok=4, + num_experts=8, + norm_topk_prob=False, + output_router_logits=False, + router_aux_loss_coef=0.001, + mlp_only_layers=None, + **kwargs, + ): + self.vocab_size = vocab_size + self.max_position_embeddings = max_position_embeddings + self.hidden_size = hidden_size + self.intermediate_size = intermediate_size + self.num_hidden_layers = num_hidden_layers + self.num_attention_heads = num_attention_heads + self.use_sliding_window = use_sliding_window + self.sliding_window = sliding_window if use_sliding_window else None + self.max_window_layers = max_window_layers + + self.num_key_value_heads = num_key_value_heads + self.hidden_act = hidden_act + self.initializer_range = initializer_range + self.rms_norm_eps = rms_norm_eps + self.use_cache = use_cache + self.rope_theta = rope_theta + self.rope_scaling = rope_scaling + self.attention_bias = attention_bias + self.attention_dropout = attention_dropout + if self.rope_scaling is not None and "type" in self.rope_scaling: + self.rope_scaling["rope_type"] = self.rope_scaling["type"] + rope_config_validation(self) + self.decoder_sparse_step = decoder_sparse_step + self.moe_intermediate_size = moe_intermediate_size + self.num_experts_per_tok = num_experts_per_tok + self.num_experts = num_experts + self.norm_topk_prob = norm_topk_prob + self.output_router_logits = output_router_logits + self.router_aux_loss_coef = router_aux_loss_coef + self.mlp_only_layers = [] if mlp_only_layers is None else mlp_only_layers + + super().__init__( + tie_word_embeddings=tie_word_embeddings, + **kwargs, + ) + +__all__ = ["DollyMoEConfig"] diff --git a/src_llm_moe/modeling_dollyMoE.py b/src_llm_moe/modeling_dollyMoE.py new file mode 100644 index 0000000..64941d1 --- /dev/null +++ b/src_llm_moe/modeling_dollyMoE.py @@ -0,0 +1,1034 @@ +from .configuration_dollyMoE import DollyMoEConfig +from transformers.modeling_utils import PreTrainedModel, ALL_ATTENTION_FUNCTIONS +from functools import partial +from typing import Callable, Optional, Tuple, Union +from transformers.activations import ACT2FN +from transformers.modeling_rope_utils import dynamic_rope_update, ROPE_INIT_FUNCTIONS +import torch +from torch import nn +import torch.nn.functional as F +from transformers.utils import can_return_tuple +from transformers.generation import GenerationMixin +from transformers.modeling_attn_mask_utils import AttentionMaskConverter +from transformers.modeling_flash_attention_utils import FlashAttentionKwargs +from transformers.utils.deprecation import deprecate_kwarg +from transformers.utils import logging,LossKwargs +from transformers.processing_utils import Unpack +from transformers.modeling_outputs import BaseModelOutputWithPast, MoeCausalLMOutputWithPast,QuestionAnsweringModelOutput, SequenceClassifierOutputWithPast, TokenClassifierOutput,MoeModelOutputWithPast +from transformers.cache_utils import Cache, DynamicCache, SlidingWindowCache, StaticCache +logger = logging.get_logger(__name__) +class DollyMoERMSNorm(nn.Module): + ''' + 输入的形状为batch_size*heads*seq_len*heads_dim, + 仅在最后一个维度进行归一化, + 参数量为heads_dim + ''' + def __init__(self, hidden_size, eps=1e-6): + super().__init__() + self.weight = nn.Parameter(torch.ones(hidden_size)) + #添加一个非零值,防止除零 + self.variance_epsilon = eps + + def forward(self, hidden_states): + input_dtype = hidden_states.dtype + hidden_states = hidden_states.to(torch.float32) + #x=(x^2)/n + variance = hidden_states.pow(2).mean(-1, keepdim=True) + #归一化并缩放 + hidden_states = (hidden_states * torch.rsqrt(variance + self.variance_epsilon)) * self.weight + return hidden_states.to(input_dtype) + + def extra_repr(self): + return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}" + +class DollyMoEMLP(nn.Module): + ''' + DollyMoEMLP层的实现, code from Qwen3 + 可训练参数量为: hidden_size * intermediate_size + hidden_size * intermediate_size + intermediate_size * hidden_size + ''' + #只传入需要的三个参数 + def __init__(self, hidden_size,intermediate_size,hidden_act): + super().__init__() + self.hidden_size = hidden_size + self.intermediate_size = intermediate_size + #可训练参数量 hidden_size * intermediate_size + self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) + #可训练参数量 hidden_size * intermediate_size + self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) + #可训练参数量 intermediate_size * hidden_size + self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False) + #默认激活函数SiLU,=Sigmoid*x,输出范围(0, ∞) + self.act_fn = ACT2FN[hidden_act] + + def forward(self, x): + #通过激活函数后的向量[batch_size*seq_len*intermediate_size]和扩展后的向量进行元素乘 + down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x)) + return down_proj + +class DollyMoERotaryEmbedding(nn.Module): + def __init__(self, config: DollyMoEConfig, device=None): + super().__init__() + + #获取"rope_type"的值,如果没有使用"default" + self.config = config + if hasattr(config, "rope_scaling") and config.rope_scaling is not None: + self.rope_type = config.rope_scaling.get("rope_type", config.rope_scaling.get("type")) + else: + self.rope_type = "default" + # self.rope_type = getattr(config, "rope_type", "default") + self.original_max_seq_len = config.max_position_embeddings + self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type] + #得到频率倒数,基础版本公式如下: + #inv_freq = 1.0 / (rope_theta ** (torch.arange(0, dim, 2) / dim)) + #得到一个长度为attention_dim/2的小数序列,如attention_dim=128,inv_freq=64 + inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device) + #注册缓存区 + self.register_buffer("inv_freq", inv_freq, persistent=False) + + @torch.no_grad() + @dynamic_rope_update + def forward(self, x, position_ids): + #将inv_freq进行维度扩展首先扩展为1*64*1,然后扩展为batch_size*64*1 + inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device) + #position_ids进行扩展batch_size* 1*seq_len + position_ids_expanded = position_ids[:, None, :].float() + device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu" + #强制float32,禁止混合精度 + with torch.autocast(device_type=device_type, enabled=False): + #矩阵乘以后,形状变为batch_size*64*seq_len后,再转为batch_size*seq_len*64 + freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2) + #沿64的维度进行拼接batch_size*seq_len*128 + emb = torch.cat((freqs, freqs), dim=-1) + #emb的cos()部分乘缩放系数:batch_size*seq_len*128 + cos = emb.cos() * self.attention_scaling + #emb的sin()部分乘缩放系数:batch_size*seq_len*128 + sin = emb.sin() * self.attention_scaling + return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype) + + +def rotate_half(x): + #x分为两段,各取batch_size*heads_num*seq_len*64 + x1 = x[..., : x.shape[-1] // 2] + x2 = x[..., x.shape[-1] // 2 :] + #下部分*-1,按下+上重新组合x + return torch.cat((-x2, x1), dim=-1) + +def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1): + ''' + 对q和k分别使用RoPE + ''' + #由batch_size*seq_len*128增加一个维度变为batch_size*1*seq_len*128 + cos = cos.unsqueeze(unsqueeze_dim) + sin = sin.unsqueeze(unsqueeze_dim) + #q:batch_size*heads_num*seq_len*128和sin及con进行元素乘batch_size*1*seq_len*128 + #cos部分直接乘,sin部分进行位置变化后再乘,最后相加完成位置编码的嵌入 + q_embed = (q * cos) + (rotate_half(q) * sin) + k_embed = (k * cos) + (rotate_half(k) * sin) + return q_embed, k_embed + + +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 + if n_rep == 1: + return hidden_states + #在第3维度[index=2]进行扩充 + 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) + +def eager_attention_forward( + module: nn.Module, + query: torch.Tensor, + key: torch.Tensor, + value: torch.Tensor, + attention_mask: Optional[torch.Tensor], + scaling: float, + dropout: float = 0.0, + **kwargs, +): + #repeat kv,确保形状和query一致 + key_states = repeat_kv(key, 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 + #casual attention + if attention_mask is not None: + #causal_mask应当为下三角为0,上三角为负无穷 + causal_mask = attention_mask[:, :, :, : key_states.shape[-2]] + attn_weights = attn_weights + causal_mask + # sofmax计算 + 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) + #乘value过程 + attn_output = torch.matmul(attn_weights, value_states) + #最后转置,形状变为batch_size*seq_len*num_heads*head_dim + attn_output = attn_output.transpose(1, 2).contiguous() + + return attn_output, attn_weights + + +class DollyMoEAttention(nn.Module): + """ + Attention in transformer + """ + def __init__(self, config: DollyMoEConfig, layer_idx: int): + super().__init__() + self.config = config + self.layer_idx = layer_idx + 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 + #attention socre的缩放系数 + self.scaling = self.head_dim**-0.5 + self.attention_dropout = config.attention_dropout + self.is_causal = True + #Q权重矩阵 + self.q_proj = nn.Linear( + config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias + ) + #K权重矩阵 + self.k_proj = nn.Linear( + config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias + ) + #V权重矩阵 + self.v_proj = nn.Linear( + config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias + ) + #Attention的最后一步,线性连接层 + self.o_proj = nn.Linear( + config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias + ) + #给输入q和k进行归一化操作,使用RMSNom,注意仅在最后一个维度进行归一化,参数量为head_dim + self.q_norm = DollyMoERMSNorm(self.head_dim, eps=config.rms_norm_eps) + self.k_norm = DollyMoERMSNorm(self.head_dim, eps=config.rms_norm_eps) + #支持滑动窗口 + self.sliding_window = config.sliding_window + if not ( + self.config.use_sliding_window + and getattr(self.config, "sliding_window", None) is not None + and self.layer_idx >= self.config.max_window_layers + ): + self.sliding_window = None + + def forward( + self, + hidden_states: torch.Tensor, + position_embeddings: Tuple[torch.Tensor, torch.Tensor], + attention_mask: Optional[torch.Tensor], + past_key_value: Optional[Cache] = None, + cache_position: Optional[torch.LongTensor] = None, + **kwargs: Unpack[FlashAttentionKwargs], + ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]: + #input_shape: batch_size* seq_len + input_shape = hidden_states.shape[:-1] + #hidden_shape: batch_size* seq_len*-1* 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) + #将输入经过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) + #将输入经过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) + #得到嵌入旋转位置编码信息后的query和key + cos, sin = position_embeddings + query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin) + + if past_key_value is not None: + # KVCache的cache更新位置信息和kv值 + 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) + + attention_interface: Callable = eager_attention_forward + if self.config._attn_implementation != "eager": + if self.config._attn_implementation == "sdpa" and kwargs.get("output_attentions", False): + logger.warning_once( + "`torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True`. Falling back to " + 'eager attention. This warning can be removed using the argument `attn_implementation="eager"` when loading the model.' + ) + else: + attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation] + #attention的具体计算,返回结果和中间的attention score + attn_output, attn_weights = attention_interface( + self, + query_states, + key_states, + value_states, + attention_mask, + dropout=0.0 if not self.training else self.attention_dropout, + scaling=self.scaling, + sliding_window=self.sliding_window, + **kwargs, + ) + #将batch_size*seq_len*num_heads*head_dim 变为 batch_size*seq_len*hiddent_size + attn_output = attn_output.reshape(*input_shape, -1).contiguous() + #attention的线性层 + attn_output = self.o_proj(attn_output) + return attn_output, attn_weights + +class DollyMoESparseMoeBlock(nn.Module): + def __init__(self, config): + super().__init__() + self.num_experts = config.num_experts + self.top_k = config.num_experts_per_tok + self.norm_topk_prob = config.norm_topk_prob + self.gate = nn.Linear(config.hidden_size, config.num_experts, bias=False) + self.experts = nn.ModuleList( + [DollyMoEMLP(config.hidden_size, config.intermediate_size, config.hidden_act) for _ in range(self.num_experts)] + ) + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + batch_size, sequence_length, hidden_dim = hidden_states.shape + hidden_states = hidden_states.view(-1, hidden_dim) + router_logits = self.gate(hidden_states) + routing_weights = F.softmax(router_logits, dim=1, dtype=torch.float) + routing_weights, selected_experts = torch.topk(routing_weights, self.top_k, dim=-1) + if self.norm_topk_prob: + routing_weights /= routing_weights.sum(dim=-1, keepdim=True) + routing_weights = routing_weights.to(hidden_states.dtype) + final_hidden_states = torch.zeros( + (batch_size * sequence_length, hidden_dim), dtype=hidden_states.dtype, device=hidden_states.device + ) + expert_mask = torch.nn.functional.one_hot(selected_experts, num_classes=self.num_experts).permute(2, 1, 0) + for expert_idx in range(self.num_experts): + expert_layer = self.experts[expert_idx] + idx, top_x = torch.where(expert_mask[expert_idx]) + current_state = hidden_states[None, top_x].reshape(-1, hidden_dim) + current_hidden_states = expert_layer(current_state) * routing_weights[top_x, idx, None] + final_hidden_states.index_add_(0, top_x, current_hidden_states.to(hidden_states.dtype)) + final_hidden_states = final_hidden_states.reshape(batch_size, sequence_length, hidden_dim) + return final_hidden_states, router_logits + +class DollyMoEDecoderLayer(nn.Module): + def __init__(self, config: DollyMoEConfig, layer_idx: int): + super().__init__() + self.hidden_size = config.hidden_size + self.self_attn = DollyMoEAttention(config=config, layer_idx=layer_idx) + if (layer_idx not in config.mlp_only_layers) and ( + config.num_experts > 0 and (layer_idx + 1) % config.decoder_sparse_step == 0 + ): + self.mlp = DollyMoESparseMoeBlock(config) + else: + self.mlp = DollyMoEMLP(config.hidden_size, config.intermediate_size, config.hidden_act) + self.input_layernorm = DollyMoERMSNorm(config.hidden_size, eps=config.rms_norm_eps) + self.post_attention_layernorm = DollyMoERMSNorm(config.hidden_size, eps=config.rms_norm_eps) + #仅flash_attention_2支持滑动窗口 + if config.sliding_window and config._attn_implementation != "flash_attention_2": + config.sliding_window = None + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_value: Optional[Cache] = None, + output_attentions: Optional[bool] = False, + output_router_logits: Optional[bool] = False, + use_cache: Optional[bool] = False, + cache_position: Optional[torch.LongTensor] = None, + position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, + **kwargs: Unpack[FlashAttentionKwargs], + ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]: + #保留最开始的值,后面做残差网络 + residual = hidden_states + #step1:归一化 + hidden_states = self.input_layernorm(hidden_states) + + #step2: Self Attention + hidden_states, self_attn_weights = self.self_attn( + hidden_states=hidden_states, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_value=past_key_value, + output_attentions=output_attentions, + use_cache=use_cache, + cache_position=cache_position, + position_embeddings=position_embeddings, + **kwargs, + ) + #step3:残差 + hidden_states = residual + hidden_states + residual = hidden_states + #step4:归一化 + hidden_states = self.post_attention_layernorm(hidden_states) + #step5:MLP + hidden_states = self.mlp(hidden_states) + if isinstance(hidden_states, tuple): + hidden_states, router_logits = hidden_states + else: + router_logits = None + #step6:残差 + hidden_states = residual + hidden_states + outputs = (hidden_states,) + #是否输出attention weights + if output_attentions: + outputs += (self_attn_weights,) + if output_router_logits: + outputs += (router_logits,) + return outputs + +class KwargsForCausalLM(FlashAttentionKwargs, LossKwargs): ... + +class DollyMoEPreTrainedModel(PreTrainedModel): + config_class = DollyMoEConfig + base_model_prefix = "model" + supports_gradient_checkpointing = True + _no_split_modules = ["DollyMoEDecoderLayer"] + _skip_keys_device_placement = ["past_key_values"] + _supports_flash_attn_2 = True + _supports_sdpa = True + _supports_flex_attn = True + _supports_cache_class = True + _supports_quantized_cache = True + _supports_static_cache = True + _supports_attention_backend = True + + def _init_weights(self, module): + std = self.config.initializer_range + if isinstance(module, nn.Linear): + #初始线性层化权重参数 + module.weight.data.normal_(mean=0.0, std=std) + if module.bias is not None: + module.bias.data.zero_() + elif isinstance(module, nn.Embedding): + #初始化embedding层参数 + module.weight.data.normal_(mean=0.0, std=std) + if module.padding_idx is not None: + module.weight.data[module.padding_idx].zero_() + +class DollyMoEModel(DollyMoEPreTrainedModel): + def __init__(self, config: DollyMoEConfig): + super().__init__(config) + self.padding_idx = config.pad_token_id + self.vocab_size = config.vocab_size + #embedding层 + self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx) + #transformer层 + self.layers = nn.ModuleList( + [DollyMoEDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)] + ) + #RMSNorm层 + self.norm = DollyMoERMSNorm(config.hidden_size, eps=config.rms_norm_eps) + #RoPE层 + self.rotary_emb = DollyMoERotaryEmbedding(config=config) + self.gradient_checkpointing = False + #进行模型初始化 + self.post_init() + + def get_input_embeddings(self): + return self.embed_tokens + + def set_input_embeddings(self, value): + self.embed_tokens = value + + @can_return_tuple + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Cache] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_router_logits: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + cache_position: Optional[torch.LongTensor] = None, + **flash_attn_kwargs: Unpack[FlashAttentionKwargs], + ) -> MoeModelOutputWithPast: + #是否输出attention的计算结果 + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_router_logits = ( + output_router_logits if output_router_logits is not None else self.config.output_router_logits + ) + #是否输出隐藏层状态 + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + #是否使用cache + use_cache = use_cache if use_cache is not None else self.config.use_cache + + if (input_ids is None) ^ (inputs_embeds is not None): + raise ValueError("You must specify exactly one of input_ids or inputs_embeds") + + if self.gradient_checkpointing and self.training and use_cache: + logger.warning_once( + "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`." + ) + use_cache = False + + if not isinstance(past_key_values, (type(None), Cache)): + raise ValueError("The `past_key_values` should be either a `Cache` object or `None`.") + + if inputs_embeds is None: + inputs_embeds = self.embed_tokens(input_ids) + + if use_cache and past_key_values is None: + past_key_values = DynamicCache() + + if cache_position is None: + past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0 + cache_position = torch.arange( + past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device + ) + + if position_ids is None: + position_ids = cache_position.unsqueeze(0) + + causal_mask = self._update_causal_mask( + attention_mask, inputs_embeds, cache_position, past_key_values, output_attentions + ) + + hidden_states = inputs_embeds + + #共享RoPE位置编码 + position_embeddings = self.rotary_emb(hidden_states, position_ids) + + # 否是输出hidden state + all_hidden_states = () if output_hidden_states else None + all_self_attns = () if output_attentions else None + all_router_logits = () if output_router_logits else None + #transformer的计算: + for decoder_layer in self.layers: + if output_hidden_states: + all_hidden_states += (hidden_states,) + #如果启用了梯度检查点,并且处于训练模式下,模型将调用 self._gradient_checkpointing_func, + # 该函数使用 partial 函数来计算并重新计算部分前向过程,从而节省内存。 + if self.gradient_checkpointing and self.training: + layer_outputs = self._gradient_checkpointing_func( + partial(decoder_layer.__call__, **flash_attn_kwargs), + hidden_states, + causal_mask, + position_ids, + past_key_values, + output_attentions, + output_router_logits, + use_cache, + cache_position, + position_embeddings, + ) + else: + layer_outputs = decoder_layer( + hidden_states, + attention_mask=causal_mask, + position_ids=position_ids, + past_key_value=past_key_values, + output_attentions=output_attentions, + output_router_logits=output_router_logits, + use_cache=use_cache, + cache_position=cache_position, + position_embeddings=position_embeddings, + **flash_attn_kwargs, + ) + + hidden_states = layer_outputs[0] + + if output_attentions: + all_self_attns += (layer_outputs[1],) + if output_router_logits: + all_router_logits += (layer_outputs[-1],) + #归一化 + hidden_states = self.norm(hidden_states) + + # 添加最后一层hidden_states + if output_hidden_states: + all_hidden_states += (hidden_states,) + #将结果打包为BaseModelOutputWithPast数据结构 + return MoeModelOutputWithPast( + last_hidden_state=hidden_states, + past_key_values=past_key_values, + hidden_states=all_hidden_states, + attentions=all_self_attns, + router_logits=all_router_logits, + ) + + def _update_causal_mask( + self, + attention_mask: torch.Tensor, + input_tensor: torch.Tensor, + cache_position: torch.Tensor, + past_key_values: Cache, + output_attentions: bool = False, + ): + #处理batch生成时padding问题 + if self.config._attn_implementation == "flash_attention_2": + if attention_mask is not None and past_key_values is not None: + is_padding_right = attention_mask[:, -1].sum().item() != input_tensor.size()[0] + if is_padding_right: + raise ValueError( + "You are attempting to perform batched generation with padding_side='right'" + " call `tokenizer.padding_side = 'left'` before tokenizing the input. " + ) + if attention_mask is not None and 0.0 in attention_mask: + return attention_mask + return None + + # For SDPA, when possible, we will rely on its `is_causal` argument instead of its `attn_mask` argument, in + # order to dispatch on Flash Attention 2. This feature is not compatible with static cache, as SDPA will fail + # to infer the attention mask. + past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0 + using_static_cache = isinstance(past_key_values, StaticCache) + using_sliding_window_cache = isinstance(past_key_values, SlidingWindowCache) + + # When output attentions is True, sdpa implementation's forward method calls the eager implementation's forward + if ( + self.config._attn_implementation == "sdpa" + and not (using_static_cache or using_sliding_window_cache) + and not output_attentions + ): + if AttentionMaskConverter._ignore_causal_mask_sdpa( + attention_mask, + inputs_embeds=input_tensor, + past_key_values_length=past_seen_tokens, + sliding_window=self.config.sliding_window, + is_training=self.training, + ): + return None + + dtype, device = input_tensor.dtype, input_tensor.device + min_dtype = torch.finfo(dtype).min + sequence_length = input_tensor.shape[1] + # SlidingWindowCache or StaticCache + if using_sliding_window_cache or using_static_cache: + target_length = past_key_values.get_max_cache_shape() + # DynamicCache or no cache + else: + target_length = ( + attention_mask.shape[-1] + if isinstance(attention_mask, torch.Tensor) + else past_seen_tokens + sequence_length + 1 + ) + + # In case the provided `attention` mask is 2D, we generate a causal mask here (4D). + causal_mask = self._prepare_4d_causal_attention_mask_with_cache_position( + attention_mask, + sequence_length=sequence_length, + target_length=target_length, + dtype=dtype, + device=device, + cache_position=cache_position, + batch_size=input_tensor.shape[0], + config=self.config, + past_key_values=past_key_values, + ) + + if ( + self.config._attn_implementation == "sdpa" + and attention_mask is not None + and attention_mask.device.type in ["cuda", "xpu"] + and not output_attentions + ): + causal_mask = AttentionMaskConverter._unmask_unattended(causal_mask, min_dtype) + + return causal_mask + + @staticmethod + def _prepare_4d_causal_attention_mask_with_cache_position( + attention_mask: torch.Tensor, + sequence_length: int, + target_length: int, + dtype: torch.dtype, + device: torch.device, + cache_position: torch.Tensor, + batch_size: int, + config: DollyMoEConfig, + past_key_values: Cache, + ): + if attention_mask is not None and attention_mask.dim() == 4: + # In this case we assume that the mask comes already in inverted form and requires no inversion or slicing. + causal_mask = attention_mask + else: + min_dtype = torch.finfo(dtype).min + causal_mask = torch.full( + (sequence_length, target_length), fill_value=min_dtype, dtype=dtype, device=device + ) + diagonal_attend_mask = torch.arange(target_length, device=device) > cache_position.reshape(-1, 1) + if config.sliding_window is not None: + # if we have sliding window, we should not attend to tokens beyond sliding window length, so we mask them out also + # the check is needed to verify is current checkpoint was trained with sliding window or not + if not isinstance(past_key_values, SlidingWindowCache) or sequence_length > target_length: + sliding_attend_mask = torch.arange(target_length, device=device) <= ( + cache_position.reshape(-1, 1) - config.sliding_window + ) + diagonal_attend_mask.bitwise_or_(sliding_attend_mask) + causal_mask *= diagonal_attend_mask + causal_mask = causal_mask[None, None, :, :].expand(batch_size, 1, -1, -1) + if attention_mask is not None: + causal_mask = causal_mask.clone() # copy to contiguous memory for in-place edit + if attention_mask.shape[-1] > target_length: + attention_mask = attention_mask[:, :target_length] + mask_length = attention_mask.shape[-1] + padding_mask = causal_mask[:, :, :, :mask_length] + attention_mask[:, None, None, :].to( + causal_mask.device + ) + padding_mask = padding_mask == 0 + causal_mask[:, :, :, :mask_length] = causal_mask[:, :, :, :mask_length].masked_fill( + padding_mask, min_dtype + ) + return causal_mask + +def load_balancing_loss_func( + gate_logits: Union[torch.Tensor, Tuple[torch.Tensor], None], + num_experts: Optional[int] = None, + top_k=2, + attention_mask: Optional[torch.Tensor] = None, +) -> Union[torch.Tensor, int]: + if gate_logits is None or not isinstance(gate_logits, tuple): + return 0 + + if isinstance(gate_logits, tuple): + compute_device = gate_logits[0].device + concatenated_gate_logits = torch.cat([layer_gate.to(compute_device) for layer_gate in gate_logits], dim=0) + + routing_weights = torch.nn.functional.softmax(concatenated_gate_logits, dim=-1) + + _, selected_experts = torch.topk(routing_weights, top_k, dim=-1) + + expert_mask = torch.nn.functional.one_hot(selected_experts, num_experts) + + if attention_mask is None: + tokens_per_expert = torch.mean(expert_mask.float(), dim=0) + router_prob_per_expert = torch.mean(routing_weights, dim=0) + else: + batch_size, sequence_length = attention_mask.shape + num_hidden_layers = concatenated_gate_logits.shape[0] // (batch_size * sequence_length) + + expert_attention_mask = ( + attention_mask[None, :, :, None, None] + .expand((num_hidden_layers, batch_size, sequence_length, top_k, num_experts)) + .reshape(-1, top_k, num_experts) + .to(compute_device) + ) + + + tokens_per_expert = torch.sum(expert_mask.float() * expert_attention_mask, dim=0) / torch.sum( + expert_attention_mask, dim=0 + ) + + router_per_expert_attention_mask = ( + attention_mask[None, :, :, None] + .expand((num_hidden_layers, batch_size, sequence_length, num_experts)) + .reshape(-1, num_experts) + .to(compute_device) + ) + + router_prob_per_expert = torch.sum(routing_weights * router_per_expert_attention_mask, dim=0) / torch.sum( + router_per_expert_attention_mask, dim=0 + ) + + overall_loss = torch.sum(tokens_per_expert * router_prob_per_expert.unsqueeze(0)) + return overall_loss * num_experts + +class DollyMoEForCausalLM(DollyMoEPreTrainedModel, GenerationMixin): + _tied_weights_keys = ["lm_head.weight"] + _tp_plan = {"lm_head": "colwise_rep"} + _pp_plan = {"lm_head": (["hidden_states"], ["logits"])} + + def __init__(self, config): + super().__init__(config) + self.model = DollyMoEModel(config) + self.vocab_size = config.vocab_size + self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False) + self.router_aux_loss_coef = config.router_aux_loss_coef + self.num_experts = config.num_experts + self.num_experts_per_tok = config.num_experts_per_tok + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self): + return self.model.embed_tokens + + def set_input_embeddings(self, value): + self.model.embed_tokens = value + + def get_output_embeddings(self): + return self.lm_head + + def set_output_embeddings(self, new_embeddings): + self.lm_head = new_embeddings + + def set_decoder(self, decoder): + self.model = decoder + + def get_decoder(self): + return self.model + + @can_return_tuple + @deprecate_kwarg("num_logits_to_keep", version="4.50", new_name="logits_to_keep") + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Cache] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + labels: Optional[torch.LongTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + output_router_logits: Optional[bool] = None, + cache_position: Optional[torch.LongTensor] = None, + logits_to_keep: Union[int, torch.Tensor] = 0, + **kwargs: Unpack[KwargsForCausalLM], + ) -> MoeCausalLMOutputWithPast: + + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + + # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn) + outputs: MoeModelOutputWithPast = self.model( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_values=past_key_values, + inputs_embeds=inputs_embeds, + use_cache=use_cache, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + output_router_logits=output_router_logits, + cache_position=cache_position, + **kwargs, + ) + + hidden_states = outputs.last_hidden_state + # Only compute necessary logits, and do not upcast them to float if we are not computing the loss + slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep + logits = self.lm_head(hidden_states[:, slice_indices, :]) + + loss = None + if labels is not None: + loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs) + aux_loss = None + if output_router_logits: + aux_loss = load_balancing_loss_func( + outputs.router_logits, + self.num_experts, + self.num_experts_per_tok, + attention_mask, + ) + if labels is not None: + loss += self.router_aux_loss_coef * aux_loss.to(loss.device) + return MoeCausalLMOutputWithPast( + loss=loss, + aux_loss=aux_loss, + logits=logits, + past_key_values=outputs.past_key_values, + hidden_states=outputs.hidden_states, + attentions=outputs.attentions, + router_logits=outputs.router_logits, + ) + +class DollyMoEForSequenceClassification(DollyMoEPreTrainedModel): + def __init__(self, config): + super().__init__(config) + self.num_labels = config.num_labels + self.model = DollyMoEModel(config) + self.score = nn.Linear(config.hidden_size, self.num_labels, bias=False) + + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self): + return self.model.embed_tokens + + def set_input_embeddings(self, value): + self.model.embed_tokens = value + + @can_return_tuple + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Cache] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + labels: Optional[torch.LongTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + ) -> SequenceClassifierOutputWithPast: + + transformer_outputs: BaseModelOutputWithPast = self.model( + input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_values=past_key_values, + inputs_embeds=inputs_embeds, + use_cache=use_cache, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + ) + hidden_states = transformer_outputs.last_hidden_state + logits = self.score(hidden_states) + + if input_ids is not None: + batch_size = input_ids.shape[0] + else: + batch_size = inputs_embeds.shape[0] + + if self.config.pad_token_id is None and batch_size != 1: + raise ValueError("Cannot handle batch sizes > 1 if no padding token is defined.") + if self.config.pad_token_id is None: + last_non_pad_token = -1 + elif input_ids is not None: + # To handle both left- and right- padding, we take the rightmost token that is not equal to pad_token_id + non_pad_mask = (input_ids != self.config.pad_token_id).to(logits.device, torch.int32) + token_indices = torch.arange(input_ids.shape[-1], device=logits.device, dtype=torch.int32) + last_non_pad_token = (token_indices * non_pad_mask).argmax(-1) + else: + last_non_pad_token = -1 + logger.warning_once( + f"{self.__class__.__name__} will not detect padding tokens in `inputs_embeds`. Results may be " + "unexpected if using padding tokens in conjunction with `inputs_embeds.`" + ) + + pooled_logits = logits[torch.arange(batch_size, device=logits.device), last_non_pad_token] + + loss = None + if labels is not None: + loss = self.loss_function(logits=logits, labels=labels, pooled_logits=pooled_logits, config=self.config) + + return SequenceClassifierOutputWithPast( + loss=loss, + logits=pooled_logits, + past_key_values=transformer_outputs.past_key_values, + hidden_states=transformer_outputs.hidden_states, + attentions=transformer_outputs.attentions, + ) + +class DollyMoEForTokenClassification(DollyMoEPreTrainedModel): + def __init__(self, config): + super().__init__(config) + self.num_labels = config.num_labels + self.model = DollyMoEModel(config) + if getattr(config, "classifier_dropout", None) is not None: + classifier_dropout = config.classifier_dropout + elif getattr(config, "hidden_dropout", None) is not None: + classifier_dropout = config.hidden_dropout + else: + classifier_dropout = 0.1 + self.dropout = nn.Dropout(classifier_dropout) + self.score = nn.Linear(config.hidden_size, config.num_labels) + + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self): + return self.model.embed_tokens + + def set_input_embeddings(self, value): + self.model.embed_tokens = value + + @can_return_tuple + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Cache] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + labels: Optional[torch.LongTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + ) -> TokenClassifierOutput: + + outputs: BaseModelOutputWithPast = self.model( + input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_values=past_key_values, + inputs_embeds=inputs_embeds, + use_cache=use_cache, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + ) + sequence_output = outputs.last_hidden_state + sequence_output = self.dropout(sequence_output) + logits = self.score(sequence_output) + + loss = None + if labels is not None: + loss = self.loss_function(logits, labels, self.config) + + return TokenClassifierOutput( + loss=loss, + logits=logits, + hidden_states=outputs.hidden_states, + attentions=outputs.attentions, + ) + +class DollyMoEForQuestionAnswering(DollyMoEPreTrainedModel): + base_model_prefix = "transformer" + + def __init__(self, config): + super().__init__(config) + self.transformer = DollyMoEModel(config) + self.qa_outputs = nn.Linear(config.hidden_size, 2) + + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self): + return self.transformer.embed_tokens + + def set_input_embeddings(self, value): + self.transformer.embed_tokens = value + + @can_return_tuple + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + attention_mask: Optional[torch.FloatTensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Cache] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + start_positions: Optional[torch.LongTensor] = None, + end_positions: Optional[torch.LongTensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + **kwargs, + ) -> QuestionAnsweringModelOutput: + + outputs: BaseModelOutputWithPast = self.transformer( + input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_values=past_key_values, + inputs_embeds=inputs_embeds, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + ) + + sequence_output = outputs.last_hidden_state + logits = self.qa_outputs(sequence_output) + start_logits, end_logits = logits.split(1, dim=-1) + start_logits = start_logits.squeeze(-1).contiguous() + end_logits = end_logits.squeeze(-1).contiguous() + + loss = None + if start_positions is not None and end_positions is not None: + loss = self.loss_function(start_logits, end_logits, start_positions, end_positions, **kwargs) + + return QuestionAnsweringModelOutput( + loss=loss, + start_logits=start_logits, + end_logits=end_logits, + hidden_states=outputs.hidden_states, + attentions=outputs.attentions, + ) + +__all__ = [ + "DollyMoEForCausalLM", + "DollyMoEForQuestionAnswering", + "DollyMoEModel", + "DollyMoEPreTrainedModel", + "DollyMoEForSequenceClassification", + "DollyMoEForTokenClassification", +] \ No newline at end of file diff --git a/src_pretrain/pretrain_deepspeed_MoE.py b/src_pretrain/pretrain_deepspeed_MoE.py new file mode 100644 index 0000000..bfacf05 --- /dev/null +++ b/src_pretrain/pretrain_deepspeed_MoE.py @@ -0,0 +1,120 @@ +import torch +from src_llm_moe.modeling_dollyMoE import DollyMoEForCausalLM +from transformers import ( + Trainer, + TrainingArguments, + DataCollatorForLanguageModeling, + AutoTokenizer, + set_seed +) +from datasets import load_dataset +from accelerate import Accelerator +import os +import logging +import glob + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +accelerator = Accelerator() +set_seed(42) + +model_name = "/mnt/han.luzhi/dolly/weights_MoE" +resume_option = None +# resume_option = True +# resume_option = "/mnt/han.luzhi/dolly_llm/checkpoints_ds/checkpoint-500" +tokenizer = AutoTokenizer.from_pretrained(model_name) +if tokenizer.pad_token is None: + tokenizer.pad_token = tokenizer.eos_token + +if isinstance(resume_option, str) and os.path.exists(resume_option): + logger.info(f"从指定检查点 {resume_option} 加载模型...") + model = DollyForCausalLM.from_pretrained(resume_option) +else: + logger.info("未找到检查点,从预训练模型加载...") + logger.info(f"从预训练模型 {model_name} 加载...") + model = DollyMoEForCausalLM.from_pretrained(model_name) +model.gradient_checkpointing_enable() + +data_files = glob.glob("/mnt/han.luzhi/dolly/corpus/*.jsonl") +logger.info(f"找到训练语料: {data_files}") + +dataset = load_dataset('json', data_files=data_files, split='train') +# dataset = load_dataset('text', data_files={'train': '/mnt/han.luzhi/dolly_llm/corpus/wikipedia.txt'}) + +def preprocess_function(examples): + return tokenizer( + examples['text'], + truncation=True, + max_length=512, + padding='max_length', + return_tensors='pt' + ) + +tokenized_datasets = dataset.map( + preprocess_function, + batched=True, + # remove_columns=['text'], + remove_columns=dataset.column_names, + num_proc=16 +) + +data_collator = DataCollatorForLanguageModeling( + tokenizer=tokenizer, + mlm=False +) + +training_args = TrainingArguments( + output_dir="/mnt/han.luzhi/dolly/checkpoints_MoE", + deepspeed="/mnt/han.luzhi/dolly/deepspeed_config/ds_stage2.json", + do_eval=False, + save_strategy="steps", + save_steps=500, + learning_rate=1e-4, + per_device_train_batch_size=16, + num_train_epochs=2, + logging_dir="/mnt/han.luzhi/dolly/logs", + logging_steps=20, + save_total_limit=2, + fp16=True, + dataloader_num_workers=3, + gradient_accumulation_steps=2, + report_to="tensorboard", + optim="adamw_torch", + lr_scheduler_type="cosine", + warmup_steps=500, + weight_decay=0.01, + local_rank=int(os.environ.get("LOCAL_RANK", 0)), + disable_tqdm=False, + logging_first_step=True, + log_level="info", + ddp_find_unused_parameters=False, + overwrite_output_dir=True, +) + +trainer = Trainer( + model=model, + args=training_args, + train_dataset=tokenized_datasets, + processing_class=tokenizer, + data_collator=data_collator, +) + +logger.info("***** 开始训练 *****") +logger.info(f" 进程数 = {accelerator.num_processes}") +logger.info(f" 设备 = {accelerator.device}") +logger.info(f" 总批大小 = {training_args.per_device_train_batch_size * accelerator.num_processes * training_args.gradient_accumulation_steps}") + +if resume_option !=None: + trainer.train(resume_from_checkpoint=resume_option) +else: + trainer.train() + + +if accelerator.is_main_process: + trainer.save_model("/mnt/han.luzhi/dolly/chechpoints_MoE/final") + tokenizer.save_pretrained("/mnt/han.luzhi/dolly/chechpoints_MoE/final") + logger.info("***** 训练完成,模型已保存 *****") + +## deepspeed --num_gpus=4 --master_port=12345 pretrain_transformers.py +# deepspeed --include="localhost:1,2,3" --master_port=12345 pretrain_transformers.py \ No newline at end of file diff --git a/test/compute_dollyMoE.py b/test/compute_dollyMoE.py new file mode 100644 index 0000000..052de0b --- /dev/null +++ b/test/compute_dollyMoE.py @@ -0,0 +1,18 @@ +from transformers.modeling_utils import PreTrainedModel +import torch +from torch import nn +from src_llm_moe.configuration_dollyMoE import DollyMoEConfig +from src_llm_moe.modeling_dollyMoE import DollyMoEModel,DollyMoEForCausalLM +model = DollyMoEForCausalLM(DollyMoEConfig()) +model.save_pretrained("./weights_MoE") +model.config.save_pretrained("./weights_MoE") + +config = DollyMoEConfig.from_pretrained("./weights_MoE") +model = DollyMoEForCausalLM.from_pretrained("./weights_MoE", config=config) + +input_ids = torch.tensor([[101, 1024, 102]]).long() +outputs = model(input_ids) +print(outputs) + +model_size = sum(t.numel() for t in model.parameters()) +print(f"Model Size: {model_size/1000**2:.1f}M parameters") \ No newline at end of file