[LLM] Add qwen3 (#10524)
* init qwen3 * first version. * fisrt version support for qwen3 * add missing files. * add readme * refine copyright. * init version for qwen moe. * fix networks. * fix generate. * refine * fix set_state_dict to slow for supper large network for network, such as moe model. * fix * fix * fix set_state_dict to slow for supper large network for network, such as moe model. * fix qwen2 tensor parallel. --------- Co-authored-by: DrownFish19 <DrownFish19@gmail.com>
This commit is contained in:
10
README.md
10
README.md
@@ -33,17 +33,20 @@
|
||||
|
||||
## News 📢
|
||||
|
||||
* **2025.03.17 《DeepSeek-R1满血版单机部署实测》** 🔥🔥🔥 飞桨框架3.0大模型推理部署全面升级,支持多款主流大模型,DeepSeek-R1满血版实现单机部署,吞吐提升一倍!欢迎广大用户开箱体验~现已开启有奖活动:完成 DeepSeek-R1-MTP 单机部署任务、提交高质量测评 blog,即可实时赢取奖金!💰💰💰
|
||||
报名[地址](https://www.wjx.top/vm/OlzzmbG.aspx#), 活动详情:https://github.com/PaddlePaddle/PaddleNLP/issues/10166 , 参考文档:https://github.com/PaddlePaddle/PaddleNLP/issues/10157 。
|
||||
* **2025.04.29 PaddleNLP 现已支持 Qwen3 系列模型**: Qwen3 系列模型支持持两种思考模式,预训练约 36 万亿个 token、119 种语言和方言。包括六个 Dense 模型, Qwen3-32B、Qwen3-14B、Qwen3-8B、Qwen3-4B、Qwen3-1.7B 和 Qwen3-0.6B。两个 MoE 模型的权重:Qwen3-235B-A22B,Qwen3-30B-A3B。
|
||||
|
||||
* **2025.03.12 [PaddleNLP v3.0 Beta4](https://github.com/PaddlePaddle/PaddleNLP/releases/tag/v3.0.0-beta4)**:全面支持 DeepSeek V3/R1/R1-Distill, 及 QwQ-32B 等热门思考模型。**DeepSeek V3/R1完整版支持 FP8、INT8、4-bit 量化推理,MTP 投机解码**。单机 FP8推理输出超**1000 tokens/s**; 4-bit 推理输出超**2100 tokens/s**! 发布新版推理部署镜像,热门模型[一键部署](https://paddlenlp.readthedocs.io/zh/latest/llm/server/docs/general_model_inference.html)。推理部署[使用文档](https://paddlenlp.readthedocs.io/zh/latest/llm/docs/predict/index.html)全面更新,体验全面提升!自研下一代通用信息抽取模型 PP-UIE [全新发布](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/application/information_extraction),支持8K 长度信息抽取。新增大模型 Embedding 训练,支持 INF-CL 超大 batch size 训练。新增[MergeKit](https://paddlenlp.readthedocs.io/zh/latest/llm/docs/mergekit.html)模型融合工具,缓解对齐代价。低资源训练全面优化,16G 小显存可以流畅训练。
|
||||
|
||||
* **2025.03.06 PaddleNLP 现已支持 Qwen/QwQ-32B 模型**: 其模型参数仅有 32B,但其数学推理、编程能力和通用能力可与具备 671B 参数(其中 37B 被激活)的 DeepSeek-R1 媲美。借助 PaddleNLP 3.0套件,现可实现多种并行策略[微调训练](./llm/README.md)、[高性能推理、低比特量化](./llm/docs/predict/qwen.md)和[服务化部署](./llm/server/README.md)。
|
||||
|
||||
* **2025.02.10 PaddleNLP 现已支持 DeepSeek-R1系列模型,[在线使用](https://aistudio.baidu.com/projectdetail/8775758)**:依托全新的 PaddleNLP 3.0套件,DeepSeek-R1系列模型现已全面支持。凭借数据并行、数据分组切分并行、模型并行、流水线并行以及专家并行等一系列先进的分布式训练能力,结合 Paddle 框架独有的列稀疏注意力掩码表示技术——FlashMask 方法,DeepSeek-R1系列模型在训练过程中显著降低了显存消耗,同时取得了卓越的训练性能提升。
|
||||
|
||||
<details><summary> <b>点击展开</b> </summary><div>
|
||||
|
||||
* **2025.03.17 《DeepSeek-R1满血版单机部署实测》** 🔥🔥🔥 飞桨框架3.0大模型推理部署全面升级,支持多款主流大模型,DeepSeek-R1满血版实现单机部署,吞吐提升一倍!欢迎广大用户开箱体验~现已开启有奖活动:完成 DeepSeek-R1-MTP 单机部署任务、提交高质量测评 blog,即可实时赢取奖金!💰💰💰
|
||||
报名[地址](https://www.wjx.top/vm/OlzzmbG.aspx#), 活动详情:https://github.com/PaddlePaddle/PaddleNLP/issues/10166 , 参考文档:https://github.com/PaddlePaddle/PaddleNLP/issues/10157 。
|
||||
|
||||
* **2025.03.06 PaddleNLP 现已支持 Qwen/QwQ-32B 模型**: 其模型参数仅有 32B,但其数学推理、编程能力和通用能力可与具备 671B 参数(其中 37B 被激活)的 DeepSeek-R1 媲美。借助 PaddleNLP 3.0套件,现可实现多种并行策略[微调训练](./llm/README.md)、[高性能推理、低比特量化](./llm/docs/predict/qwen.md)和[服务化部署](./llm/server/README.md)。
|
||||
|
||||
* **2025.02.20 🔥🔥《PP-UIE 信息抽取智能引擎全新升级》** 强化零样本学习能力,支持极少甚至零标注数据实现高效冷启动与迁移学习,显著降低数据标注成本;具备处理长文本能力,支持 8192 个 Token 长度文档信息抽取,实现跨段落识别关键信息,形成完整理解;提供完整可定制化的训练和推理全流程,训练效率相较于 LLama-Factory 实现了1.8倍的提升。
|
||||
2月26日(周三)19:00为您深度解析全新 PP-UIE 技术方案及在部署方面的功能、优势与技巧。报名链接:https://www.wjx.top/vm/mBKC6pb.aspx?udsid=606418
|
||||
|
||||
@@ -119,6 +122,7 @@
|
||||
| [Qwen2.5](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen2.5-0.5B, Qwen/Qwen2.5-0.5B-Instruct, Qwen/Qwen2.5-1.5B, Qwen/Qwen2.5-1.5B-Instruct, Qwen/Qwen2.5-3B, Qwen/Qwen2.5-3B-Instruct, Qwen/Qwen2.5-7B, Qwen/Qwen2.5-7B-Instruct, Qwen/Qwen2.5-7B-Instruct-1M, Qwen/Qwen2.5-14B, Qwen/Qwen2.5-14B-Instruct, Qwen/Qwen2.5-14B-Instruct-1M, Qwen/Qwen2.5-32B, Qwen/Qwen2.5-32B-Instruct, Qwen/Qwen2.5-72B, Qwen/Qwen2.5-72B-Instruct |
|
||||
| [Qwen2.5-Math](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen2.5-Math-1.5B, Qwen/Qwen2.5-Math-1.5B-Instruct, Qwen/Qwen2.5-Math-7B, Qwen/Qwen2.5-Math-7B-Instruct, Qwen/Qwen2.5-Math-72B, Qwen/Qwen2.5-Math-72B-Instruct, Qwen/Qwen2.5-Math-RM-72B |
|
||||
| [Qwen2.5-Coder](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen2.5-Coder-1.5B, Qwen/Qwen2.5-Coder-1.5B-Instruct, Qwen/Qwen2.5-Coder-7B, Qwen/Qwen2.5-Coder-7B-Instruct |
|
||||
| [Qwen3](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/Qwen3-0.6B, Qwen/Qwen3-1.7B, Qwen/Qwen3-4B, Qwen/Qwen3-8B, Qwen/Qwen3-14B, Qwen/Qwen3-32B, Qwen/Qwen3-30B-A3B, Qwen/Qwen3-235B-A22B, Qwen/Qwen3-0.6B-Base, Qwen/Qwen3-1.7B-Base, Qwen/Qwen3-4B-Base, Qwen/Qwen3-8B-Base, Qwen/Qwen3-14B-Base, Qwen/Qwen3-30B-A3B-Base |
|
||||
| [QwQ](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/qwen/) | Qwen/QwQ-32B, Qwen/QwQ-32B-Preview |
|
||||
| [Yuan2](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/llm/config/yuan/) | IEITYuan/Yuan2-2B, IEITYuan/Yuan2-51B, IEITYuan/Yuan2-102B |
|
||||
|
||||
|
||||
@@ -261,6 +261,8 @@ from .prophetnet.tokenizer import *
|
||||
from .qwen import *
|
||||
from .qwen2 import *
|
||||
from .qwen2_moe import *
|
||||
from .qwen3 import *
|
||||
from .qwen3_moe import *
|
||||
from .reformer.configuration import *
|
||||
from .reformer.modeling import *
|
||||
from .reformer.tokenizer import *
|
||||
|
||||
@@ -99,6 +99,8 @@ CONFIG_MAPPING_NAMES = OrderedDict(
|
||||
("qwen", "QWenConfig"),
|
||||
("qwen2", "Qwen2Config"),
|
||||
("qwen2_moe", "Qwen2MoeConfig"),
|
||||
("qwen3", "Qwen3Config"),
|
||||
("qwen3_moe", "Qwen3MoeConfig"),
|
||||
("reformer", "ReformerConfig"),
|
||||
("rembert", "RemBertConfig"),
|
||||
("roberta", "RobertaConfig"),
|
||||
@@ -190,6 +192,8 @@ MODEL_NAMES_MAPPING = OrderedDict(
|
||||
("qwen", "QWen"),
|
||||
("qwen2", "Qwen2"),
|
||||
("qwen2_moe", "Qwen2Moe"),
|
||||
("qwen3", "Qwen3"),
|
||||
("qwen3_moe", "Qwen3Moe"),
|
||||
("reformer", "Reformer"),
|
||||
("rembert", "RemBert"),
|
||||
("roberta", "Roberta"),
|
||||
|
||||
@@ -124,7 +124,9 @@ MAPPING_NAMES = OrderedDict(
|
||||
("Mistral", "mistral"),
|
||||
("Mixtral", "mixtral"),
|
||||
("Qwen2", "qwen2"),
|
||||
("Qwen3", "qwen3"),
|
||||
("Qwen2Moe", "qwen2_moe"),
|
||||
("Qwen3Moe", "qwen3_moe"),
|
||||
("Gemma", "gemma"),
|
||||
("Yuan", "yuan"),
|
||||
("Mamba", "mamba"),
|
||||
|
||||
@@ -38,7 +38,7 @@ from paddle import Tensor
|
||||
from paddle.nn import Layer
|
||||
|
||||
from paddlenlp.utils.distributed import distributed_allgather, distributed_gather
|
||||
from paddlenlp.utils.env import CONFIG_NAME, PADDLE_WEIGHTS_NAME, PYTORCH_WEIGHTS_NAME
|
||||
from paddlenlp.utils.env import CONFIG_NAME, PYTORCH_WEIGHTS_NAME
|
||||
from paddlenlp.utils.import_utils import (
|
||||
is_package_available,
|
||||
is_torch_available,
|
||||
@@ -1161,7 +1161,7 @@ class ConversionMixin:
|
||||
file for file in os.listdir(os.path.dirname(weight_file)) if file.startswith("pytorch_model-")
|
||||
]
|
||||
state_dict = {}
|
||||
for file in files:
|
||||
for file in sorted(files):
|
||||
sub_state_dict = load_torch(os.path.join(os.path.dirname(weight_file), file))
|
||||
state_dict.update(sub_state_dict)
|
||||
else:
|
||||
@@ -1179,13 +1179,9 @@ class ConversionMixin:
|
||||
all_layer_names.remove(name_mapping.source_name)
|
||||
|
||||
if all_layer_names:
|
||||
logger.warning(f"there are {len(all_layer_names)} tensors not initialized:")
|
||||
for layer_name in all_layer_names:
|
||||
logger.warning(f"--- {layer_name}")
|
||||
logger.warning(f"There are {len(all_layer_names)} tensors not initialized:")
|
||||
logger.warning(f"Keys: {all_layer_names}")
|
||||
|
||||
model_weight_file = os.path.join(cache_dir, PADDLE_WEIGHTS_NAME)
|
||||
if not os.path.isfile(model_weight_file):
|
||||
paddle.save(state_dict, model_weight_file)
|
||||
return state_dict
|
||||
|
||||
@classmethod
|
||||
@@ -1553,10 +1549,7 @@ class Converter(ConversionMixin, LogitComparer):
|
||||
all_layer_names.remove(name_mapping.source_name)
|
||||
|
||||
if all_layer_names:
|
||||
logger.warning(f"there are {len(all_layer_names)} tensors not initialized:")
|
||||
for layer_name in all_layer_names:
|
||||
logger.warning(f"--- {layer_name}")
|
||||
logger.warning(f"There are {len(all_layer_names)} tensors not initialized:")
|
||||
logger.warning(f"Keys: {all_layer_names}")
|
||||
|
||||
model_weight_file = os.path.join(input_dir, PADDLE_WEIGHTS_NAME)
|
||||
paddle.save(state_dict, model_weight_file)
|
||||
return state_dict
|
||||
|
||||
@@ -807,12 +807,14 @@ def load_sharded_checkpoint(model, folder, variant=None, strict=True, prefer_saf
|
||||
return missing_keys, unexpected_keys
|
||||
|
||||
|
||||
def faster_set_state_dict(model, state_dict, strict_dtype=True):
|
||||
def faster_set_state_dict(model, state_dict, model_state_dict=None, strict_dtype=True):
|
||||
if model_state_dict is None:
|
||||
model_state_dict = model.state_dict()
|
||||
# the state_dict will be destroyed.
|
||||
unused_keys = set(state_dict.keys())
|
||||
unset_keys = set(model.state_dict().keys())
|
||||
unset_keys = set(model_state_dict.keys())
|
||||
with paddle.no_grad():
|
||||
for k, v in model.state_dict().items():
|
||||
for k, v in model_state_dict.items():
|
||||
if k in state_dict:
|
||||
v_new = state_dict.pop(k)
|
||||
if not isinstance(v_new, paddle.Tensor):
|
||||
@@ -857,14 +859,14 @@ def faster_set_state_dict(model, state_dict, strict_dtype=True):
|
||||
return error_msgs
|
||||
|
||||
|
||||
def _load_state_dict_into_model(model_to_load, state_dict, start_prefix):
|
||||
def _load_state_dict_into_model(model_to_load, state_dict, start_prefix, model_to_load_state_dict):
|
||||
# torch will cast dtype in load_state_dict, but paddle strictly check dtype
|
||||
if len(start_prefix) > 0:
|
||||
for key in list(state_dict.keys()):
|
||||
if key.startswith(start_prefix):
|
||||
state_dict[key.replace(start_prefix, "")] = state_dict.pop(key)
|
||||
|
||||
_convert_state_dict_dtype_and_shape(state_dict, model_to_load)
|
||||
_convert_state_dict_dtype_and_shape(state_dict, model_to_load_state_dict)
|
||||
|
||||
error_msgs = []
|
||||
|
||||
@@ -874,7 +876,15 @@ def _load_state_dict_into_model(model_to_load, state_dict, start_prefix):
|
||||
# paddlenlp hold missing_keys , just ignore not found warnings.
|
||||
warnings.filterwarnings("ignore", message=r".*is not found in the provided dict.*")
|
||||
warnings.filterwarnings("ignore", message=r".*paddle.to_tensor.*")
|
||||
model_to_load.set_state_dict(state_dict)
|
||||
if len(model_to_load_state_dict) > 4000 and os.getenv("DISABLE_FASTER_SET_STATE_DICT", None) is None:
|
||||
logger.warning_once(
|
||||
"The model contains an excessive number of tensors, so we utilize the faster_set_state_dict method to load tensors into the model efficiently."
|
||||
" If any issues arise during the loading process, you can disable this feature by setting the environment variable DISABLE_FASTER_SET_STATE_DICT=1."
|
||||
)
|
||||
faster_set_state_dict(model_to_load, state_dict, model_to_load_state_dict)
|
||||
else:
|
||||
model_to_load.set_state_dict(state_dict)
|
||||
|
||||
error_msgs.extend([str(x.message) for x in w])
|
||||
|
||||
del state_dict
|
||||
@@ -882,12 +892,12 @@ def _load_state_dict_into_model(model_to_load, state_dict, start_prefix):
|
||||
return error_msgs
|
||||
|
||||
|
||||
def _convert_state_dict_dtype_and_shape(state_dict, model_to_load):
|
||||
def _convert_state_dict_dtype_and_shape(state_dict, model_to_load_state_dict):
|
||||
# convert the dtype of state dict
|
||||
def is_0d_or_1d(tensor):
|
||||
return len(tensor.shape) == 0 or list(tensor.shape) == [1]
|
||||
|
||||
for key, value in model_to_load.state_dict().items():
|
||||
for key, value in model_to_load_state_dict.items():
|
||||
if key in list(state_dict.keys()):
|
||||
if isinstance(state_dict[key], np.ndarray):
|
||||
raise ValueError(
|
||||
@@ -2034,12 +2044,15 @@ class PretrainedModel(Layer, GenerationMixin, ConversionMixin):
|
||||
start_prefix = cls.base_model_prefix + "."
|
||||
if len(cls.base_model_prefix) > 0 and hasattr(model, cls.base_model_prefix) and not has_prefix_module:
|
||||
model_to_load = getattr(model, cls.base_model_prefix)
|
||||
base_model_expected_keys = list(model_to_load.state_dict().keys())
|
||||
base_model_expected_keys = list(model_state_dict.keys())
|
||||
if any(key in expected_keys_not_prefixed and key not in base_model_expected_keys for key in loaded_keys):
|
||||
raise ValueError(
|
||||
"The state dictionary of the model you are trying to load is corrupted. Are you sure it was "
|
||||
"properly saved?"
|
||||
)
|
||||
model_to_load_state_dict = model_to_load.state_dict()
|
||||
else:
|
||||
model_to_load_state_dict = model_state_dict
|
||||
|
||||
def _find_mismatched_keys(
|
||||
state_dict,
|
||||
@@ -2143,7 +2156,12 @@ class PretrainedModel(Layer, GenerationMixin, ConversionMixin):
|
||||
keep_in_fp32_modules=keep_in_fp32_modules,
|
||||
)
|
||||
else:
|
||||
error_msgs = _load_state_dict_into_model(model_to_load, state_dict, start_prefix)
|
||||
error_msgs = _load_state_dict_into_model(
|
||||
model_to_load,
|
||||
state_dict,
|
||||
start_prefix,
|
||||
model_to_load_state_dict,
|
||||
)
|
||||
else:
|
||||
# Sharded checkpoint or whole but low_cpu_mem_usage==True
|
||||
|
||||
@@ -2156,9 +2174,7 @@ class PretrainedModel(Layer, GenerationMixin, ConversionMixin):
|
||||
resume_state_dict = {}
|
||||
if len(resolved_archive_file) > 1:
|
||||
resolved_archive_file = tqdm(resolved_archive_file, desc="Loading checkpoint shards")
|
||||
if low_cpu_mem_usage or quantization_linear_list is not None:
|
||||
# model.state_dict() takes a long time
|
||||
model_to_load_state_dict = model_to_load.state_dict()
|
||||
|
||||
for shard_file in resolved_archive_file:
|
||||
pre_tensor_parallel_split = False
|
||||
if quantization_linear_list is not None:
|
||||
@@ -2270,7 +2286,9 @@ class PretrainedModel(Layer, GenerationMixin, ConversionMixin):
|
||||
)
|
||||
error_msgs += new_error_msgs
|
||||
else:
|
||||
error_msgs += _load_state_dict_into_model(model_to_load, state_dict, start_prefix)
|
||||
error_msgs += _load_state_dict_into_model(
|
||||
model_to_load, state_dict, start_prefix, model_to_load_state_dict
|
||||
)
|
||||
|
||||
# force memory release
|
||||
del state_dict
|
||||
@@ -2581,6 +2599,7 @@ class PretrainedModel(Layer, GenerationMixin, ConversionMixin):
|
||||
for key in model.state_dict().keys():
|
||||
if "quant_weight" in key:
|
||||
quantization_linear_list.append(key[:-13])
|
||||
|
||||
model, missing_keys, unexpected_keys, mismatched_keys = cls._load_pretrained_model(
|
||||
model=model,
|
||||
state_dict=state_dict,
|
||||
@@ -2749,7 +2768,7 @@ class PretrainedModel(Layer, GenerationMixin, ConversionMixin):
|
||||
|
||||
# make sure that file to be deleted matches format of sharded file, e.g. paddle_model-00001-of-00005
|
||||
filename_no_suffix = filename.replace(".pdparams", "").replace(".safetensors", "")
|
||||
reg = re.compile("(.*?)-\d{5}-of-\d{5}")
|
||||
reg = re.compile(r"(.*?)-\d{5}-of-\d{5}")
|
||||
|
||||
if (
|
||||
filename.startswith(weights_no_suffix)
|
||||
|
||||
@@ -226,7 +226,7 @@ class PretrainedMoEGate(nn.Layer, MoEGateMixin):
|
||||
chosen_expert = topk_idx.reshape([-1])
|
||||
# Shape: [seq_len * k, num_experts].
|
||||
token_priority = F.one_hot(chosen_expert, self.num_experts).cast(paddle.int32)
|
||||
token_priority = paddle.logical_and(token_priority > 0, token_priority.cumsum(axis=0) < capacity)
|
||||
token_priority = paddle.logical_and(token_priority > 0, token_priority.cumsum(axis=0) <= capacity)
|
||||
# Shape: [seq_len, num_experts].
|
||||
token_priority = token_priority.reshape([-1, k, self.num_experts]).sum(axis=1)
|
||||
|
||||
@@ -532,12 +532,14 @@ class PretrainedMoEGate(nn.Layer, MoEGateMixin):
|
||||
token_priority = self._priority(top_idx, capacity)
|
||||
|
||||
# normalize gates
|
||||
# gates_masked is equal to top_gate.
|
||||
gates_masked = gates * mask
|
||||
if self.training:
|
||||
gates_s = paddle.sum(gates_masked, axis=-1, keepdim=True)
|
||||
denom_s = paddle.clip(gates_s, min=paddle.finfo(gates_masked.dtype).eps)
|
||||
if self.norm_topk_prob:
|
||||
gates_masked = gates_masked / denom_s
|
||||
# if self.training:
|
||||
gates_s = paddle.sum(gates_masked, axis=-1, keepdim=True)
|
||||
denom_s = paddle.clip(gates_s, min=paddle.finfo(gates_masked.dtype).eps)
|
||||
if self.norm_topk_prob:
|
||||
gates_masked = gates_masked / denom_s
|
||||
gates_masked *= self.routed_scaling_factor
|
||||
|
||||
return (
|
||||
capacity,
|
||||
|
||||
@@ -101,7 +101,7 @@ class Qwen2Config(PretrainedConfig):
|
||||
num_key_value_heads=32,
|
||||
hidden_act="silu",
|
||||
max_position_embeddings=32768,
|
||||
seq_length=32768,
|
||||
# seq_length=32768,
|
||||
initializer_range=0.02,
|
||||
rms_norm_eps=1e-6,
|
||||
use_cache=True,
|
||||
@@ -113,6 +113,7 @@ class Qwen2Config(PretrainedConfig):
|
||||
use_sliding_window=False,
|
||||
sliding_window=4096,
|
||||
max_window_layers=28,
|
||||
attention_bias=True,
|
||||
attention_dropout=0.0,
|
||||
rope_scaling_factor=1.0,
|
||||
rope_scaling_type=None,
|
||||
@@ -122,7 +123,7 @@ class Qwen2Config(PretrainedConfig):
|
||||
):
|
||||
self.vocab_size = vocab_size
|
||||
self.max_position_embeddings = max_position_embeddings
|
||||
self.seq_length = seq_length
|
||||
# self.seq_length = seq_length
|
||||
self.hidden_size = hidden_size
|
||||
self.intermediate_size = intermediate_size
|
||||
self.num_hidden_layers = num_hidden_layers
|
||||
@@ -141,6 +142,7 @@ class Qwen2Config(PretrainedConfig):
|
||||
self.rms_norm_eps = rms_norm_eps
|
||||
self.use_cache = use_cache
|
||||
self.rope_theta = rope_theta
|
||||
self.attention_bias = attention_bias
|
||||
self.attention_dropout = attention_dropout
|
||||
|
||||
self.use_cache = use_cache
|
||||
|
||||
@@ -509,8 +509,9 @@ class Qwen2Attention(nn.Layer):
|
||||
self.skip_recompute_ops = skip_recompute_ops
|
||||
self.hidden_size = config.hidden_size
|
||||
self.num_heads = config.num_attention_heads
|
||||
self.num_attention_heads = config.num_attention_heads
|
||||
|
||||
self.head_dim = self.hidden_size // config.num_attention_heads
|
||||
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
||||
|
||||
self.num_key_value_heads = config.num_key_value_heads
|
||||
assert config.num_attention_heads // config.num_key_value_heads
|
||||
@@ -521,9 +522,9 @@ class Qwen2Attention(nn.Layer):
|
||||
self.is_causal = True
|
||||
self.attention_dropout = config.attention_dropout
|
||||
|
||||
self.seq_length = config.seq_length
|
||||
# self.seq_length = config.seq_length
|
||||
self.sequence_parallel = config.sequence_parallel
|
||||
|
||||
self.has_bias = config.attention_bias
|
||||
self.fuse_attention_qkv = config.fuse_attention_qkv
|
||||
|
||||
# Note that we will actually perform a recompute only if both enable_recompute and layerwise_recompute are set to True
|
||||
@@ -576,27 +577,37 @@ class Qwen2Attention(nn.Layer):
|
||||
if self.fuse_attention_qkv:
|
||||
self.qkv_proj = ColumnParallelLinear(
|
||||
self.hidden_size,
|
||||
self.hidden_size + 2 * self.config.num_key_value_heads * self.head_dim,
|
||||
has_bias=True,
|
||||
self.num_attention_heads * self.head_dim + 2 * self.config.num_key_value_heads * self.head_dim,
|
||||
has_bias=self.has_bias,
|
||||
gather_output=False,
|
||||
)
|
||||
else:
|
||||
self.q_proj = ColumnParallelLinear(
|
||||
self.hidden_size, self.hidden_size, has_bias=True, gather_output=False
|
||||
self.hidden_size,
|
||||
self.num_attention_heads * self.head_dim,
|
||||
has_bias=self.has_bias,
|
||||
gather_output=False,
|
||||
)
|
||||
self.k_proj = ColumnParallelLinear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, has_bias=True, gather_output=False) # fmt:skip
|
||||
self.v_proj = ColumnParallelLinear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, has_bias=True, gather_output=False) # fmt:skip
|
||||
self.k_proj = ColumnParallelLinear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, has_bias=self.has_bias, gather_output=False) # fmt:skip
|
||||
self.v_proj = ColumnParallelLinear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, has_bias=self.has_bias, gather_output=False) # fmt:skip
|
||||
self.o_proj = RowParallelLinear(self.hidden_size, self.hidden_size, has_bias=False, input_is_parallel=True)
|
||||
else:
|
||||
if self.fuse_attention_qkv:
|
||||
self.qkv_proj = Linear(
|
||||
self.hidden_size, self.hidden_size + 2 * self.config.num_key_value_heads * self.head_dim
|
||||
self.hidden_size,
|
||||
self.num_attention_heads * self.head_dim + 2 * self.config.num_key_value_heads * self.head_dim,
|
||||
)
|
||||
else:
|
||||
self.q_proj = Linear(self.hidden_size, self.hidden_size, bias_attr=True)
|
||||
self.k_proj = Linear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, bias_attr=True)
|
||||
self.v_proj = Linear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, bias_attr=True)
|
||||
self.o_proj = Linear(self.hidden_size, self.hidden_size, bias_attr=False)
|
||||
self.q_proj = Linear(
|
||||
self.hidden_size, self.num_attention_heads * self.head_dim, bias_attr=self.has_bias
|
||||
)
|
||||
self.k_proj = Linear(
|
||||
self.hidden_size, self.config.num_key_value_heads * self.head_dim, bias_attr=self.has_bias
|
||||
)
|
||||
self.v_proj = Linear(
|
||||
self.hidden_size, self.config.num_key_value_heads * self.head_dim, bias_attr=self.has_bias
|
||||
)
|
||||
self.o_proj = Linear(self.num_attention_heads * self.head_dim, self.hidden_size, bias_attr=False)
|
||||
|
||||
self.rotary_emb = Qwen2RotaryEmbedding(
|
||||
self.head_dim,
|
||||
|
||||
@@ -779,7 +779,7 @@ class Qwen2MoeGate(PretrainedMoEGate):
|
||||
return capacity, combine_weights, dispatch_mask, exp_counts, l_aux, l_zloss
|
||||
|
||||
|
||||
class Qwen2MoeSparseMoEBlock(MoELayer):
|
||||
class Qwen2MoeSparseMoeBlock(MoELayer):
|
||||
def __init__(self, config: Qwen2MoeConfig):
|
||||
gate = Qwen2MoeGate(
|
||||
config,
|
||||
@@ -822,7 +822,7 @@ class Qwen2MoeDecoderLayer(nn.Layer):
|
||||
self.self_attn = Qwen2MoeAttention(config, layerwise_recompute)
|
||||
|
||||
if config.num_experts > 0:
|
||||
self.mlp = Qwen2MoeSparseMoEBlock(config)
|
||||
self.mlp = Qwen2MoeSparseMoeBlock(config)
|
||||
else:
|
||||
# num_experts == 0 or this layer is not sparse layer
|
||||
self.mlp = Qwen2MoeMLP(config)
|
||||
|
||||
18
paddlenlp/transformers/qwen3/__init__.py
Normal file
18
paddlenlp/transformers/qwen3/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||||
# Copyright 2024 The Qwen Team and The HuggingFace Inc. team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .configuration import *
|
||||
from .modeling import *
|
||||
from .modeling_pp import *
|
||||
195
paddlenlp/transformers/qwen3/configuration.py
Normal file
195
paddlenlp/transformers/qwen3/configuration.py
Normal file
@@ -0,0 +1,195 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
# Copyright 2024 The Qwen team, Alibaba Group and the HuggingFace Inc. team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Qwen2 model configuration"""
|
||||
|
||||
from ..configuration_utils import PretrainedConfig
|
||||
|
||||
|
||||
class Qwen3Config(PretrainedConfig):
|
||||
r"""
|
||||
This is the configuration class to store the configuration of a [`Qwen3Model`]. It is used to instantiate a
|
||||
Qwen3 model according to the specified arguments, defining the model architecture. Instantiating a configuration
|
||||
with the defaults will yield a similar configuration to that of
|
||||
Qwen3-8B [Qwen/Qwen3-8B](https://huggingface.co/Qwen/Qwen3-8B).
|
||||
|
||||
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
|
||||
documentation from [`PretrainedConfig`] for more information.
|
||||
|
||||
|
||||
Args:
|
||||
vocab_size (`int`, *optional*, defaults to 151936):
|
||||
Vocabulary size of the Qwen3 model. Defines the number of different tokens that can be represented by the
|
||||
`inputs_ids` passed when calling [`Qwen3Model`]
|
||||
hidden_size (`int`, *optional*, defaults to 4096):
|
||||
Dimension of the hidden representations.
|
||||
intermediate_size (`int`, *optional*, defaults to 22016):
|
||||
Dimension of the MLP representations.
|
||||
num_hidden_layers (`int`, *optional*, defaults to 32):
|
||||
Number of hidden layers in the Transformer encoder.
|
||||
num_attention_heads (`int`, *optional*, defaults to 32):
|
||||
Number of attention heads for each attention layer in the Transformer encoder.
|
||||
num_key_value_heads (`int`, *optional*, defaults to 32):
|
||||
This is the number of key_value heads that should be used to implement Grouped Query Attention. If
|
||||
`num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
|
||||
`num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used. When
|
||||
converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
|
||||
by meanpooling all the original heads within that group. For more details checkout [this
|
||||
paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to `32`.
|
||||
head_dim (`int`, *optional*, defaults to 128):
|
||||
The attention head dimension.
|
||||
hidden_act (`str` or `function`, *optional*, defaults to `"silu"`):
|
||||
The non-linear activation function (function or string) in the decoder.
|
||||
max_position_embeddings (`int`, *optional*, defaults to 32768):
|
||||
The maximum sequence length that this model might ever be used with.
|
||||
initializer_range (`float`, *optional*, defaults to 0.02):
|
||||
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
||||
rms_norm_eps (`float`, *optional*, defaults to 1e-06):
|
||||
The epsilon used by the rms normalization layers.
|
||||
use_cache (`bool`, *optional*, defaults to `True`):
|
||||
Whether or not the model should return the last key/values attentions (not used by all models). Only
|
||||
relevant if `config.is_decoder=True`.
|
||||
tie_word_embeddings (`bool`, *optional*, defaults to `False`):
|
||||
Whether the model's input and output word embeddings should be tied.
|
||||
rope_theta (`float`, *optional*, defaults to 10000.0):
|
||||
The base period of the RoPE embeddings.
|
||||
rope_scaling (`Dict`, *optional*):
|
||||
Dictionary containing the scaling configuration for the RoPE embeddings. NOTE: if you apply new rope type
|
||||
and you expect the model to work on longer `max_position_embeddings`, we recommend you to update this value
|
||||
accordingly.
|
||||
Expected contents:
|
||||
`rope_type` (`str`):
|
||||
The sub-variant of RoPE to use. Can be one of ['default', 'linear', 'dynamic', 'yarn', 'longrope',
|
||||
'llama3'], with 'default' being the original RoPE implementation.
|
||||
`factor` (`float`, *optional*):
|
||||
Used with all rope types except 'default'. The scaling factor to apply to the RoPE embeddings. In
|
||||
most scaling types, a `factor` of x will enable the model to handle sequences of length x *
|
||||
original maximum pre-trained length.
|
||||
`original_max_position_embeddings` (`int`, *optional*):
|
||||
Used with 'dynamic', 'longrope' and 'llama3'. The original max position embeddings used during
|
||||
pretraining.
|
||||
`attention_factor` (`float`, *optional*):
|
||||
Used with 'yarn' and 'longrope'. The scaling factor to be applied on the attention
|
||||
computation. If unspecified, it defaults to value recommended by the implementation, using the
|
||||
`factor` field to infer the suggested value.
|
||||
`beta_fast` (`float`, *optional*):
|
||||
Only used with 'yarn'. Parameter to set the boundary for extrapolation (only) in the linear
|
||||
ramp function. If unspecified, it defaults to 32.
|
||||
`beta_slow` (`float`, *optional*):
|
||||
Only used with 'yarn'. Parameter to set the boundary for interpolation (only) in the linear
|
||||
ramp function. If unspecified, it defaults to 1.
|
||||
`short_factor` (`List[float]`, *optional*):
|
||||
Only used with 'longrope'. The scaling factor to be applied to short contexts (<
|
||||
`original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
|
||||
size divided by the number of attention heads divided by 2
|
||||
`long_factor` (`List[float]`, *optional*):
|
||||
Only used with 'longrope'. The scaling factor to be applied to long contexts (<
|
||||
`original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
|
||||
size divided by the number of attention heads divided by 2
|
||||
`low_freq_factor` (`float`, *optional*):
|
||||
Only used with 'llama3'. Scaling factor applied to low frequency components of the RoPE
|
||||
`high_freq_factor` (`float`, *optional*):
|
||||
Only used with 'llama3'. Scaling factor applied to high frequency components of the RoPE
|
||||
attention_bias (`bool`, defaults to `False`, *optional*, defaults to `False`):
|
||||
Whether to use a bias in the query, key, value and output projection layers during self-attention.
|
||||
use_sliding_window (`bool`, *optional*, defaults to `False`):
|
||||
Whether to use sliding window attention.
|
||||
sliding_window (`int`, *optional*, defaults to 4096):
|
||||
Sliding window attention (SWA) window size. If not specified, will default to `4096`.
|
||||
max_window_layers (`int`, *optional*, defaults to 28):
|
||||
The number of layers that use SWA (Sliding Window Attention). The bottom layers use SWA while the top use full attention.
|
||||
attention_dropout (`float`, *optional*, defaults to 0.0):
|
||||
The dropout ratio for the attention probabilities.
|
||||
|
||||
```python
|
||||
>>> from transformers import Qwen3Model, Qwen3Config
|
||||
|
||||
>>> # Initializing a Qwen3 style configuration
|
||||
>>> configuration = Qwen3Config()
|
||||
|
||||
>>> # Initializing a model from the Qwen3-8B style configuration
|
||||
>>> model = Qwen3Model(configuration)
|
||||
|
||||
>>> # Accessing the model configuration
|
||||
>>> configuration = model.config
|
||||
```"""
|
||||
|
||||
model_type = "qwen3"
|
||||
keys_to_ignore_at_inference = ["past_key_values"]
|
||||
|
||||
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,
|
||||
head_dim=128,
|
||||
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=10000.0,
|
||||
rope_scaling=None,
|
||||
attention_bias=False,
|
||||
use_sliding_window=False,
|
||||
sliding_window=4096,
|
||||
max_window_layers=28,
|
||||
attention_dropout=0.0,
|
||||
dpo_config=None,
|
||||
use_fused_head_and_loss_fn=False,
|
||||
**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 # we check `use_sliding_window` in the modeling code
|
||||
self.max_window_layers = max_window_layers
|
||||
|
||||
# for backward compatibility
|
||||
if num_key_value_heads is None:
|
||||
num_key_value_heads = num_attention_heads
|
||||
|
||||
self.num_key_value_heads = num_key_value_heads
|
||||
self.head_dim = head_dim
|
||||
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
|
||||
# Validate the correctness of rotary position embeddings parameters
|
||||
# BC: if there is a 'type' field, move it to 'rope_type'.
|
||||
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.dpo_config = dpo_config
|
||||
self.use_fused_head_and_loss_fn = use_fused_head_and_loss_fn
|
||||
|
||||
super().__init__(
|
||||
tie_word_embeddings=tie_word_embeddings,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
__all__ = ["Qwen3Config"]
|
||||
1449
paddlenlp/transformers/qwen3/modeling.py
Normal file
1449
paddlenlp/transformers/qwen3/modeling.py
Normal file
File diff suppressed because it is too large
Load Diff
364
paddlenlp/transformers/qwen3/modeling_pp.py
Normal file
364
paddlenlp/transformers/qwen3/modeling_pp.py
Normal file
@@ -0,0 +1,364 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from typing import OrderedDict
|
||||
|
||||
import paddle
|
||||
import paddle.distributed.fleet as fleet
|
||||
import paddle.nn as nn
|
||||
from paddle.distributed.fleet.meta_parallel import (
|
||||
LayerDesc,
|
||||
PipelineLayer,
|
||||
SharedLayerDesc,
|
||||
)
|
||||
from paddle.distributed.fleet.recompute.recompute import recompute
|
||||
|
||||
from paddlenlp.transformers.refined_recompute import get_skip_recompute_ops
|
||||
from paddlenlp.transformers.refined_recompute import recompute as rr_recompute
|
||||
|
||||
from ...utils.tools import get_env_device
|
||||
from ..dpo_criterion import DPOCriterion
|
||||
from ..model_utils import PipelinePretrainedModel
|
||||
from .modeling import (
|
||||
Qwen3Config,
|
||||
Qwen3DecoderLayer,
|
||||
Qwen3LMHead,
|
||||
Qwen3Model,
|
||||
Qwen3PretrainedModel,
|
||||
Qwen3PretrainingCriterion,
|
||||
Qwen3RMSNorm,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Qwen3ForCausalLMPipe",
|
||||
]
|
||||
|
||||
|
||||
def parse_args(args):
|
||||
if isinstance(args, tuple):
|
||||
if len(args) == 4:
|
||||
hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids = args
|
||||
elif len(args) == 3:
|
||||
hidden_states, attention_mask, attn_mask_startend_row_indices = args
|
||||
position_ids = None
|
||||
elif len(args) == 2:
|
||||
hidden_states, attention_mask = args
|
||||
attn_mask_startend_row_indices, position_ids = None, None
|
||||
else:
|
||||
hidden_states = args
|
||||
attention_mask, attn_mask_startend_row_indices, position_ids = None, None, None
|
||||
|
||||
if position_ids is not None:
|
||||
position_ids.stop_gradient = True
|
||||
|
||||
if attention_mask is not None:
|
||||
attention_mask.stop_gradient = True
|
||||
|
||||
if attn_mask_startend_row_indices is not None:
|
||||
attn_mask_startend_row_indices.stop_gradient = True
|
||||
|
||||
return hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids
|
||||
|
||||
|
||||
def return_args(hidden_states, attention_mask=None, attn_mask_startend_row_indices=None, position_ids=None):
|
||||
ret = (hidden_states,)
|
||||
|
||||
if attention_mask is not None:
|
||||
ret += (attention_mask.clone(),)
|
||||
if attn_mask_startend_row_indices is not None:
|
||||
ret += (attn_mask_startend_row_indices.clone(),)
|
||||
if position_ids is not None:
|
||||
ret += (position_ids.clone(),)
|
||||
if len(ret) == 1:
|
||||
ret = ret[0]
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def get_attr(layer, name):
|
||||
if getattr(layer, name, None) is not None:
|
||||
return getattr(layer, name, None)
|
||||
else:
|
||||
return get_attr(layer._layer, name)
|
||||
|
||||
|
||||
class Qwen3EmbeddingPipe(nn.Layer):
|
||||
"""Extends QWenEmbeddings to forward attention_mask through the pipeline."""
|
||||
|
||||
def __init__(self, config: Qwen3Config):
|
||||
super(Qwen3EmbeddingPipe, self).__init__()
|
||||
self.config = config
|
||||
self.sequence_parallel = config.sequence_parallel
|
||||
self.hidden_size = config.hidden_size
|
||||
if config.tensor_parallel_degree > 1 and config.vocab_size % config.tensor_parallel_degree == 0:
|
||||
self.embed_tokens = fleet.meta_parallel.VocabParallelEmbedding(
|
||||
config.vocab_size,
|
||||
config.hidden_size,
|
||||
weight_attr=paddle.ParamAttr(initializer=nn.initializer.XavierNormal()),
|
||||
)
|
||||
else:
|
||||
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size)
|
||||
|
||||
@property
|
||||
def embedding_weight(self):
|
||||
return get_attr(self.embed_tokens, "weight")
|
||||
|
||||
def forward(self, args):
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
input (_type_): _description_
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
input_ids, attention_mask, attn_mask_startend_row_indices, position_ids = parse_args(args)
|
||||
input_embeds = self.embed_tokens(input_ids)
|
||||
if self.config.sequence_parallel:
|
||||
from paddlenlp.transformers import ScatterOp
|
||||
|
||||
# [bs, seq_len, num_head * head_dim] -> [bs * seq_len, num_head * head_dim]
|
||||
bs, seq_len, hidden_size = input_embeds.shape
|
||||
input_embeds = paddle.reshape_(input_embeds, [bs * seq_len, hidden_size])
|
||||
# [seq_len * bs / n, num_head * head_dim] (n is mp parallelism)
|
||||
input_embeds = ScatterOp.apply(input_embeds)
|
||||
|
||||
batch_size, seq_length = input_ids.shape
|
||||
|
||||
if attention_mask is not None:
|
||||
assert (
|
||||
attn_mask_startend_row_indices is None
|
||||
), "attention_mask and attn_mask_startend_row_indices can not be set at same time"
|
||||
|
||||
attention_mask = Qwen3Model._prepare_decoder_attention_mask(
|
||||
attention_mask, (batch_size, seq_length), 0, input_embeds.dtype
|
||||
)
|
||||
attention_mask.stop_gradient = True
|
||||
if get_env_device() == "npu":
|
||||
attention_mask = attention_mask.astype("bool")
|
||||
elif get_env_device() == "npu":
|
||||
attention_mask = paddle.tril(paddle.ones((seq_length, seq_length), dtype="bool"))
|
||||
attention_mask.stop_gradient = True
|
||||
|
||||
return return_args(input_embeds, attention_mask, attn_mask_startend_row_indices, position_ids)
|
||||
|
||||
|
||||
class Qwen3DecoderLayerPipe(Qwen3DecoderLayer):
|
||||
def forward(self, args):
|
||||
hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids = parse_args(args)
|
||||
|
||||
has_gradient = not hidden_states.stop_gradient
|
||||
|
||||
if attention_mask is not None and attention_mask.dtype == paddle.int32:
|
||||
attention_mask, attn_mask_startend_row_indices, position_ids = (
|
||||
None,
|
||||
attention_mask,
|
||||
attn_mask_startend_row_indices,
|
||||
)
|
||||
elif attention_mask is not None and attention_mask.dtype == paddle.int64:
|
||||
attention_mask, attn_mask_startend_row_indices, position_ids = None, None, attention_mask
|
||||
elif attn_mask_startend_row_indices is not None and attn_mask_startend_row_indices.dtype == paddle.int64:
|
||||
attn_mask_startend_row_indices, position_ids = None, attn_mask_startend_row_indices
|
||||
|
||||
if self.enable_recompute and self.config.recompute_granularity == "full" and has_gradient:
|
||||
recompute_fn = rr_recompute if any(self.skip_recompute_ops.values()) else recompute
|
||||
if attention_mask is not None or attn_mask_startend_row_indices is not None:
|
||||
hidden_states = recompute_fn(
|
||||
super().forward,
|
||||
hidden_states,
|
||||
position_ids=position_ids,
|
||||
attention_mask=attention_mask,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
use_reentrant=False,
|
||||
)
|
||||
else:
|
||||
# for pretrain
|
||||
hidden_states = recompute_fn(
|
||||
super().forward,
|
||||
hidden_states,
|
||||
position_ids=position_ids,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
use_reentrant=self.config.recompute_use_reentrant,
|
||||
)
|
||||
else:
|
||||
hidden_states = super().forward(
|
||||
hidden_states,
|
||||
position_ids=position_ids,
|
||||
attention_mask=attention_mask,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
)
|
||||
|
||||
return return_args(hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids)
|
||||
|
||||
|
||||
class Qwen3RMSNormPipe(nn.Layer):
|
||||
def __init__(self, config):
|
||||
super().__init__()
|
||||
self.norm = Qwen3RMSNorm(config)
|
||||
|
||||
def forward(self, args):
|
||||
hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids = parse_args(args)
|
||||
return self.norm(hidden_states)
|
||||
|
||||
|
||||
class Qwen3LMHeadPipe(Qwen3LMHead):
|
||||
def __init__(self, config, transpose_y=False):
|
||||
super(Qwen3LMHeadPipe, self).__init__(config, transpose_y=transpose_y)
|
||||
|
||||
@property
|
||||
def embedding_weight(self):
|
||||
return get_attr(self, "weight")
|
||||
|
||||
|
||||
class Qwen3ForCausalLMPipe(PipelinePretrainedModel, PipelineLayer):
|
||||
"""QWenForPretraining adapted for pipeline parallelism.
|
||||
|
||||
The largest change is flattening the QWenModel class so we can express it as a
|
||||
sequence of layers including embedding, transformer layers, and output.
|
||||
"""
|
||||
|
||||
config_class = Qwen3Config
|
||||
|
||||
_get_tensor_parallel_mappings = Qwen3PretrainedModel._get_tensor_parallel_mappings
|
||||
_init_weights = Qwen3PretrainedModel._init_weights
|
||||
_keys_to_ignore_on_load_unexpected = Qwen3PretrainedModel._keys_to_ignore_on_load_unexpected
|
||||
_get_model_flops = Qwen3PretrainedModel._get_model_flops
|
||||
_get_hardware_flops = Qwen3PretrainedModel._get_hardware_flops
|
||||
|
||||
_tied_weights_keys = ["lm_head.weight"]
|
||||
|
||||
# DONOT Add base_model_prefix !!!!
|
||||
|
||||
@classmethod
|
||||
def _prepare_pipeline_inputs_func(cls, inputs):
|
||||
|
||||
first_stage_keys = ["input_ids", "attention_mask", "attn_mask_startend_row_indices", "position_ids"]
|
||||
last_stage_keys = ["labels"]
|
||||
|
||||
def get_expected_keys(inputs, keys):
|
||||
ret = tuple([inputs.pop(k) if k in inputs else None for k in keys])
|
||||
if len(ret) == 1:
|
||||
ret = ret[0]
|
||||
return ret
|
||||
|
||||
if type(inputs) is dict or type(inputs) is OrderedDict:
|
||||
return [
|
||||
get_expected_keys(inputs, first_stage_keys),
|
||||
get_expected_keys(inputs, last_stage_keys),
|
||||
]
|
||||
|
||||
keys = list(inputs[0].keys())
|
||||
inputs_batch = {key: [data.pop(key) for data in inputs] for key in keys}
|
||||
return [
|
||||
get_expected_keys(inputs_batch, first_stage_keys),
|
||||
get_expected_keys(inputs_batch, last_stage_keys),
|
||||
]
|
||||
|
||||
def __init__(self, config: Qwen3Config):
|
||||
self.config = config
|
||||
|
||||
# Note that we will actually perform a recompute only if both enable_recompute and layerwise_recompute are set to True
|
||||
# Enable_recompute defaults to False and is controlled by Trainer
|
||||
self.enable_recompute = False
|
||||
self.recompute_granularity = self.config.recompute_granularity
|
||||
self.pp_recompute_interval = self.config.pp_recompute_interval
|
||||
self.no_recompute_layers = config.no_recompute_layers if config.no_recompute_layers is not None else []
|
||||
if self.recompute_granularity == "full":
|
||||
assert len(self.no_recompute_layers) == 0, "for pp with full recompute, no_recompute_layers is not support"
|
||||
|
||||
virtual_pp_degree = getattr(self.config, "virtual_pp_degree", 1)
|
||||
|
||||
def get_hcg():
|
||||
return fleet.get_hybrid_communicate_group()
|
||||
|
||||
hcg = get_hcg()
|
||||
tensor_parallel_degree = max(hcg.get_model_parallel_world_size(), 1)
|
||||
tensor_parallel_rank = max(hcg.get_model_parallel_rank(), 0)
|
||||
|
||||
# TODO: fix tensor_parallel_degree rewrite in here
|
||||
config.tensor_parallel_degree = tensor_parallel_degree
|
||||
config.tensor_parallel_rank = tensor_parallel_rank
|
||||
|
||||
if config.tie_word_embeddings:
|
||||
self.add_sequential_layer(
|
||||
SharedLayerDesc(
|
||||
"model_shared_weight", Qwen3EmbeddingPipe, shared_weight_attr="embedding_weight", config=config
|
||||
),
|
||||
"model",
|
||||
)
|
||||
else:
|
||||
self.add_sequential_layer(LayerDesc(Qwen3EmbeddingPipe, config=config), "model")
|
||||
|
||||
for i in range(config.num_hidden_layers):
|
||||
self.add_sequential_layer(
|
||||
LayerDesc(
|
||||
Qwen3DecoderLayerPipe,
|
||||
config=config,
|
||||
layerwise_recompute=i not in self.no_recompute_layers,
|
||||
skip_recompute_ops=get_skip_recompute_ops(config, i),
|
||||
),
|
||||
f"model.layers.{i}",
|
||||
)
|
||||
self.add_sequential_layer(LayerDesc(Qwen3RMSNormPipe, config=config), "model")
|
||||
|
||||
if config.tie_word_embeddings:
|
||||
self.add_sequential_layer(
|
||||
SharedLayerDesc(
|
||||
"model_shared_weight",
|
||||
Qwen3LMHeadPipe,
|
||||
shared_weight_attr="embedding_weight",
|
||||
config=config,
|
||||
**{"transpose_y": True},
|
||||
),
|
||||
"lm_head",
|
||||
)
|
||||
else:
|
||||
self.add_sequential_layer(LayerDesc(Qwen3LMHeadPipe, config=config), "lm_head")
|
||||
|
||||
recompute_interval = 0
|
||||
if self.enable_recompute and self.recompute_granularity == "full":
|
||||
assert self.config.pp_recompute_interval <= config.num_hidden_layers // (
|
||||
virtual_pp_degree * get_hcg().topology().get_dim_size("pipe")
|
||||
), "pp recompute interval should smaller than num layers of each pp chunk"
|
||||
recompute_interval = self.config.pp_recompute_interval
|
||||
|
||||
seg_method = "layer:Qwen3DecoderLayer"
|
||||
if config.num_hidden_layers % get_hcg().topology().get_dim_size("pipe") != 0:
|
||||
seg_method = "uniform"
|
||||
|
||||
PipelineLayer.__init__(
|
||||
self,
|
||||
layers=self.get_sequential_layers(),
|
||||
loss_fn=self.get_loss_fn(config),
|
||||
topology=get_hcg().topology(),
|
||||
seg_method=seg_method,
|
||||
recompute_interval=recompute_interval,
|
||||
recompute_ctx={
|
||||
"mp_group": get_hcg().get_model_parallel_group(),
|
||||
"offload": False,
|
||||
"partition": False,
|
||||
},
|
||||
num_virtual_pipeline_stages=virtual_pp_degree,
|
||||
)
|
||||
# You should call init here, since there is a diamond inheritance problem
|
||||
self.apply(self._init_weights)
|
||||
# DON'T init PipelinePretrainedModel
|
||||
# PipelinePretrainedModel.__init__(self.super(), config=config)
|
||||
|
||||
def get_loss_fn(self, config):
|
||||
if config.dpo_config is not None:
|
||||
return DPOCriterion(config, use_infohub=True)
|
||||
else:
|
||||
return Qwen3PretrainingCriterion(config)
|
||||
17
paddlenlp/transformers/qwen3_moe/__init__.py
Normal file
17
paddlenlp/transformers/qwen3_moe/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .configuration import *
|
||||
from .modeling import *
|
||||
from .modeling_pp import *
|
||||
219
paddlenlp/transformers/qwen3_moe/configuration.py
Normal file
219
paddlenlp/transformers/qwen3_moe/configuration.py
Normal file
@@ -0,0 +1,219 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
# coding=utf-8
|
||||
# Copyright 2024 The Qwen team, Alibaba Group and the HuggingFace Inc. team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Qwen3MoE model configuration"""
|
||||
|
||||
from ..configuration_utils import PretrainedConfig
|
||||
|
||||
|
||||
class Qwen3MoeConfig(PretrainedConfig):
|
||||
r"""
|
||||
This is the configuration class to store the configuration of a [`Qwen3MoeModel`]. It is used to instantiate a
|
||||
Qwen3MoE model according to the specified arguments, defining the model architecture. Instantiating a configuration
|
||||
with the defaults will yield a similar configuration to that of [Qwen/Qwen3-MoE-15B-A2B](https://huggingface.co/Qwen/Qwen3-15B-A2B).
|
||||
|
||||
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
|
||||
documentation from [`PretrainedConfig`] for more information.
|
||||
|
||||
|
||||
Args:
|
||||
vocab_size (`int`, *optional*, defaults to 151936):
|
||||
Vocabulary size of the Qwen3MoE model. Defines the number of different tokens that can be represented by the
|
||||
`inputs_ids` passed when calling [`Qwen3MoeModel`]
|
||||
hidden_size (`int`, *optional*, defaults to 2048):
|
||||
Dimension of the hidden representations.
|
||||
intermediate_size (`int`, *optional*, defaults to 6144):
|
||||
Dimension of the MLP representations.
|
||||
num_hidden_layers (`int`, *optional*, defaults to 24):
|
||||
Number of hidden layers in the Transformer encoder.
|
||||
num_attention_heads (`int`, *optional*, defaults to 32):
|
||||
Number of attention heads for each attention layer in the Transformer encoder.
|
||||
num_key_value_heads (`int`, *optional*, defaults to 4):
|
||||
This is the number of key_value heads that should be used to implement Grouped Query Attention. If
|
||||
`num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
|
||||
`num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used. When
|
||||
converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
|
||||
by meanpooling all the original heads within that group. For more details checkout [this
|
||||
paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to `32`.
|
||||
hidden_act (`str` or `function`, *optional*, defaults to `"silu"`):
|
||||
The non-linear activation function (function or string) in the decoder.
|
||||
max_position_embeddings (`int`, *optional*, defaults to 32768):
|
||||
The maximum sequence length that this model might ever be used with.
|
||||
initializer_range (`float`, *optional*, defaults to 0.02):
|
||||
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
||||
rms_norm_eps (`float`, *optional*, defaults to 1e-06):
|
||||
The epsilon used by the rms normalization layers.
|
||||
use_cache (`bool`, *optional*, defaults to `True`):
|
||||
Whether or not the model should return the last key/values attentions (not used by all models). Only
|
||||
relevant if `config.is_decoder=True`.
|
||||
tie_word_embeddings (`bool`, *optional*, defaults to `False`):
|
||||
Whether the model's input and output word embeddings should be tied.
|
||||
rope_theta (`float`, *optional*, defaults to 10000.0):
|
||||
The base period of the RoPE embeddings.
|
||||
rope_scaling (`Dict`, *optional*):
|
||||
Dictionary containing the scaling configuration for the RoPE embeddings. NOTE: if you apply new rope type
|
||||
and you expect the model to work on longer `max_position_embeddings`, we recommend you to update this value
|
||||
accordingly.
|
||||
Expected contents:
|
||||
`rope_type` (`str`):
|
||||
The sub-variant of RoPE to use. Can be one of ['default', 'linear', 'dynamic', 'yarn', 'longrope',
|
||||
'llama3'], with 'default' being the original RoPE implementation.
|
||||
`factor` (`float`, *optional*):
|
||||
Used with all rope types except 'default'. The scaling factor to apply to the RoPE embeddings. In
|
||||
most scaling types, a `factor` of x will enable the model to handle sequences of length x *
|
||||
original maximum pre-trained length.
|
||||
`original_max_position_embeddings` (`int`, *optional*):
|
||||
Used with 'dynamic', 'longrope' and 'llama3'. The original max position embeddings used during
|
||||
pretraining.
|
||||
`attention_factor` (`float`, *optional*):
|
||||
Used with 'yarn' and 'longrope'. The scaling factor to be applied on the attention
|
||||
computation. If unspecified, it defaults to value recommended by the implementation, using the
|
||||
`factor` field to infer the suggested value.
|
||||
`beta_fast` (`float`, *optional*):
|
||||
Only used with 'yarn'. Parameter to set the boundary for extrapolation (only) in the linear
|
||||
ramp function. If unspecified, it defaults to 32.
|
||||
`beta_slow` (`float`, *optional*):
|
||||
Only used with 'yarn'. Parameter to set the boundary for interpolation (only) in the linear
|
||||
ramp function. If unspecified, it defaults to 1.
|
||||
`short_factor` (`List[float]`, *optional*):
|
||||
Only used with 'longrope'. The scaling factor to be applied to short contexts (<
|
||||
`original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
|
||||
size divided by the number of attention heads divided by 2
|
||||
`long_factor` (`List[float]`, *optional*):
|
||||
Only used with 'longrope'. The scaling factor to be applied to long contexts (<
|
||||
`original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
|
||||
size divided by the number of attention heads divided by 2
|
||||
`low_freq_factor` (`float`, *optional*):
|
||||
Only used with 'llama3'. Scaling factor applied to low frequency components of the RoPE
|
||||
`high_freq_factor` (`float`, *optional*):
|
||||
Only used with 'llama3'. Scaling factor applied to high frequency components of the RoPE
|
||||
attention_bias (`bool`, defaults to `False`, *optional*, defaults to `False`):
|
||||
Whether to use a bias in the query, key, value and output projection layers during self-attention.
|
||||
use_sliding_window (`bool`, *optional*, defaults to `False`):
|
||||
Whether to use sliding window attention.
|
||||
sliding_window (`int`, *optional*, defaults to 4096):
|
||||
Sliding window attention (SWA) window size. If not specified, will default to `4096`.
|
||||
max_window_layers (`int`, *optional*, defaults to 28):
|
||||
The number of layers that use SWA (Sliding Window Attention). The bottom layers use SWA while the top use full attention.
|
||||
attention_dropout (`float`, *optional*, defaults to 0.0):
|
||||
The dropout ratio for the attention probabilities.
|
||||
decoder_sparse_step (`int`, *optional*, defaults to 1):
|
||||
The frequency of the MoE layer.
|
||||
moe_intermediate_size (`int`, *optional*, defaults to 768):
|
||||
Intermediate size of the routed expert.
|
||||
num_experts_per_tok (`int`, *optional*, defaults to 8):
|
||||
Number of selected experts.
|
||||
num_experts (`int`, *optional*, defaults to 128):
|
||||
Number of routed experts.
|
||||
norm_topk_prob (`bool`, *optional*, defaults to `False`):
|
||||
Whether to normalize the topk probabilities.
|
||||
output_router_logits (`bool`, *optional*, defaults to `False`):
|
||||
Whether or not the router logits should be returned by the model. Enabling this will also
|
||||
allow the model to output the auxiliary loss, including load balancing loss and router z-loss.
|
||||
router_aux_loss_coef (`float`, *optional*, defaults to 0.001):
|
||||
The aux loss factor for the total loss.
|
||||
mlp_only_layers (`List[int]`, *optional*, defaults to `[]`):
|
||||
Indicate which layers use Qwen3MoeMLP rather than Qwen3MoeSparseMoeBlock
|
||||
The list contains layer index, from 0 to num_layers-1 if we have num_layers layers
|
||||
If `mlp_only_layers` is empty, `decoder_sparse_step` is used to determine the sparsity.
|
||||
|
||||
```python
|
||||
>>> from transformers import Qwen3MoeModel, Qwen3MoeConfig
|
||||
|
||||
>>> # Initializing a Qwen3MoE style configuration
|
||||
>>> configuration = Qwen3MoeConfig()
|
||||
|
||||
>>> # Initializing a model from the Qwen3-15B-A2B" style configuration
|
||||
>>> model = Qwen3MoeModel(configuration)
|
||||
|
||||
>>> # Accessing the model configuration
|
||||
>>> configuration = model.config
|
||||
```"""
|
||||
|
||||
model_type = "qwen3_moe"
|
||||
keys_to_ignore_at_inference = ["past_key_values"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab_size=151936,
|
||||
hidden_size=2048,
|
||||
intermediate_size=6144,
|
||||
num_hidden_layers=24,
|
||||
num_attention_heads=32,
|
||||
num_key_value_heads=4,
|
||||
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=10000.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=8,
|
||||
num_experts=128,
|
||||
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
|
||||
# Validate the correctness of rotary position embeddings parameters
|
||||
# BC: if there is a 'type' field, move it to 'rope_type'.
|
||||
if self.rope_scaling is not None and "type" in self.rope_scaling:
|
||||
self.rope_scaling["rope_type"] = self.rope_scaling["type"]
|
||||
|
||||
# MoE arguments
|
||||
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__ = ["Qwen3MoeConfig"]
|
||||
996
paddlenlp/transformers/qwen3_moe/modeling.py
Normal file
996
paddlenlp/transformers/qwen3_moe/modeling.py
Normal file
@@ -0,0 +1,996 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
# Copyright 2025 The Qwen team, Alibaba Group and the HuggingFace Inc. team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Paddle Qwen3Moe model."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from functools import partial
|
||||
from typing import List, Optional, Tuple, Union
|
||||
|
||||
import paddle
|
||||
import paddle.distributed.fleet.meta_parallel as mpu
|
||||
import paddle.nn.functional as F
|
||||
from paddle import Tensor, nn
|
||||
from paddle.distributed.fleet.meta_parallel import get_rng_state_tracker
|
||||
from paddle.distributed.fleet.utils import recompute
|
||||
|
||||
from .. import linear_utils
|
||||
from ..conversion_utils import StateDictNameMapping, init_name_mappings
|
||||
from ..llama.modeling import get_use_casual_mask
|
||||
from ..model_outputs import MoECausalLMOutputWithPast, MoEModelOutputWithPast
|
||||
from ..model_utils import PretrainedModel, register_base_model
|
||||
from ..moe_layer import MoELayer
|
||||
from ..utils import logger
|
||||
from .configuration import Qwen3MoeConfig
|
||||
|
||||
try:
|
||||
from paddle.distributed.fleet.utils.sequence_parallel_utils import ScatterOp
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
__all__ = [
|
||||
"Qwen3MoeModel",
|
||||
"Qwen3MoePretrainedModel",
|
||||
"Qwen3MoeForCausalLM",
|
||||
"Qwen3MoePretrainingCriterion",
|
||||
]
|
||||
|
||||
from ..qwen2_moe.modeling import Qwen2MoeGate, Qwen2MoeMLP, load_balancing_loss_func
|
||||
from ..qwen3.modeling import (
|
||||
Qwen3Attention,
|
||||
Qwen3LMHead,
|
||||
Qwen3PretrainingCriterion,
|
||||
Qwen3RMSNorm,
|
||||
_expand_2d_mask,
|
||||
_make_causal_mask,
|
||||
is_casual_mask,
|
||||
)
|
||||
|
||||
|
||||
class Qwen3MoeRMSNorm(Qwen3RMSNorm):
|
||||
pass
|
||||
|
||||
|
||||
class Qwen3MoeMLP(Qwen2MoeMLP):
|
||||
pass
|
||||
|
||||
|
||||
class Qwen3MoeAttention(Qwen3Attention):
|
||||
pass
|
||||
|
||||
|
||||
class Qwen3MoeGate(Qwen2MoeGate):
|
||||
pass
|
||||
|
||||
|
||||
class ExpertParallelQwen3MoeSparseMoeBlock(MoELayer):
|
||||
def __init__(self, config: Qwen3MoeConfig):
|
||||
gate = Qwen3MoeGate(
|
||||
config,
|
||||
config.num_experts,
|
||||
config.hidden_size,
|
||||
top_k=config.num_experts_per_tok,
|
||||
drop_tokens=False,
|
||||
norm_topk_prob=config.norm_topk_prob,
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
config,
|
||||
moe_num_experts=config.num_experts,
|
||||
expert_class=Qwen3MoeMLP,
|
||||
expert_kwargs={"config": config},
|
||||
gate=gate,
|
||||
capacity=2.0,
|
||||
)
|
||||
|
||||
self.top_k = config.num_experts_per_tok
|
||||
self.norm_topk_prob = config.norm_topk_prob
|
||||
|
||||
def forward(self, hidden_states):
|
||||
final_hidden_states, l_aux, l_zloss = super().forward(hidden_states)
|
||||
|
||||
return final_hidden_states, l_aux
|
||||
|
||||
|
||||
class Qwen3MoeSparseMoeBlock(nn.Layer):
|
||||
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
|
||||
|
||||
# gating
|
||||
self.gate = nn.Linear(config.hidden_size, config.num_experts, bias_attr=False)
|
||||
self.experts = nn.LayerList([Qwen3MoeMLP(config) for _ in range(self.num_experts)])
|
||||
|
||||
def forward(self, hidden_states: paddle.Tensor) -> paddle.Tensor:
|
||||
""" """
|
||||
batch_size, sequence_length, hidden_dim = hidden_states.shape
|
||||
hidden_states = hidden_states.view([-1, hidden_dim])
|
||||
# router_logits: (batch * sequence_length, n_experts)
|
||||
router_logits = self.gate(hidden_states)
|
||||
|
||||
routing_weights = F.softmax(router_logits, axis=1, dtype=paddle.float32)
|
||||
# (batch * sequence_length, topk)
|
||||
routing_weights, selected_experts = paddle.topk(routing_weights, self.top_k, axis=-1)
|
||||
if self.norm_topk_prob: # only diff with mixtral sparse moe block!
|
||||
routing_weights /= routing_weights.sum(axis=-1, keepdim=True)
|
||||
# we cast back to the input dtype
|
||||
routing_weights = routing_weights.to(hidden_states.dtype)
|
||||
|
||||
final_hidden_states = paddle.zeros((batch_size * sequence_length, hidden_dim), dtype=hidden_states.dtype)
|
||||
|
||||
# One hot encode the selected experts to create an expert mask
|
||||
# this will be used to easily index which expert is going to be sollicitated
|
||||
expert_mask = paddle.nn.functional.one_hot(selected_experts, num_classes=self.num_experts).transpose([2, 1, 0])
|
||||
# [num_experts, topk, bs*seq]
|
||||
tokens_per_expert = expert_mask.reshape([expert_mask.shape[0], -1]).sum(axis=-1)
|
||||
# Loop over all available experts in the model and perform the computation on each expert
|
||||
for expert_idx in range(self.num_experts):
|
||||
if tokens_per_expert[expert_idx] <= 0.1:
|
||||
continue
|
||||
expert_layer = self.experts[expert_idx]
|
||||
top_x, idx = paddle.where(expert_mask[expert_idx])
|
||||
# Index the correct hidden states and compute the expert hidden state for
|
||||
# the current expert. We need to make sure to multiply the output hidden
|
||||
# states by `routing_weights` on the corresponding tokens (top-1 and top-2)
|
||||
|
||||
current_state = hidden_states[idx, None].reshape([-1, hidden_dim])
|
||||
current_hidden_states = expert_layer(current_state) * routing_weights[idx, top_x].unsqueeze(-1)
|
||||
final_hidden_states.index_add_(
|
||||
index=idx.reshape([-1]), axis=0, value=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 Qwen3MoeDecoderLayer(nn.Layer):
|
||||
def __init__(self, config: Qwen3MoeConfig, layerwise_recompute: bool = False):
|
||||
super().__init__()
|
||||
self.config = config
|
||||
|
||||
self.self_attn = Qwen3MoeAttention(config, layerwise_recompute)
|
||||
|
||||
if config.num_experts > 0:
|
||||
self.mlp = ExpertParallelQwen3MoeSparseMoeBlock(config)
|
||||
else:
|
||||
# num_experts == 0 or this layer is not sparse layer
|
||||
self.mlp = Qwen3MoeMLP(config)
|
||||
|
||||
self.input_layernorm = Qwen3MoeRMSNorm(config)
|
||||
self.post_attention_layernorm = Qwen3MoeRMSNorm(config)
|
||||
|
||||
self.sequence_parallel = config.sequence_parallel
|
||||
# Note that we will actually perform a recompute only if both enable_recompute and layerwise_recompute are set to True
|
||||
# Enable_recompute defaults to False and is controlled by Trainer
|
||||
self.enable_recompute = False
|
||||
self.layerwise_recompute = layerwise_recompute
|
||||
self.recompute_granularity = config.recompute_granularity
|
||||
|
||||
def forward(
|
||||
self,
|
||||
hidden_states: paddle.Tensor,
|
||||
position_ids: Optional[paddle.Tensor] = None,
|
||||
attention_mask: Optional[paddle.Tensor] = None,
|
||||
output_attentions: Optional[bool] = False,
|
||||
output_router_logits: Optional[bool] = False,
|
||||
past_key_value: Optional[Tuple[paddle.Tensor]] = None,
|
||||
use_cache: Optional[bool] = False,
|
||||
attn_mask_startend_row_indices: Optional[paddle.Tensor] = None,
|
||||
**kwargs,
|
||||
) -> Tuple[paddle.Tensor, Optional[Tuple[paddle.Tensor, paddle.Tensor]]]:
|
||||
"""
|
||||
Args:
|
||||
hidden_states (`paddle.Tensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
|
||||
attention_mask (`paddle.Tensor`, *optional*): attention mask of size
|
||||
`(batch, sequence_length)` where padding elements are indicated by 0.
|
||||
output_attentions (`bool`, *optional*):
|
||||
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
||||
returned tensors for more detail.
|
||||
output_router_logits (`bool`, *optional*):
|
||||
Whether or not to return the logits of all the routers. They are useful for computing the router loss, and
|
||||
should not be returned during inference.
|
||||
use_cache (`bool`, *optional*):
|
||||
If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
|
||||
(see `past_key_values`).
|
||||
past_key_value (`Tuple(paddle.Tensor)`, *optional*): cached past key and value projection states
|
||||
"""
|
||||
|
||||
# [bs * seq_len, embed_dim] -> [seq_len * bs / n, embed_dim] (sequence_parallel)
|
||||
residual = hidden_states
|
||||
|
||||
hidden_states = self.input_layernorm(hidden_states)
|
||||
|
||||
# Self Attention
|
||||
has_gradient = not hidden_states.stop_gradient
|
||||
if (
|
||||
self.enable_recompute
|
||||
and self.layerwise_recompute
|
||||
and has_gradient
|
||||
and self.recompute_granularity == "full_attn"
|
||||
):
|
||||
outputs = recompute(
|
||||
self.self_attn,
|
||||
hidden_states,
|
||||
position_ids,
|
||||
past_key_value,
|
||||
attention_mask,
|
||||
output_attentions,
|
||||
use_cache,
|
||||
attn_mask_startend_row_indices,
|
||||
use_reentrant=self.config.recompute_use_reentrant,
|
||||
)
|
||||
else:
|
||||
outputs = self.self_attn(
|
||||
hidden_states,
|
||||
position_ids,
|
||||
past_key_value,
|
||||
attention_mask,
|
||||
output_attentions,
|
||||
use_cache,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
)
|
||||
|
||||
if type(outputs) is tuple:
|
||||
hidden_states = outputs[0]
|
||||
else:
|
||||
hidden_states = outputs
|
||||
|
||||
if output_attentions:
|
||||
self_attn_weights = outputs[1]
|
||||
|
||||
if use_cache:
|
||||
present_key_value = outputs[2 if output_attentions else 1]
|
||||
|
||||
hidden_states = residual + hidden_states
|
||||
|
||||
# Fully Connected
|
||||
residual = hidden_states
|
||||
hidden_states = self.post_attention_layernorm(hidden_states)
|
||||
hidden_states = self.mlp(hidden_states)
|
||||
if isinstance(hidden_states, tuple):
|
||||
hidden_states, router_logits = hidden_states
|
||||
else:
|
||||
router_logits = None
|
||||
|
||||
hidden_states = residual + hidden_states
|
||||
|
||||
outputs = (hidden_states,)
|
||||
|
||||
if output_attentions:
|
||||
outputs += (self_attn_weights,)
|
||||
|
||||
if use_cache:
|
||||
outputs += (present_key_value,)
|
||||
|
||||
if output_router_logits:
|
||||
outputs += (router_logits,)
|
||||
|
||||
if type(outputs) is tuple and len(outputs) == 1:
|
||||
outputs = outputs[0]
|
||||
|
||||
return outputs
|
||||
|
||||
|
||||
class Qwen3MoePretrainedModel(PretrainedModel):
|
||||
config_class = Qwen3MoeConfig
|
||||
base_model_prefix = "model"
|
||||
_keys_to_ignore_on_load_unexpected = [r"self_attn.rotary_emb.inv_freq"]
|
||||
|
||||
@classmethod
|
||||
def _get_name_mappings(cls, config: Qwen3MoeConfig) -> list[StateDictNameMapping]:
|
||||
mappings: list[StateDictNameMapping] = []
|
||||
model_mappings = [
|
||||
["embed_tokens.weight"],
|
||||
["norm.weight"],
|
||||
]
|
||||
for layer_index in range(config.num_hidden_layers):
|
||||
layer_mappings = [
|
||||
[f"layers.{layer_index}.self_attn.q_proj.weight", None, "transpose"],
|
||||
[f"layers.{layer_index}.self_attn.k_proj.weight", None, "transpose"],
|
||||
[f"layers.{layer_index}.self_attn.v_proj.weight", None, "transpose"],
|
||||
[f"layers.{layer_index}.self_attn.o_proj.weight", None, "transpose"],
|
||||
[f"layers.{layer_index}.self_attn.rotary_emb.inv_freq"],
|
||||
[f"layers.{layer_index}.input_layernorm.weight"],
|
||||
[f"layers.{layer_index}.post_attention_layernorm.weight"],
|
||||
[f"layers.{layer_index}.self_attn.q_norm.weight"],
|
||||
[f"layers.{layer_index}.self_attn.k_norm.weight"],
|
||||
]
|
||||
model_mappings.extend(layer_mappings)
|
||||
|
||||
for expert_idx in range(config.num_experts):
|
||||
expert_mappings = [
|
||||
[f"layers.{layer_index}.mlp.experts.{expert_idx}.gate_proj.weight", None, "transpose"],
|
||||
[f"layers.{layer_index}.mlp.experts.{expert_idx}.down_proj.weight", None, "transpose"],
|
||||
[f"layers.{layer_index}.mlp.experts.{expert_idx}.up_proj.weight", None, "transpose"],
|
||||
]
|
||||
model_mappings.extend(expert_mappings)
|
||||
model_mappings.append([f"layers.{layer_index}.mlp.gate.weight", None, "transpose"])
|
||||
|
||||
init_name_mappings(mappings=model_mappings)
|
||||
# base-model prefix "Qwen3MoeModel"
|
||||
if "Qwen3MoeModel" not in config.architectures:
|
||||
for mapping in model_mappings:
|
||||
mapping[0] = "model." + mapping[0]
|
||||
mapping[1] = "model." + mapping[1]
|
||||
model_mappings.append(["lm_head.weight", "lm_head.weight", "transpose"])
|
||||
|
||||
mappings = [StateDictNameMapping(*mapping, index=index) for index, mapping in enumerate(model_mappings)]
|
||||
return mappings
|
||||
|
||||
@classmethod
|
||||
def _get_tensor_parallel_mappings(cls, config: Qwen3MoeConfig, is_split=True):
|
||||
from paddlenlp.transformers.conversion_utils import split_or_merge_func
|
||||
|
||||
fn = split_or_merge_func(
|
||||
is_split=is_split,
|
||||
tensor_parallel_degree=config.tensor_parallel_degree,
|
||||
tensor_parallel_rank=config.tensor_parallel_rank,
|
||||
num_attention_heads=config.num_attention_heads,
|
||||
)
|
||||
|
||||
def get_tensor_parallel_split_mappings(num_layers, num_experts):
|
||||
final_actions = {}
|
||||
|
||||
base_actions = {
|
||||
"lm_head.weight": partial(fn, is_column=True),
|
||||
# Row Linear
|
||||
"embed_tokens.weight": partial(fn, is_column=False),
|
||||
"layers.0.self_attn.o_proj.weight": partial(fn, is_column=False),
|
||||
}
|
||||
|
||||
if not config.vocab_size % config.tensor_parallel_degree == 0:
|
||||
base_actions.pop("lm_head.weight")
|
||||
base_actions.pop("embed_tokens.weight")
|
||||
|
||||
# Column Linear
|
||||
base_actions["layers.0.self_attn.q_proj.weight"] = partial(fn, is_column=True)
|
||||
# if we have enough num_key_value_heads to split, then split it.
|
||||
if config.num_key_value_heads % config.tensor_parallel_degree == 0:
|
||||
base_actions["layers.0.self_attn.k_proj.weight"] = partial(fn, is_column=True)
|
||||
base_actions["layers.0.self_attn.v_proj.weight"] = partial(fn, is_column=True)
|
||||
|
||||
for key, action in base_actions.items():
|
||||
if "layers.0." in key:
|
||||
for i in range(num_layers):
|
||||
final_actions[key.replace("layers.0.", f"layers.{i}.")] = action
|
||||
final_actions[key] = action
|
||||
|
||||
# Add tp split for expert params.
|
||||
base_actions = {
|
||||
"layers.0.mlp.experts.0.gate_proj.weight": partial(fn, is_column=True),
|
||||
"layers.0.mlp.experts.0.down_proj.weight": partial(fn, is_column=False),
|
||||
"layers.0.mlp.experts.0.up_proj.weight": partial(fn, is_column=True),
|
||||
}
|
||||
for key, action in base_actions.items():
|
||||
for i in range(num_layers):
|
||||
newkey = key.replace("layers.0.", f"layers.{i}.")
|
||||
for j in range(num_experts):
|
||||
newkey2 = newkey.replace("experts.0.", f"experts.{j}.")
|
||||
final_actions[newkey2] = action
|
||||
|
||||
# Add tp split for shared expert params.
|
||||
base_actions = {}
|
||||
for key, action in base_actions.items():
|
||||
if "layers.0." in key:
|
||||
for i in range(num_layers):
|
||||
final_actions[key.replace("layers.0.", f"layers.{i}.")] = action
|
||||
final_actions[key] = action
|
||||
|
||||
return final_actions
|
||||
|
||||
mappings = get_tensor_parallel_split_mappings(config.num_hidden_layers, config.num_experts)
|
||||
|
||||
return mappings
|
||||
|
||||
@classmethod
|
||||
def _get_fuse_or_split_param_mappings(cls, config: Qwen3MoeConfig, is_fuse=False):
|
||||
# return parameter fuse utils
|
||||
from paddlenlp.transformers.conversion_utils import split_or_fuse_func
|
||||
|
||||
fn = split_or_fuse_func(is_fuse=is_fuse)
|
||||
|
||||
# last key is fused key, other keys are to be fused.
|
||||
fuse_qkv_keys = [
|
||||
(
|
||||
"layers.0.self_attn.q_proj.weight",
|
||||
"layers.0.self_attn.k_proj.weight",
|
||||
"layers.0.self_attn.v_proj.weight",
|
||||
"layers.0.self_attn.qkv_proj.weight",
|
||||
),
|
||||
]
|
||||
|
||||
fuse_gate_up_keys = (
|
||||
"layers.0.mlp.gate_proj.weight",
|
||||
"layers.0.mlp.up_proj.weight",
|
||||
"layers.0.mlp.gate_up_fused_proj.weight",
|
||||
)
|
||||
num_heads = config.num_attention_heads
|
||||
num_key_value_heads = getattr(config, "num_key_value_heads", num_heads)
|
||||
fuse_attention_qkv = getattr(config, "fuse_attention_qkv", False)
|
||||
fuse_attention_ffn = getattr(config, "fuse_attention_ffn", False)
|
||||
|
||||
final_actions = {}
|
||||
if is_fuse:
|
||||
if fuse_attention_qkv:
|
||||
for i in range(config.num_hidden_layers):
|
||||
for fuse_keys in fuse_qkv_keys:
|
||||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_keys])
|
||||
final_actions[keys] = partial(
|
||||
fn, is_qkv=True, num_heads=num_heads, num_key_value_heads=num_key_value_heads
|
||||
)
|
||||
if fuse_attention_ffn:
|
||||
for i in range(config.num_hidden_layers):
|
||||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_gate_up_keys])
|
||||
final_actions[keys] = fn
|
||||
else:
|
||||
if not fuse_attention_qkv:
|
||||
for i in range(config.num_hidden_layers):
|
||||
for fuse_keys in fuse_qkv_keys:
|
||||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_keys])
|
||||
final_actions[keys] = partial(
|
||||
fn, split_nums=3, is_qkv=True, num_heads=num_heads, num_key_value_heads=num_key_value_heads
|
||||
)
|
||||
if not fuse_attention_ffn:
|
||||
for i in range(config.num_hidden_layers):
|
||||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_gate_up_keys])
|
||||
final_actions[keys] = partial(fn, split_nums=2)
|
||||
return final_actions
|
||||
|
||||
def _init_weights(self, layer):
|
||||
"""Initialization hook"""
|
||||
return None
|
||||
if self.config.tensor_parallel_degree > 1:
|
||||
rng_tracker = get_rng_state_tracker().rng_state
|
||||
if isinstance(
|
||||
layer,
|
||||
(
|
||||
nn.Linear,
|
||||
nn.Embedding,
|
||||
mpu.VocabParallelEmbedding,
|
||||
mpu.RowParallelLinear,
|
||||
mpu.ColumnParallelLinear,
|
||||
linear_utils.RowSequenceParallelLinear,
|
||||
linear_utils.ColumnSequenceParallelLinear,
|
||||
Qwen3MoeLMHead,
|
||||
),
|
||||
):
|
||||
# In the dygraph mode, use the `set_value` to reset the parameter directly,
|
||||
# and reset the `state_dict` to update parameter in static mode.
|
||||
if isinstance(layer.weight, paddle.Tensor):
|
||||
if layer.weight.is_distributed:
|
||||
with rng_tracker():
|
||||
layer.weight.set_value(
|
||||
paddle.tensor.normal(
|
||||
mean=0.0,
|
||||
std=self.config.initializer_range
|
||||
if hasattr(self.config, "initializer_range")
|
||||
else self.model.config.initializer_range,
|
||||
shape=layer.weight.shape,
|
||||
)
|
||||
)
|
||||
else:
|
||||
layer.weight.set_value(
|
||||
paddle.tensor.normal(
|
||||
mean=0.0,
|
||||
std=self.config.initializer_range
|
||||
if hasattr(self.config, "initializer_range")
|
||||
else self.model.config.initializer_range,
|
||||
shape=layer.weight.shape,
|
||||
)
|
||||
)
|
||||
if hasattr(layer, "bias") and isinstance(layer.bias, paddle.Tensor):
|
||||
layer.bias.set_value(paddle.zeros_like(layer.bias))
|
||||
# Layer.apply is DFS https://github.com/PaddlePaddle/Paddle/blob/a6f5021fcc58b21f4414bae6bf4731ef6971582c/python/paddle/nn/layer/layers.py#L527-L530
|
||||
# sublayer is init first
|
||||
# scale RowParallelLinear weight
|
||||
with paddle.no_grad():
|
||||
if isinstance(layer, Qwen3MoeMLP):
|
||||
factor = 1 / math.sqrt(2 * self.config.num_hidden_layers)
|
||||
layer.down_proj.weight.scale_(factor)
|
||||
if isinstance(layer, Qwen3MoeAttention):
|
||||
factor = 1 / math.sqrt(2 * self.config.num_hidden_layers)
|
||||
layer.o_proj.weight.scale_(factor)
|
||||
|
||||
|
||||
@register_base_model
|
||||
class Qwen3MoeModel(Qwen3MoePretrainedModel):
|
||||
"""
|
||||
Transformer decoder consisting of *config.num_hidden_layers* layers. Each layer is a [`Qwen3MoeDecoderLayer`]
|
||||
Args:
|
||||
config: Qwen3MoeConfig
|
||||
"""
|
||||
|
||||
def __init__(self, config: Qwen3MoeConfig):
|
||||
super().__init__(config)
|
||||
self.padding_idx = config.pad_token_id
|
||||
self.vocab_size = config.vocab_size
|
||||
self.hidden_size = config.hidden_size
|
||||
self.sequence_parallel = config.sequence_parallel
|
||||
self.recompute_granularity = config.recompute_granularity
|
||||
self.no_recompute_layers = config.no_recompute_layers if config.no_recompute_layers is not None else []
|
||||
|
||||
# Recompute defaults to False and is controlled by Trainer
|
||||
self.enable_recompute = False
|
||||
if config.tensor_parallel_degree > 1 and config.vocab_size % config.tensor_parallel_degree == 0:
|
||||
self.embed_tokens = mpu.VocabParallelEmbedding(
|
||||
self.vocab_size,
|
||||
self.hidden_size,
|
||||
weight_attr=paddle.ParamAttr(initializer=nn.initializer.XavierNormal()),
|
||||
)
|
||||
else:
|
||||
self.embed_tokens = nn.Embedding(
|
||||
self.vocab_size,
|
||||
self.hidden_size,
|
||||
)
|
||||
|
||||
self.layers = nn.LayerList(
|
||||
[
|
||||
Qwen3MoeDecoderLayer(
|
||||
config=config,
|
||||
layerwise_recompute=layer_idx not in self.no_recompute_layers,
|
||||
)
|
||||
for layer_idx in range(config.num_hidden_layers)
|
||||
]
|
||||
)
|
||||
self.norm = Qwen3MoeRMSNorm(config)
|
||||
|
||||
def get_input_embeddings(self):
|
||||
return self.embed_tokens
|
||||
|
||||
def set_input_embeddings(self, value):
|
||||
self.embed_tokens = value
|
||||
|
||||
@staticmethod
|
||||
def _prepare_decoder_attention_mask(attention_mask, input_shape, past_key_values_length, dtype):
|
||||
if attention_mask is not None:
|
||||
# [bsz, seq_len] -> [bsz, 1, tgt_seq_len, src_seq_len]
|
||||
if len(attention_mask.shape) == 2:
|
||||
expanded_attn_mask = _expand_2d_mask(attention_mask, dtype, tgt_length=input_shape[-1])
|
||||
# For decoding phase in generation, seq_length = 1, we don't need to add causal mask
|
||||
if input_shape[-1] > 1:
|
||||
combined_attention_mask = _make_causal_mask(
|
||||
input_shape,
|
||||
past_key_values_length=past_key_values_length,
|
||||
)
|
||||
expanded_attn_mask = expanded_attn_mask & combined_attention_mask
|
||||
# [bsz, seq_len, seq_len] -> [bsz, 1, seq_len, seq_len]
|
||||
elif len(attention_mask.shape) == 3:
|
||||
expanded_attn_mask = attention_mask.unsqueeze(1).astype("bool")
|
||||
# if attention_mask is already 4-D, do nothing
|
||||
else:
|
||||
expanded_attn_mask = attention_mask
|
||||
else:
|
||||
expanded_attn_mask = _make_causal_mask(
|
||||
input_shape,
|
||||
past_key_values_length=past_key_values_length,
|
||||
)
|
||||
# Convert bool attention_mask to float attention mask, which will be added to attention_scores later
|
||||
expanded_attn_mask = paddle.where(expanded_attn_mask.to("bool"), 0.0, paddle.finfo(dtype).min).astype(dtype)
|
||||
return expanded_attn_mask
|
||||
|
||||
@paddle.jit.not_to_static
|
||||
def recompute_training_full(
|
||||
self,
|
||||
layer_module: nn.Layer,
|
||||
hidden_states: Tensor,
|
||||
position_ids: Optional[Tensor],
|
||||
attention_mask: Tensor,
|
||||
output_attentions: bool,
|
||||
output_router_logits: bool,
|
||||
past_key_value: Tensor,
|
||||
use_cache: bool,
|
||||
attn_mask_startend_row_indices=None,
|
||||
):
|
||||
def create_custom_forward(module):
|
||||
def custom_forward(*inputs):
|
||||
return module(*inputs)
|
||||
|
||||
return custom_forward
|
||||
|
||||
hidden_states = recompute(
|
||||
create_custom_forward(layer_module),
|
||||
hidden_states,
|
||||
position_ids,
|
||||
attention_mask,
|
||||
output_attentions,
|
||||
output_router_logits,
|
||||
past_key_value,
|
||||
use_cache,
|
||||
attn_mask_startend_row_indices,
|
||||
use_reentrant=self.config.recompute_use_reentrant,
|
||||
)
|
||||
|
||||
return hidden_states
|
||||
|
||||
def forward(
|
||||
self,
|
||||
input_ids: paddle.Tensor = None,
|
||||
position_ids: Optional[paddle.Tensor] = None,
|
||||
attention_mask: Optional[paddle.Tensor] = None,
|
||||
inputs_embeds: Optional[paddle.Tensor] = None,
|
||||
use_cache: Optional[bool] = None,
|
||||
past_key_values: Optional[List[paddle.Tensor]] = None,
|
||||
output_attentions: Optional[bool] = None,
|
||||
output_hidden_states: Optional[bool] = None,
|
||||
output_router_logits: Optional[bool] = None,
|
||||
return_dict: Optional[bool] = None,
|
||||
attn_mask_startend_row_indices=None,
|
||||
**kwargs,
|
||||
) -> Union[Tuple, MoEModelOutputWithPast]:
|
||||
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
|
||||
)
|
||||
use_cache = use_cache if use_cache is not None else self.config.use_cache
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
|
||||
# retrieve input_ids and inputs_embeds
|
||||
if input_ids is not None and inputs_embeds is not None:
|
||||
raise ValueError("You cannot specify both decoder_input_ids and decoder_inputs_embeds at the same time")
|
||||
elif input_ids is not None:
|
||||
batch_size, seq_length = input_ids.shape
|
||||
elif inputs_embeds is not None:
|
||||
batch_size, seq_length, _ = inputs_embeds.shape
|
||||
else:
|
||||
raise ValueError("You have to specify either decoder_input_ids or decoder_inputs_embeds")
|
||||
|
||||
if past_key_values is None:
|
||||
past_key_values = tuple([None] * len(self.layers))
|
||||
# NOTE: to make cache can be clear in-time
|
||||
past_key_values = list(past_key_values)
|
||||
|
||||
seq_length_with_past = seq_length
|
||||
cache_length = 0
|
||||
if past_key_values[0] is not None:
|
||||
cache_length = past_key_values[0][0].shape[1]
|
||||
seq_length_with_past += cache_length
|
||||
if inputs_embeds is None:
|
||||
# [bs, seq_len, dim]
|
||||
inputs_embeds = self.embed_tokens(input_ids)
|
||||
|
||||
if self.sequence_parallel:
|
||||
# [bs, seq_len, num_head * head_dim] -> [bs * seq_len, num_head * head_dim]
|
||||
bs, seq_len, hidden_size = inputs_embeds.shape
|
||||
inputs_embeds = paddle.reshape_(inputs_embeds, [bs * seq_len, hidden_size])
|
||||
# [seq_len * bs / n, num_head * head_dim] (n is mp parallelism)
|
||||
inputs_embeds = ScatterOp.apply(inputs_embeds)
|
||||
|
||||
# embed positions
|
||||
if attn_mask_startend_row_indices is not None or get_use_casual_mask():
|
||||
attention_mask = None
|
||||
else:
|
||||
# [bs, seq_len]
|
||||
attention_mask = (
|
||||
paddle.ones((batch_size, seq_length_with_past), dtype=paddle.bool)
|
||||
if attention_mask is None
|
||||
else attention_mask
|
||||
)
|
||||
attention_mask = self._prepare_decoder_attention_mask(
|
||||
attention_mask, (batch_size, seq_length), cache_length, inputs_embeds.dtype
|
||||
) # [bs, 1, seq_len, seq_len]
|
||||
if self.config.use_flash_attention:
|
||||
attention_mask = None if is_casual_mask(attention_mask) else attention_mask
|
||||
|
||||
if position_ids is None:
|
||||
position_ids = paddle.arange(seq_length, dtype="int64").expand((batch_size, seq_length))
|
||||
|
||||
hidden_states = inputs_embeds
|
||||
|
||||
# decoder layers
|
||||
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
|
||||
next_decoder_cache = () if use_cache else None
|
||||
|
||||
for idx, (decoder_layer) in enumerate(self.layers):
|
||||
if output_hidden_states:
|
||||
all_hidden_states += (hidden_states,)
|
||||
past_key_value = past_key_values[idx] if past_key_values is not None else None
|
||||
|
||||
has_gradient = not hidden_states.stop_gradient
|
||||
if (
|
||||
self.enable_recompute
|
||||
and idx not in self.no_recompute_layers
|
||||
and has_gradient
|
||||
and self.recompute_granularity == "full"
|
||||
):
|
||||
layer_outputs = self.recompute_training_full(
|
||||
decoder_layer,
|
||||
hidden_states,
|
||||
position_ids,
|
||||
attention_mask,
|
||||
output_attentions,
|
||||
output_router_logits,
|
||||
past_key_value,
|
||||
use_cache,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
)
|
||||
else:
|
||||
layer_outputs = decoder_layer(
|
||||
hidden_states,
|
||||
position_ids,
|
||||
attention_mask,
|
||||
output_attentions,
|
||||
output_router_logits,
|
||||
past_key_value,
|
||||
use_cache,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
)
|
||||
|
||||
# NOTE: clear outdate cache after it has been used for memory saving
|
||||
past_key_value = past_key_values[idx] = None
|
||||
if type(layer_outputs) is tuple:
|
||||
hidden_states = layer_outputs[0]
|
||||
else:
|
||||
hidden_states = layer_outputs
|
||||
|
||||
if output_attentions:
|
||||
all_self_attns += (layer_outputs[1],)
|
||||
|
||||
if use_cache:
|
||||
next_decoder_cache += (layer_outputs[2 if output_attentions else 1],)
|
||||
|
||||
if output_router_logits:
|
||||
all_router_logits += (layer_outputs[-1],)
|
||||
|
||||
hidden_states = self.norm(hidden_states)
|
||||
|
||||
# add hidden states from the last decoder layer
|
||||
if output_hidden_states:
|
||||
all_hidden_states += (hidden_states,)
|
||||
|
||||
next_cache = next_decoder_cache if use_cache else None
|
||||
|
||||
if not return_dict:
|
||||
return tuple(
|
||||
v
|
||||
for v in [hidden_states, next_cache, all_hidden_states, all_self_attns, all_router_logits]
|
||||
if v is not None
|
||||
)
|
||||
return MoEModelOutputWithPast(
|
||||
last_hidden_state=hidden_states,
|
||||
past_key_values=next_cache,
|
||||
hidden_states=all_hidden_states,
|
||||
attentions=all_self_attns,
|
||||
router_logits=all_router_logits,
|
||||
)
|
||||
|
||||
|
||||
class Qwen3MoePretrainingCriterion(Qwen3PretrainingCriterion):
|
||||
pass
|
||||
|
||||
|
||||
class Qwen3MoeLMHead(Qwen3LMHead):
|
||||
pass
|
||||
|
||||
|
||||
class Qwen3MoeForCausalLM(Qwen3MoePretrainedModel):
|
||||
enable_to_static_method = True
|
||||
_tied_weights_keys = ["lm_head.weight"]
|
||||
|
||||
def __init__(self, config: Qwen3MoeConfig):
|
||||
super().__init__(config)
|
||||
self.config = config
|
||||
|
||||
self.model = Qwen3MoeModel(config)
|
||||
self.lm_head = Qwen3MoeLMHead(config)
|
||||
self.criterion = Qwen3MoePretrainingCriterion(config)
|
||||
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
|
||||
|
||||
if config.sliding_window:
|
||||
self.config.sliding_window = False
|
||||
logger.warning("We do not support sliding window attention for now.")
|
||||
|
||||
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
|
||||
|
||||
def prepare_inputs_for_generation(
|
||||
self,
|
||||
input_ids,
|
||||
use_cache=False,
|
||||
past_key_values=None,
|
||||
attention_mask=None,
|
||||
inputs_embeds=None,
|
||||
output_router_logits=False,
|
||||
**kwargs,
|
||||
):
|
||||
batch_size, seq_length = input_ids.shape
|
||||
position_ids = kwargs.get("position_ids", paddle.arange(seq_length).expand((batch_size, seq_length)))
|
||||
if past_key_values:
|
||||
input_ids = input_ids[:, -1].unsqueeze(axis=-1)
|
||||
position_ids = position_ids[:, -1].unsqueeze(-1)
|
||||
|
||||
# if `inputs_embeds` are passed, we only want to use them in the 1st generation step
|
||||
if inputs_embeds is not None and past_key_values is None:
|
||||
model_inputs = {"inputs_embeds": inputs_embeds}
|
||||
else:
|
||||
model_inputs = {"input_ids": input_ids}
|
||||
|
||||
model_inputs.update(
|
||||
{
|
||||
"position_ids": position_ids,
|
||||
"past_key_values": past_key_values,
|
||||
"use_cache": use_cache,
|
||||
"attention_mask": attention_mask,
|
||||
"output_router_logits": output_router_logits,
|
||||
}
|
||||
)
|
||||
return model_inputs
|
||||
|
||||
def _get_model_inputs_spec(self, dtype: str):
|
||||
return {
|
||||
"input_ids": paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
"attention_mask": paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
"position_ids": paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def update_model_kwargs_for_generation(outputs, model_kwargs, is_encoder_decoder=False):
|
||||
# update cache
|
||||
if isinstance(outputs, tuple) and len(outputs) > 1 and not isinstance(outputs[1], paddle.Tensor):
|
||||
model_kwargs["past_key_values"] = outputs[1]
|
||||
|
||||
if isinstance(outputs, MoECausalLMOutputWithPast) and "past_key_values" in outputs:
|
||||
model_kwargs["past_key_values"] = outputs.past_key_values
|
||||
|
||||
# update position_ids
|
||||
if "position_ids" in model_kwargs and model_kwargs["position_ids"] is not None:
|
||||
position_ids = model_kwargs["position_ids"]
|
||||
model_kwargs["position_ids"] = paddle.concat([position_ids, position_ids[..., -1:] + 1], axis=-1)
|
||||
|
||||
if not is_encoder_decoder and "attention_mask" in model_kwargs:
|
||||
# TODO: support attention mask for other models
|
||||
attention_mask = model_kwargs["attention_mask"]
|
||||
if len(attention_mask.shape) == 2:
|
||||
model_kwargs["attention_mask"] = paddle.concat(
|
||||
[attention_mask, paddle.ones([attention_mask.shape[0], 1], dtype=attention_mask.dtype)],
|
||||
axis=-1,
|
||||
)
|
||||
elif len(attention_mask.shape) == 4:
|
||||
model_kwargs["attention_mask"] = paddle.concat(
|
||||
[attention_mask, paddle.ones([*attention_mask.shape[:3], 1], dtype=attention_mask.dtype)],
|
||||
axis=-1,
|
||||
)[:, :, -1:, :]
|
||||
|
||||
return model_kwargs
|
||||
|
||||
def forward(
|
||||
self,
|
||||
input_ids: paddle.Tensor = None,
|
||||
position_ids: Optional[paddle.Tensor] = None,
|
||||
attention_mask: Optional[paddle.Tensor] = None,
|
||||
inputs_embeds: Optional[paddle.Tensor] = None,
|
||||
labels: Optional[paddle.Tensor] = None,
|
||||
use_cache: Optional[bool] = None,
|
||||
past_key_values: Optional[List[paddle.Tensor]] = None,
|
||||
output_attentions: Optional[bool] = None,
|
||||
output_hidden_states: Optional[bool] = None,
|
||||
output_router_logits: Optional[bool] = None,
|
||||
return_dict: Optional[bool] = None,
|
||||
attn_mask_startend_row_indices=None,
|
||||
):
|
||||
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
|
||||
)
|
||||
output_router_logits = (
|
||||
output_router_logits if output_router_logits is not None else self.config.output_router_logits
|
||||
)
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
|
||||
if attn_mask_startend_row_indices is not None and attention_mask is not None:
|
||||
logger.warning(
|
||||
"You have provided both attn_mask_startend_row_indices and attention_mask. "
|
||||
"The attn_mask_startend_row_indices will be used."
|
||||
)
|
||||
attention_mask = None
|
||||
|
||||
# decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
|
||||
outputs = self.model(
|
||||
input_ids=input_ids, # [bs, seq_len]
|
||||
position_ids=position_ids,
|
||||
attention_mask=attention_mask,
|
||||
inputs_embeds=inputs_embeds,
|
||||
use_cache=use_cache,
|
||||
past_key_values=past_key_values,
|
||||
output_attentions=output_attentions,
|
||||
output_hidden_states=output_hidden_states,
|
||||
output_router_logits=output_router_logits,
|
||||
return_dict=return_dict,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
)
|
||||
|
||||
hidden_states = outputs[0] # [bs, seq_len, dim]
|
||||
|
||||
# if labels is None,means we need full output, instead of tensor_parallel_output
|
||||
# tensor_parallel_output is together with ParallelCrossEntropy
|
||||
tensor_parallel_output = self.config.tensor_parallel_output and self.config.tensor_parallel_degree > 1
|
||||
|
||||
if labels is not None and self.config.use_fused_linear_cross_entropy:
|
||||
from paddlenlp_kernel.triton.cut_cross_entropy import linear_cross_entropy
|
||||
|
||||
assert (
|
||||
self.config.tensor_parallel_degree <= 1
|
||||
), "The argument `use_fused_linear_cross_entropy` is imcompatiable with tensor parallel "
|
||||
|
||||
masked_lm_loss = linear_cross_entropy(hidden_states, self.lm_head.weight, targets=labels)
|
||||
|
||||
binary_sequence = paddle.where(
|
||||
masked_lm_loss > 0, paddle.ones_like(masked_lm_loss), paddle.zeros_like(masked_lm_loss)
|
||||
)
|
||||
count = paddle.sum(binary_sequence)
|
||||
if count == 0:
|
||||
loss = paddle.sum(masked_lm_loss * binary_sequence)
|
||||
else:
|
||||
loss = paddle.sum(masked_lm_loss * binary_sequence) / count
|
||||
logits = None
|
||||
else:
|
||||
logits = self.lm_head(hidden_states, tensor_parallel_output=tensor_parallel_output)
|
||||
|
||||
loss = None
|
||||
if labels is not None:
|
||||
loss = self.criterion(logits, labels)
|
||||
|
||||
aux_loss = None
|
||||
if output_router_logits:
|
||||
aux_loss = load_balancing_loss_func(
|
||||
outputs.router_logits if return_dict else outputs[-1],
|
||||
self.num_experts,
|
||||
self.num_experts_per_tok,
|
||||
attention_mask,
|
||||
)
|
||||
if labels is not None:
|
||||
loss += self.router_aux_loss_coef * aux_loss
|
||||
|
||||
if not return_dict:
|
||||
output = (logits,) + outputs[1:]
|
||||
if output_router_logits:
|
||||
output = (aux_loss,) + output
|
||||
return (loss,) + output if loss is not None else output
|
||||
|
||||
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,
|
||||
)
|
||||
254
paddlenlp/transformers/qwen3_moe/modeling_pp.py
Normal file
254
paddlenlp/transformers/qwen3_moe/modeling_pp.py
Normal file
@@ -0,0 +1,254 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from typing import OrderedDict
|
||||
|
||||
import paddle
|
||||
import paddle.distributed.fleet as fleet
|
||||
import paddle.nn as nn
|
||||
from paddle.distributed.fleet.meta_parallel import (
|
||||
LayerDesc,
|
||||
PipelineLayer,
|
||||
SharedLayerDesc,
|
||||
)
|
||||
from paddle.distributed.fleet.recompute.recompute import recompute
|
||||
|
||||
from ..model_utils import PipelinePretrainedModel
|
||||
from .modeling import (
|
||||
Qwen3MoeConfig,
|
||||
Qwen3MoeDecoderLayer,
|
||||
Qwen3MoeLMHead,
|
||||
Qwen3MoePretrainedModel,
|
||||
Qwen3MoePretrainingCriterion,
|
||||
Qwen3MoeRMSNorm,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Qwen3MoeForCausalLMPipe",
|
||||
]
|
||||
|
||||
from ..qwen2_moe.modeling_pp import (
|
||||
Qwen2MoeEmbeddingPipe,
|
||||
get_attr,
|
||||
parse_args,
|
||||
return_args,
|
||||
)
|
||||
|
||||
|
||||
class Qwen3MoeEmbeddingPipe(Qwen2MoeEmbeddingPipe):
|
||||
pass
|
||||
|
||||
|
||||
class Qwen3MoeDecoderLayerPipe(Qwen3MoeDecoderLayer):
|
||||
def forward(self, args):
|
||||
hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids = parse_args(args)
|
||||
|
||||
has_gradient = not hidden_states.stop_gradient
|
||||
|
||||
if attention_mask is not None and attention_mask.dtype == paddle.int32:
|
||||
attention_mask, attn_mask_startend_row_indices, position_ids = (
|
||||
None,
|
||||
attention_mask,
|
||||
attn_mask_startend_row_indices,
|
||||
)
|
||||
elif attention_mask is not None and attention_mask.dtype == paddle.int64:
|
||||
attention_mask, attn_mask_startend_row_indices, position_ids = None, None, attention_mask
|
||||
elif attn_mask_startend_row_indices is not None and attn_mask_startend_row_indices.dtype == paddle.int64:
|
||||
attn_mask_startend_row_indices, position_ids = None, attn_mask_startend_row_indices
|
||||
|
||||
if self.enable_recompute and self.config.recompute_granularity == "full" and has_gradient:
|
||||
if attention_mask is not None or attn_mask_startend_row_indices is not None:
|
||||
hidden_states = recompute(
|
||||
super().forward,
|
||||
hidden_states,
|
||||
position_ids=position_ids,
|
||||
attention_mask=attention_mask,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
use_reentrant=False,
|
||||
)
|
||||
else:
|
||||
# for pretrain
|
||||
hidden_states = recompute(
|
||||
super().forward,
|
||||
hidden_states,
|
||||
position_ids=position_ids,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
use_reentrant=self.config.recompute_use_reentrant,
|
||||
)
|
||||
else:
|
||||
hidden_states = super().forward(
|
||||
hidden_states,
|
||||
position_ids=position_ids,
|
||||
attention_mask=attention_mask,
|
||||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||||
)
|
||||
|
||||
return return_args(hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids)
|
||||
|
||||
|
||||
class Qwen3MoeRMSNormPipe(nn.Layer):
|
||||
def __init__(self, config):
|
||||
super().__init__()
|
||||
self.norm = Qwen3MoeRMSNorm(config)
|
||||
|
||||
def forward(self, args):
|
||||
hidden_states, attention_mask, attn_mask_startend_row_indices, position_ids = parse_args(args)
|
||||
return self.norm(hidden_states)
|
||||
|
||||
|
||||
class Qwen3MoeLMHeadPipe(Qwen3MoeLMHead):
|
||||
def __init__(self, config, transpose_y=False):
|
||||
super(Qwen3MoeLMHeadPipe, self).__init__(config)
|
||||
|
||||
@property
|
||||
def embedding_weight(self):
|
||||
return get_attr(self, "weight")
|
||||
|
||||
|
||||
class Qwen3MoeForCausalLMPipe(PipelinePretrainedModel, PipelineLayer):
|
||||
"""QWenForPretraining adapted for pipeline parallelism.
|
||||
|
||||
The largest change is flattening the QWenModel class so we can express it as a
|
||||
sequence of layers including embedding, transformer layers, and output.
|
||||
"""
|
||||
|
||||
config_class = Qwen3MoeConfig
|
||||
|
||||
_get_tensor_parallel_mappings = Qwen3MoePretrainedModel._get_tensor_parallel_mappings
|
||||
_init_weights = Qwen3MoePretrainedModel._init_weights
|
||||
_keys_to_ignore_on_load_unexpected = Qwen3MoePretrainedModel._keys_to_ignore_on_load_unexpected
|
||||
_tied_weights_keys = ["lm_head.weight"]
|
||||
|
||||
# DONOT Add base_model_prefix !!!!
|
||||
|
||||
@classmethod
|
||||
def _prepare_pipeline_inputs_func(cls, inputs):
|
||||
first_stage_keys = ["input_ids", "attention_mask", "attn_mask_startend_row_indices", "position_ids"]
|
||||
last_stage_keys = ["labels"]
|
||||
|
||||
def get_expected_keys(inputs, keys):
|
||||
ret = tuple([inputs.pop(k) if k in inputs else None for k in keys])
|
||||
if len(ret) == 1:
|
||||
ret = ret[0]
|
||||
return ret
|
||||
|
||||
if type(inputs) is dict or type(inputs) is OrderedDict:
|
||||
return [
|
||||
get_expected_keys(inputs, first_stage_keys),
|
||||
get_expected_keys(inputs, last_stage_keys),
|
||||
]
|
||||
|
||||
keys = list(inputs[0].keys())
|
||||
inputs_batch = {key: [data.pop(key) for data in inputs] for key in keys}
|
||||
return [
|
||||
get_expected_keys(inputs_batch, first_stage_keys),
|
||||
get_expected_keys(inputs_batch, last_stage_keys),
|
||||
]
|
||||
|
||||
def __init__(self, config: Qwen3MoeConfig):
|
||||
self.config = config
|
||||
|
||||
# Note that we will actually perform a recompute only if both enable_recompute and layerwise_recompute are set to True
|
||||
# Enable_recompute defaults to False and is controlled by Trainer
|
||||
self.enable_recompute = False
|
||||
self.recompute_granularity = self.config.recompute_granularity
|
||||
self.pp_recompute_interval = self.config.pp_recompute_interval
|
||||
self.no_recompute_layers = config.no_recompute_layers if config.no_recompute_layers is not None else []
|
||||
if self.recompute_granularity == "full":
|
||||
assert len(self.no_recompute_layers) == 0, "for pp with full recompute, no_recompute_layers is not support"
|
||||
|
||||
virtual_pp_degree = getattr(self.config, "virtual_pp_degree", 1)
|
||||
|
||||
def get_hcg():
|
||||
return fleet.get_hybrid_communicate_group()
|
||||
|
||||
hcg = get_hcg()
|
||||
tensor_parallel_degree = max(hcg.get_model_parallel_world_size(), 1)
|
||||
tensor_parallel_rank = max(hcg.get_model_parallel_rank(), 0)
|
||||
|
||||
# TODO: fix tensor_parallel_degree rewrite in here
|
||||
config.tensor_parallel_degree = tensor_parallel_degree
|
||||
config.tensor_parallel_rank = tensor_parallel_rank
|
||||
|
||||
if config.tie_word_embeddings:
|
||||
self.add_sequential_layer(
|
||||
SharedLayerDesc(
|
||||
"model_moe_shared_weight",
|
||||
Qwen3MoeEmbeddingPipe,
|
||||
shared_weight_attr="embedding_weight",
|
||||
config=config,
|
||||
),
|
||||
"model",
|
||||
)
|
||||
else:
|
||||
self.add_sequential_layer(LayerDesc(Qwen3MoeEmbeddingPipe, config=config), "model")
|
||||
|
||||
for i in range(config.num_hidden_layers):
|
||||
self.add_sequential_layer(
|
||||
LayerDesc(
|
||||
Qwen3MoeDecoderLayerPipe,
|
||||
config=config,
|
||||
layerwise_recompute=i not in self.no_recompute_layers,
|
||||
),
|
||||
f"model.layers.{i}",
|
||||
)
|
||||
self.add_sequential_layer(LayerDesc(Qwen3MoeRMSNormPipe, config=config), "model")
|
||||
|
||||
if config.tie_word_embeddings:
|
||||
self.add_sequential_layer(
|
||||
SharedLayerDesc(
|
||||
"model_moe_shared_weight",
|
||||
Qwen3MoeLMHeadPipe,
|
||||
shared_weight_attr="embedding_weight",
|
||||
config=config,
|
||||
**{"transpose_y": True},
|
||||
),
|
||||
"lm_head",
|
||||
)
|
||||
else:
|
||||
self.add_sequential_layer(LayerDesc(Qwen3MoeLMHeadPipe, config=config), "lm_head")
|
||||
|
||||
recompute_interval = 0
|
||||
if self.enable_recompute and self.recompute_granularity == "full":
|
||||
assert self.config.pp_recompute_interval <= config.num_hidden_layers // (
|
||||
virtual_pp_degree * get_hcg().topology().get_dim_size("pipe")
|
||||
), "pp recompute interval should smaller than num layers of each pp chunk"
|
||||
recompute_interval = self.config.pp_recompute_interval
|
||||
|
||||
seg_method = "layer:Qwen3MoeDecoderLayer"
|
||||
if config.num_hidden_layers % get_hcg().topology().get_dim_size("pipe") != 0:
|
||||
seg_method = "uniform"
|
||||
|
||||
PipelineLayer.__init__(
|
||||
self,
|
||||
layers=self.get_sequential_layers(),
|
||||
loss_fn=self.get_loss_fn(config),
|
||||
topology=get_hcg().topology(),
|
||||
seg_method=seg_method,
|
||||
recompute_interval=recompute_interval,
|
||||
recompute_ctx={
|
||||
"mp_group": get_hcg().get_model_parallel_group(),
|
||||
"offload": False,
|
||||
"partition": False,
|
||||
},
|
||||
num_virtual_pipeline_stages=virtual_pp_degree,
|
||||
)
|
||||
# You should call init here, since there is a diamond inheritance problem
|
||||
self.apply(self._init_weights)
|
||||
# DON'T init PipelinePretrainedModel
|
||||
# PipelinePretrainedModel.__init__(self.super(), config=config)
|
||||
|
||||
def get_loss_fn(self, config):
|
||||
return Qwen3MoePretrainingCriterion(config)
|
||||
@@ -25,6 +25,7 @@ import paddle
|
||||
from _io import BufferedReader
|
||||
from safetensors import deserialize
|
||||
|
||||
from paddlenlp.transformers.utils import device_guard
|
||||
from paddlenlp.utils.env import PYTORCH_WEIGHTS_NAME, SAFE_WEIGHTS_NAME
|
||||
|
||||
MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30
|
||||
@@ -226,10 +227,14 @@ def load_torch(path: str, **pickle_load_args):
|
||||
state_dict = {}
|
||||
for k, v in flat:
|
||||
dtype = _TYPES[v["dtype"]]
|
||||
if v["dtype"] == "BF16":
|
||||
arr = paddle.to_tensor(np.frombuffer(v["data"], dtype=dtype).reshape(v["shape"]), dtype="bfloat16")
|
||||
else:
|
||||
arr = paddle.to_tensor(np.frombuffer(v["data"], dtype=dtype).reshape(v["shape"]))
|
||||
with device_guard("cpu"):
|
||||
if v["dtype"] == "BF16":
|
||||
arr = paddle.Tensor(
|
||||
np.frombuffer(v["data"], dtype=dtype).reshape(v["shape"]), dtype="bfloat16", zero_copy=True
|
||||
)
|
||||
else:
|
||||
arr = paddle.Tensor(np.frombuffer(v["data"], dtype=dtype).reshape(v["shape"]), zero_copy=True)
|
||||
|
||||
state_dict[k] = arr
|
||||
|
||||
return state_dict
|
||||
|
||||
Reference in New Issue
Block a user