ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PaddleNLP 文本生成引擎深度解析:GenerationMixin 与三种解码策略实战指南

PaddleNLP 文本生成引擎深度解析:GenerationMixin 与三种解码策略实战指南 PaddleNLP 文本生成引擎深度解析GenerationMixin 与三种解码策略实战指南【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP导读generation_utils是 PaddleNLPpaddlenlp/generation/utils.py中承载文本生成能力的核心模块它以GenerationMixin混入类的方式为所有预训练模型PretrainedModel提供统一的generate()解码接口内置贪心搜索greedy_search、采样sampling与束搜索beam_search三种解码策略并配套 logits 处理器、停止条件与流式输出机制。本文以docs/zh/source/paddlenlp.transformers.generation_utils.rst文档为主线结合源码实现与配置示例系统讲解generate()的参数语义、三种解码策略的实现细节、GenerationConfig的配置方式以及流式生成的接入方法帮助你掌握 PaddleNLP 中从模型 分词器到一段可运行生成代码的完整链路。模块定位一切生成能力的统一入口docs/zh/source/paddlenlp.transformers.generation_utils.rst通过 Sphinxautomodule指令自动生成paddlenlp.transformers.generation_utils模块的 API 文档其核心是GenerationMixin类。从当前仓库的代码结构看生成能力的实现位于 paddlenlp/generation/utils.py模块顶层通过__all__导出了GenerationMixin、BeamSearchScorer、BeamHypotheses、LogitsProcessorList等符号__all__ [ GenerationMixin, BeamSearchScorer, BeamHypotheses, LogitsProcessorList, LogitsProcessor, MinLengthLogitsProcessor, RepetitionPenaltyLogitsProcessor, TopKProcess, TopPProcess, get_unfinished_flag, ]GenerationMixin作为基类被PretrainedModel继承这意味着任何基于 PaddleNLP 的预训练模型如 UnifiedTransformer、GPT、Llama、Qwen 等都天然拥有generate()能力。官方文档对其定位的描述是This class implements the interface for generation task它被用作paddlenlp.transformers.PretrainedModel的基类。模型本身只需实现prepare_inputs_for_generation()、adjust_logits_during_generation()、reorder_cache()等钩子方法源码中的默认实现位于 utils.py 的GenerationMixin内即可复用整套解码框架。generate() 接口参数语义全解析generate()是生成任务的唯一对外接口其完整签名见 utils.py 源码为 paddle.no_grad() def generate( self, input_ids: paddle.Tensor None, generation_config: GenerationConfig None, stopping_criteria: StoppingCriteria None, streamer: BaseStreamer None, synced_gpus: Optional[bool] None, **kwargs, ):各参数语义如下参数类型默认值说明input_idsTensorNone输入序列的 token id形状为[batch_size, sequence_length]数据类型须为 int32 或 int64。为None时自动初始化为形状[1, 1]、填充bos_token_id的张量generation_configGenerationConfigNone生成配置对象**kwargs中与配置同名的参数会覆盖其属性。未提供时按优先级加载1) 模型目录下的generation_config.json2) 模型config中的默认值stopping_criteriaStoppingCriteriaListNone自定义停止条件与由参数构建的默认停止条件互补streamerBaseStreamerNone流式输出对象生成的 token 会通过streamer.put(token_ids)逐步传出synced_gpusboolNone多卡如 DeepSpeed ZeRO-3环境下是否保持 while 循环直至max_length避免部分卡提前结束导致的悬挂**kwargsdict-额外传给模型或覆盖生成配置的参数返回值的结构generate()返回一个二元组(ids, scores)idsTensor生成的序列 id形状为[batch_size * num_return_sequences, sequence_length]数据类型与输入input_ids一致scoresTensor每个生成序列的得分形状为[batch_size * num_return_sequences, 1]数据类型为 float32 或 float64与模型参数精度一致。三种解码策略的调度逻辑从generate()的源码utils.py可以清晰看到解码策略的分发过程。首先对decode_strategy做合法性校验仅接受greedy_search、sampling、beam_search三者之一。随后按策略分别调用底层实现greedy_search要求num_return_sequences必须为 1否则抛出 ValueError随后调用self.greedy_search(...)sampling若num_return_sequences 1先通过expand_inputs_for_generation将输入扩展为对应倍数再调用self.sample(...)并传入top_k、top_p、temperature三个采样参数beam_search要求num_return_sequences num_beams使用BeamSearchScorer管理束调用self.beam_search(...)num_beam_groups 1或self.group_beam_search(...)分组多样束搜索。关键的前置处理generate()内部还做了几项重要的前置处理配置解析与合并若未显式传入generation_config则使用模型自带的self.generation_config随后copy.deepcopy一份并通过generation_config.update(**kwargs)让调用参数覆盖配置项token id 回退链bos_token_id、eos_token_id、pad_token_id、forced_bos_token_id、forced_eos_token_id、decoder_start_token_id、no_repeat_ngram_size均遵循generation_config优先否则回退到self.config的取值逻辑见源码 L776-L804输入初始化input_ids为None时用prepare_input_ids_for_generation(bos_token_id)构造起始序列支持inputs_embeds作为输入attention_mask缺失时由prepare_attention_mask_for_generation依据pad_token_id、eos_token_id自动生成编解码模型适配当self.config.is_encoder_decoder为真时调用prepare_encoder_decoder_kwargs_for_generation编码输入并以decoder_input_ids缺省时由prepare_decoder_input_ids_for_generation以decoder_start_token_id或bos_token_id起始作为生成起点废弃参数迁移max_length、min_length会打印弃用警告并自动换算为max_new_tokens、min_new_tokensuse_faster、use_fast参数已直接抛错废弃流式限制streamer与束搜索不兼容若decode_strategy beam_search或num_beams 1时会抛异常pad_token 兜底set_pad_token_id在pad_token_id为空且eos_token_id非空时将pad_token_id回退为eos_token_id列表时取首元素并给出 open-end generation 提示。官方示例实战UnifiedTransformer 对话生成文档的Example部分提供了基于unified_transformer-12L-cn-luge模型的完整示例演示了三种解码策略的调用方式。以下是整理后的完整可运行代码初始化模型与输入import paddle from paddlenlp.transformers import ( UnifiedTransformerLMHeadModel, UnifiedTransformerTokenizer, ) paddle.seed(2) # 初始化模型与分词器 model_name_or_path unified_transformer-12L-cn-luge model UnifiedTransformerLMHeadModel.from_pretrained(model_name_or_path) tokenizer UnifiedTransformerTokenizer.from_pretrained(model_name_or_path) # 准备模型输入 history 早上好今天空气质量不错。 inputs tokenizer.dialogue_encode(history, task_typechitchat, add_start_token_as_responseTrue, return_tensorsTrue)tokenizer.dialogue_encode是对话式模型专用的编码入口task_typechitchat指定闲聊任务add_start_token_as_responseTrue会在响应部分前附加起始 token从而让generate()以[1, 1]的起始状态开始续写。策略一贪心搜索greedy_searchids, scores model.generate( **inputs, decode_strategygreedy_search) print(ids.shape, scores.shape) # [1, 3] [1, 1] sequence_ids ids.cpu().numpy().tolist()[0] sequence_ids sequence_ids[:sequence_ids.index(tokenizer.sep_token_id)] response tokenizer.convert_ids_to_string(sequence_ids, keep_spaceFalse) print(response) # 是的贪心搜索每一步选取概率最大的 token确定性最强、速度最快但容易陷入重复或局部最优。输出中ids的形状[1, 3]表示生成了 1 条、长度为 3 的序列解码时以sep_token_id截断响应部分。策略二采样samplingtop_k5generation_config GenerationConfig( decode_strategysampling, top_k5, num_return_sequences2 ) ids, scores model.generate( **inputs, generation_configgeneration_config, ) print(ids.shape, scores.shape) # [2, 7] [2, 1] response [] for sequence_ids in ids.cpu().numpy().tolist(): sequence_ids sequence_ids[:sequence_ids.index(tokenizer.sep_token_id)] text tokenizer.convert_ids_to_string(sequence_ids, keep_spaceFalse) response.append(text) print(response) # [天气好,心情也好, 你也是]采样策略引入随机性top_k5表示仅在概率最高的 5 个 token 中按概率分布抽样num_return_sequences2返回两条不同候选因此ids形状变为[2, 7]。采样支持的温度temperature、top-ptop_p参数可在GenerationConfig中一并设置。策略三束搜索beam_searchnum_beams5generation_config GenerationConfig( decode_strategybeam_search, num_beams5, num_return_sequences2 ) ids, scores model.generate( **inputs, generation_configgeneration_config, ) print(ids.shape, scores.shape) # [2, 3] [2, 1] response [] for sequence_ids in ids.cpu().numpy().tolist(): sequence_ids sequence_ids[:sequence_ids.index(tokenizer.sep_token_id)] text tokenizer.convert_ids_to_string(sequence_ids, keep_spaceFalse) response.append(text) print(response) # [是的, 嗯嗯]束搜索维护num_beams5条候选路径按累计 log 概率筛选解码质量高但计算开销随束宽线性增长num_return_sequences2返回得分最高的两条序列。GenerationConfig生成参数的集中化管理自新版本起generate()推荐通过GenerationConfig实现于 paddlenlp/generation/configuration_utils.py统一管理生成参数而非散落在generate()的**kwargs中。该配置类的核心能力包括from_pretrained从generation_config.json加载配置支持from_hf_hub、from_aistudio、cache_dir、force_download等参数save_pretrained将配置保存为generation_config.json实现配置随模型一起发布update(**kwargs)用键值对更新配置并返回差异字典generate()内部正是通过它实现参数覆盖from_model_config从模型PretrainedConfig推断生成配置保证未配置时的合理默认值validate()对配置做合法性校验例如束宽、采样参数取值范围。与生成直接相关的常用配置项包括配置项默认值作用decode_strategygreedy_search解码策略可选greedy_search/sampling/beam_searchmax_new_tokensDEFAULT_MAX_NEW_TOKENS最大新增 token 数max_length为废弃别名min_new_tokens0最小新增 token 数temperature1.0采样温度1.0 表示不生效top_k0top-k 截断保留的 token 数0 表示不生效top_p1.0累积概率阈值须满足0 top_p 11.0 表示不生效repetition_penalty1.0重复惩罚系数1.0 表示不惩罚no_repeat_ngram_size0禁止重复的 n-gram 大小0 表示不限制num_beams1束搜索的束宽num_beam_groups1多样束搜索的分组数diversity_rate0.0分组多样束搜索的多样性系数length_penalty0.0束搜索长度惩罚指数越大越倾向生成短序列early_stoppingFalse是否在每批至少num_beams条序列结束时提前停止束搜索bos_token_id/eos_token_id/pad_token_idNone起始、结束、填充 token iddecoder_start_token_idNone编解码模型的解码起始 token idforced_bos_token_id/forced_eos_token_idNone强制作为首 token / 末 token 的 id常用于多语言模型num_return_sequences1每个输入返回的序列数多样束搜索与长度惩罚num_beam_groups将num_beams划分为多个组以执行 DIVERSE BEAM SEARCH组间通过diversity_rate惩罚相似候选组内正常执行束搜索从而在保证质量的同时提升多样性。官方文档同时提到当num_beam_groups为 1 时diversity_rate用于 Diverse Siblings Search。length_penalty作为序列长度的指数惩罚项参与束打分见BeamHypotheses.add中的得分公式sum_logprobs / (((hyp.shape[-1] - origin_len 5) / 6) ** length_penalty)其值越大模型越倾向于生成更短的序列。解码策略的底层实现原理贪心搜索与采样greedy_search与sample是逐 token 自回归解码的两种典型实现。二者都接收logits_processors、max_length、pad_token_id、eos_token_id并支持fast_ptq_sampling量化场景下的快速采样、trunc_input截断输入与synced_gpus多卡同步选项。核心差异在于选择下一个 token 的方式贪心搜索直接取argmax采样在 logits 上先应用temperature缩放再经TopKProcess/TopPProcesspaddlenlp/generation/logits_process.py截断后按概率分布抽样。每步解码后都会依据eos_token_id更新unfinished_flag由get_unfinished_flag实现支持单个 id、多个 id 列表、乃至[[10], [20, 20]]这类按批次/多 token的结束判定并通过update_model_kwargs_for_generation更新 KV cache 等模型状态。束搜索与 BeamHypothesesbeam_search使用BeamSearchScorer内部维护每个批次的BeamHypotheses集合管理候选束。每步对batch_size * num_beams个候选打分后BeamHypotheses.process负责将已生成eos_token_id的假设归入完成列表其余继续扩展finalize在解码结束后挑选最终序列并做pad_token_id填充。BeamHypotheses.add中的长度归一化公式如上文所示early_stopping与num_beam_hyps_to_keep共同决定提前终止与保留假设的数量。分组多样束搜索group_beam_search则通过HammingDiversityLogitsProcessor施加组间惩罚见 logits_process.py 中的_get_ngrams/_calc_banned_ngram_tokens逻辑。logits 处理器与停止条件generate()通过get_logits_processor依据配置构建LogitsProcessorList按序执行MinLengthLogitsProcessor强制最小长度、RepetitionPenaltyLogitsProcessor重复惩罚、NoRepeatNGramLogitsProcessorn-gram 去重、ForcedBOSTokenLogitsProcessor/ForcedEOSTokenLogitsProcessor强制首/末 token、HammingDiversityLogitsProcessor多样性惩罚等处理器任何处理器都可改写 logits 以影响采样或贪心选择。停止条件则由 stopping_criteria.py 中的StoppingCriteriaList统一管理内置MaxLengthCriteria最大长度、MaxTimeCriteria超时等validate_stopping_criteria负责校验其与max_length的一致性。流式输出与多卡同步generate()支持通过streamer参数接入流式输出基类BaseStreamer定义于 paddlenlp/generation/streamers.py。解码循环中新生成的 token 通过streamer.put(token_ids)实时传出解码结束后调用streamer.end()从而支持类似 ChatGPT 的逐字输出体验。需要特别注意的是streamer目前不能与束搜索同时使用num_beams 1时抛出 ValueError流式解码推荐配合贪心搜索或采样策略使用。synced_gpus参数面向多卡推理场景在 DeepSpeed ZeRO-3 多卡环境下为避免某张卡提前结束 while 循环导致其余卡悬挂会强制将循环持续到max_length除非被显式覆盖。扩展阅读生成配置类paddlenlp/generation/configuration_utils.pylogits 处理器实现paddlenlp/generation/logits_process.py停止条件实现paddlenlp/generation/stopping_criteria.py流式输出实现paddlenlp/generation/streamers.py各模型对生成接口的接入方式可参考 paddlenlp/transformers 目录下对应模型的generation相关实现预训练与微调场景下的生成应用可参见 llm/docs/predict 目录下的预测文档。【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表