Repository navigation
Ulysses 模块化 - #321
Ulysses 模块化#321werwrewe wants to merge 6 commits into
Conversation
…v-swift-v5' into resolve-pr-dev-swift-v5 # Conflicts: # src/twinkle/loss/base.py # src/twinkle/loss/value.py # src/twinkle/model/transformers/moe/router_replay.py # src/twinkle/model/transformers/strategy/sequence_parallel/__init__.py # src/twinkle/model/transformers/transformers.py # src/twinkle/processor/base.py
| pass | ||
|
|
||
| if hasattr(base_model, 'language_model'): | ||
| text_model = base_model.language_model |
There was a problem hiding this comment.
这块是dpo训练时出现的问题,这个判断无法区分同架构的不同模型实例(虽然 text_model 取的是 policy,但列表里存的是各层的类型)。比如 policy 和 reference 的 attention 类型相同,就可能被当成同一个模型处理。
现在改为在每个模型的 prepare() 中选择文本侧模块树,并通过 _register_module_tree(text_model, self) 注册模块实例与 SP context 的对应关系;wrapper 调用时通过 _MODULE_TO_CTX.get(module) 找到所属 context。因此 _prepare_flash_attn() 中不再需要这段局部变量和模型判断。
| pass | ||
|
|
||
| if hasattr(base_model, 'language_model'): | ||
| text_model = base_model.language_model |
| def _pad_key(self, value, spec, position_ids=None): | ||
| if value is None: | ||
| return None | ||
| pad_value = self.tokenizer.pad_token_id if spec.pad_value == 'tokenizer' else spec.pad_value |
There was a problem hiding this comment.
就是取出pad value,由于注册的时候DataKeySpec('input_ids', split_dim=1, pad_value='tokenizer', stage='forward'),input_ids的pad值为tokenizer.pad_token_id,导入文件时没有模型实例,先用文本占位,在 _pad_key这个函数进行取出。对于别的键值都是取注册时候的pad value。
There was a problem hiding this comment.
主要是不知道 spec.pad_value == 'tokenizer' 为什么需要有这个条件
There was a problem hiding this comment.
是给input_ids的pad value开的特例判断,原因是input_ids的pad value需要根据实例化tokenizer的tokenizer.pad_token_id去取,不能在注册键值的时候固定一个pad value,因此在注册input_ids时后给的pad value是用字符串'tokenizer'占位,在实际使用到pad value的时候根据当前实例化的tokenizer.pad_token_id去取值。
| tokenizer = self.tokenizer | ||
| if not isinstance(keys, SPKeyCollection): | ||
| raise TypeError('pad_and_split_inputs expects an SPKeyCollection') | ||
| if boundary not in ('prepare', 'forward', 'model_internal', 'router_replay'): |
There was a problem hiding this comment.
这块原子化改动主要围绕pad and split函数,这四个boundary对应pad and split函数调用的四个时机,每个键值都持有一个boundary代表它被pad and split的位置。
prepare:SequenceParallel.prepare_inputs()
forward:SequenceParallel._prepare_forward_hook()
model_internal:SequenceParallel.pad_and_split_mm_tokens()
router_replay:moe/router_replay.py::set_router_replay_data()
| if micro_batch_size is None: | ||
| # normal collate | ||
| outputs = self._collate_macro_batch(inputs) | ||
| outputs = self._collate_macro_batch(inputs, sp_strategy=kwargs.get('sp_strategy')) |
There was a problem hiding this comment.
请评估一下sp_strategy能否传入processor,也许这一直是一个错误的做法
There was a problem hiding this comment.
已经改正追加commit,从 strategy 读取键规则,改为直接接收 input_key_specs / output_key_specs。改正仅限本次提交的代码,不包括以前的情形。
There was a problem hiding this comment.
然后就是假设ppo所有模型要开启sp,要怎么写cookbook
There was a problem hiding this comment.
已经改正追加commit,把processor里面所有SP相关准备移动到各自的位置去。
There was a problem hiding this comment.
可以基于现有 cookbook/rl/ppo/ppo.py 扩展,,为每个模型分别创建 DeviceMesh,并设置 ulysses_size。
Move SP input preparation, loss tensor gathering and last-token pooling into the model/strategy layer. Keep processors responsible for batch layouts and preserve sentence-level labels during SP preprocessing. Cover pooling outputs and gradients for padded, packed and ring layouts with CPU/Gloo regression tests.
eb404b8 to
f787f85
Compare
| inputs: Dict[str, Any] = processor( | ||
| inputs, | ||
| sp_strategy=self.sp_strategy, | ||
| input_key_specs=input_key_specs, |
There was a problem hiding this comment.
sp 中有哪些额外字段是需要传入processor中特殊处理的呢,是不是所有字段本身就已经被processor处理过了
| labels: torch.Tensor = inputs.pop('labels', None) | ||
| loss_scale = inputs.pop('loss_scale', None) | ||
| channel = inputs.pop('channel', None) | ||
| sp_auxiliary_inputs = processor.pop_sp_auxiliary_inputs(inputs, input_key_specs=input_key_specs) |
There was a problem hiding this comment.
pop_sp_auxiliary_inputs 的作用是什么,sp 有什么字段是需要特殊弹出的吗
?不开sp时,没有这些字段吗
PR type
PR information
改动内容
Phase 1:隔离每个模型的 SP 上下文
SequenceParallelStrategy持有自己的SequenceParallel上下文,保存该模型的通信组、rank 和当前 batch 状态。GatherLoss显式保存前向所属的上下文,反向传播不再依赖可能已被其他模型覆盖的全局单例。Phase 2:声明 SP 数据键规则
DataKeySpec、输入键注册表和输出键注册表,描述键的序列维度、padding 值、是否补齐/切分及各自执行边界、是否 gather,以及 gather 是否保留梯度。常用键与模型/任务扩展键统一放入SPKeyCollection,由pad_and_split_inputs按声明执行。labels、completion_mask、loss_scale、logps、entropies)使用统一规则处理。real_position_ids与cache_position作为位置/模型调用上下文单独传入,不混入普通键集合;completion_mask、loss_scale默认保持完整序列,避免未经声明就参与 SP 分片。Phase 3:将模型专属行为移入适配器
ModelSPAdapter合约和模型适配器注册机制,由适配器负责模型家族识别、数据键声明及模型专属 hook/patch 配置。Phase 4:由 loss 声明需要的序列数据
sp_gather_keys、sp_input_key_specs和sp_output_key_specs声明,让 loss 指定计算前需要收集或对齐的序列张量。PPOValueLoss声明收集逐 token value(存于outputs['logits']);新增自定义 token loss 用例验证输入/输出键声明和 optimizer 更新。SafeLossWrapper丢失自定义 loss SP 声明的问题,确保经过安全包装后声明仍到达训练入口。Experiment results
测试环境
硬件/软件:Ascend 910B4;CANN 9.1.0、驱动 25.5.1、Python 3.11.15、PyTorch 2.10.0+cpu / torch_npu 2.10.0、Transformers 5.13.1
训练loss的回归测试
dpo的sp>1分支打通测试,以及异构模型持有不同sp状态的测试。


带补丁的模型回归测试(改动前 vs 改动后):