赞
踩
目录
本小解通过 mindnlp.transformers 加载 gpt2 模型的实践,对比观察了不同参数设置下的gpt2模型生成输出结果。包括只关心下一个最优的贪心搜索、序列最优的Beam搜索、采样生成 及其在不同参数(如温度、top-k、top-p设置)下的输出效果,不同的算法和参数设置有不同的效果,可以根据实际场景选择。
要点:根据前文预测下一个单词。
一个文本序列的概率分布可以分解为每个词基于其上文的条件概率的乘积:
,其中,
MindNLP/huggingface Transformers提供的文本生成方法:分为 beam 方法和 非beam方法。
- pip install mindnlp
- pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.2.14
1、导入了GPT2模型的分词器(tokenizer)和语言模型头(LMHeadModel)。
2、从镜像源 ’modelscope’ 加载 "iiBcai/gpt2" 项目的预训练的GPT2分词器和GPT2语言模型头,并将EOS(End Of Sequence)标记作为PAD(Padding)标记,这样做是为了避免在模型处理序列时出现警告。
3、使用分词器将字符串 ‘I enjoy walking with my cute dog’ 编码成模型可以理解的输入ID。return_tensors='ms'
表示返回的是MindSpore格式的张量。
4、使用模型进行贪婪搜索生成文本,其中 max_length=50
指定了生成文本(包括输入的上下文)的最大长度为50个token。
5、tokenizer.decode
函数将模型的输出ID转换回文本字符串。skip_special_tokens=True
参数表示在解码过程中忽略特殊token,例如 EOS 和 PAD token。
- #greedy_search
- from mindnlp.transformers import GPT2Tokenizer, GPT2LMHeadModel
-
- ## 加载 gpt2 tokenizer
- tokenizer = GPT2Tokenizer.from_pretrained("iiBcai/gpt2", mirror='modelscope')
-
- # add the EOS token as PAD token to avoid warnings
- model = GPT2LMHeadModel.from_pretrained(
- "iiBcai/gpt2",
- pad_token_id=tokenizer.eos_token_id, mirror='modelscope')
- # encode context the generation is conditioned on
- input_ids = tokenizer.encode('I enjoy walking with my cute dog',
- return_tensors='ms')
-
- # generate text until the output length (which includes the context length) reaches 50
- greedy_output = model.generate(input_ids, max_length=50)
-
- print("Output:\n" + 100 * '-')
- print(tokenizer.decode(greedy_output[0], skip_special_tokens=True))
修改输入为中文后的输出。
Beam search通过在每个时间步保留最可能的 num_beams 个词,并从中最终选择出概率最高的序列来降低丢失潜在的高概率序列的风险。
优点:一定程度保留最优路径
缺点:1. 无法解决重复问题;2. 开放域生成效果差
如下图,句子序列的概率是每个可能生成的字的概率的乘积,比如,("The","dog","has") : 0.4 * 0.9 = 0.36
代码实现流程,其中,1、2、3 步骤同贪心搜索过程。
4.1、使用模型进行Beam搜索生成文本,其中 num_beams=5 表示维护了
大小为 5 的 beam,即在每一步考虑5个可能的输出序列, max_length=50
限制了输出序列的最大长度为 50 个 token。early_stopping=True
表示一旦所有beam中的序列都完成了(即生成了EOS token),则停止生成。
4.2、通过设置 no_repeat_ngram_size 来避免重复的 n-gram,比如,设置为2表示在生成文本时避免重复2-gram(即连续两个token)。这有助于提高生成文本的多样性。
4.3、通过设置 num_return_sequences=5
表示返回前5个beam中的序列。
5、tokenizer.decode
函数将模型的输出ID转换回文本字符串,解码了第一个beam中的序列。其中,skip_special_tokens=True
参数表示在解码过程中忽略特殊token,例如 EOS 和 PAD token。
- from mindnlp.transformers import GPT2Tokenizer, GPT2LMHeadModel
-
- tokenizer = GPT2Tokenizer.from_pretrained("iiBcai/gpt2", mirror='modelscope')
-
- # add the EOS token as PAD token to avoid warnings
- model = GPT2LMHeadModel.from_pretrained("iiBcai/gpt2", pad_token_id=tokenizer.eos_token_id, mirror='modelscope')
-
- # encode context the generation is conditioned on
- input_ids = tokenizer.encode('I enjoy walking with my cute dog', return_tensors='ms')
-
- # activate beam search and early_stopping
- beam_output = model.generate(
- input_ids,
- max_length=50,
- num_beams=5,
- early_stopping=True
- )
-
- print("Output:\n" + 100 * '-')
- print(tokenizer.decode(beam_output[0], skip_special_tokens=True))
- print(100 * '-')
-
- # set no_repeat_ngram_size to 2
- beam_output = model.generate(
- input_ids,
- max_length=50,
- num_beams=5,
- no_repeat_ngram_size=2,
- early_stopping=True
- )
-
- print("Beam search with ngram, Output:\n" + 100 * '-')
- print(tokenizer.decode(beam_output[0], skip_special_tokens=True))
- print(100 * '-')
-
- # set return_num_sequences > 1
- beam_outputs = model.generate(
- input_ids,
- max_length=50,
- num_beams=5,
- no_repeat_ngram_size=2,
- num_return_sequences=5,
- early_stopping=True
- )
-
- # now we have 3 output sequences
- print("return_num_sequences, Output:\n" + 100 * '-')
- for i, beam_output in enumerate(beam_outputs):
- print("{}: {}".format(i, tokenizer.decode(beam_output, skip_special_tokens=True)))
- print(100 * '-')
如上两个图,当出现重复问题时,进行n-gram 惩罚,讲出现过的候选词概率设置为0,比如,当设置no_repeat_ngram_size=2 ,任意 2-gram 不会出现两次,但实际上有时需要重复的文本出现。
修改输入为中文后的输出,很差,感觉日文占比很多。
根据当前条件概率分布随机选择输出词 。即
- 优点:文本生成多样性高
- 缺点:生成文本不连续
例子:
("car") ~P(w∣"The") ,car 的输出由基于The条件下的nice、dog、car的分布概率选择出。
("drives") ~P(w∣"The","car") , drivers 的输出由基于The 和 Car 条件下的 drivers、is、turns 的分布概率选择出。
代码实现流程,其中,1、2、3 步骤同贪心搜索过程。
4、设置了MindSpore的随机种子为0,确保每次运行代码时生成的结果都是可复现的。
5、模型生成文本时,通过设置 do_sample=True 激活了模型的采样生成策略, 限制输出序列的最大长度为50个token。top_k=0
表示禁用了top-k采样,因为在top-k采样中,通常是从概率最高的k个token中随机选择一个token作为下一个输出,而这里设置为0表示不限制token的选择,实际上这将等同于使用 softmax 概率分布直接进行采样。
6、tokenizer.decode
函数将模型的输出ID转换回文本字符串,解码了第一个beam中的序列。其中,skip_special_tokens=True
参数表示在解码过程中忽略特殊token,例如 EOS 和 PAD token。
- import mindspore
- from mindnlp.transformers import GPT2Tokenizer, GPT2LMHeadModel
-
- tokenizer = GPT2Tokenizer.from_pretrained("iiBcai/gpt2", mirror='modelscope')
-
- # add the EOS token as PAD token to avoid warnings
- model = GPT2LMHeadModel.from_pretrained("iiBcai/gpt2", pad_token_id=tokenizer.eos_token_id, mirror='modelscope')
-
- # encode context the generation is conditioned on
- input_ids = tokenizer.encode('I enjoy walking with my cute dog', return_tensors='ms')
-
- mindspore.set_seed(0)
- # activate sampling and deactivate top_k by setting top_k sampling to 0
- sample_output = model.generate(
- input_ids,
- do_sample=True,
- max_length=50,
- top_k=0
- )
-
- print("Output:\n" + 100 * '-')
- print(tokenizer.decode(sample_output[0], skip_special_tokens=True))
中文输出依旧很垃圾。
降低 softmax 的 temperature 使 分布更陡峭,即增加高概率单词的似然并降低低概率单词的似然。
代码实现流程,其中,1、2、3、4、5 步骤同采样输出过程。
6、temperature=0.7
控制了生成的 token 的概率分布的平滑程度。较高的temperature值会使得分布更加平滑,从而增加输出的多样性,而较低的temperature值会使得分布更加尖锐,使得模型更倾向于选择概率最高的token。
7、tokenizer.decode
函数将模型的输出ID转换回文本字符串,解码了第一个beam中的序列。其中,skip_special_tokens=True
参数表示在解码过程中忽略特殊token,例如 EOS 和 PAD token。
- import mindspore
- from mindnlp.transformers import GPT2Tokenizer, GPT2LMHeadModel
-
- tokenizer = GPT2Tokenizer.from_pretrained("iiBcai/gpt2", mirror='modelscope')
-
- # add the EOS token as PAD token to avoid warnings
- model = GPT2LMHeadModel.from_pretrained("iiBcai/gpt2", pad_token_id=tokenizer.eos_token_id, mirror='modelscope')
-
- # encode context the generation is conditioned on
- input_ids = tokenizer.encode('I enjoy walking with my cute dog', return_tensors='ms')
-
- mindspore.set_seed(1234)
- # activate sampling and deactivate top_k by setting top_k sampling to 0
- sample_output = model.generate(
- input_ids,
- do_sample=True,
- max_length=50,
- top_k=0,
- temperature=0.7
- )
-
- print("Output:\n" + 100 * '-')
- print(tokenizer.decode(sample_output[0], skip_special_tokens=True))
temperature=0.7 时
temperature=0.3 时
选出概率最大的 K 个词,重新归一化,最后在归一化后的 K 个词中采样。
将采样池限制为固定大小 K :
例子展示:
代码实现流程,其中,1、2、3、4 步骤同采样输出过程。
5、模型生成文本时,通过设置 do_sample=True 激活了模型的采样生成策略, 限制输出序列的最大长度为50个token。top_k=0
表示禁用了top-k采样,因为在top-k采样中,通常是从概率最高的k个token中随机选择一个token作为下一个输出,而这里设置为0表示不限制token的选择,实际上这将等同于使用 softmax 概率分布直接进行采样。
6、tokenizer.decode
函数将模型的输出ID转换回文本字符串,解码了第一个beam中的序列。其中,skip_special_tokens=True
参数表示在解码过程中忽略特殊token,例如 EOS 和 PAD token。
- import mindspore
- from mindnlp.transformers import GPT2Tokenizer, GPT2LMHeadModel
-
- tokenizer = GPT2Tokenizer.from_pretrained("iiBcai/gpt2", mirror='modelscope')
-
- # add the EOS token as PAD token to avoid warnings
- model = GPT2LMHeadModel.from_pretrained("iiBcai/gpt2", pad_token_id=tokenizer.eos_token_id, mirror='modelscope')
-
- # encode context the generation is conditioned on
- input_ids = tokenizer.encode('I enjoy walking with my cute dog', return_tensors='ms')
-
- mindspore.set_seed(0)
- # activate sampling and deactivate top_k by setting top_k sampling to 0
- sample_output = model.generate(
- input_ids,
- do_sample=True,
- max_length=50,
- top_k=50
- )
-
- print("Output:\n" + 100 * '-')
- print(tokenizer.decode(sample_output[0], skip_special_tokens=True))
在累积概率超过概率 p 的最小单词集中进行采样,重新归一化。
其中,采样池可以根据下一个词的概率分布动态增加和减少。
例子:
代码实现流程,其中,1、2、3、4 步骤同采样输出过程。
5、模型生成文本时,通过设置 do_sample=True 激活了模型的采样生成策略, 限制输出序列的最大长度为50个token。top-p=0.92,top-p采样表示在每一步生成token时,只从概率分布中累计概率达到92%的token中进行采样。这有助于保持生成文本的流畅性和质量,同时允许一些低概率的token被选中,从而增加多样性。top_k=0
表示禁用了top-k采样。
6、tokenizer.decode
函数将模型的输出ID转换回文本字符串,解码了第一个beam中的序列。其中,skip_special_tokens=True
参数表示在解码过程中忽略特殊token,例如 EOS 和 PAD token。
- import mindspore
- from mindnlp.transformers import GPT2Tokenizer, GPT2LMHeadModel
-
- tokenizer = GPT2Tokenizer.from_pretrained("iiBcai/gpt2", mirror='modelscope')
-
- # add the EOS token as PAD token to avoid warnings
- model = GPT2LMHeadModel.from_pretrained("iiBcai/gpt2", pad_token_id=tokenizer.eos_token_id, mirror='modelscope')
-
- # encode context the generation is conditioned on
- input_ids = tokenizer.encode('I enjoy walking with my cute dog', return_tensors='ms')
-
- mindspore.set_seed(0)
-
- # deactivate top_k sampling and sample only from 92% most likely words
- sample_output = model.generate(
- input_ids,
- do_sample=True,
- max_length=50,
- top_p=0.92,
- top_k=0
- )
-
- print("Output:\n" + 100 * '-')
- print(tokenizer.decode(sample_output[0], skip_special_tokens=True))
代码实现流程,其中,1、2、3、4 步骤同采样输出过程。
5、模型生成文本时,通过设置 do_sample=True 激活了模型的采样生成策略, 限制输出序列的最大长度为50个token。top-p=0.95,top-p采样表示在每一步生成token时,只从概率分布中累计概率达到95%的token中进行采样,有助于保持生成文本的流畅性和质量,同时允许一些低概率的token被选中,从而增加多样性。top_k=5
表示在每一步生成token时,模型将考虑概率最高的5个token进行采样。num_return_sequences=3
指示模型生成3个不同的输出序列。
6、tokenizer.decode
函数将模型的输出ID转换回文本字符串,解码了第一个beam中的序列。其中,skip_special_tokens=True
参数表示在解码过程中忽略特殊token,例如 EOS 和 PAD token。
- import mindspore
- from mindnlp.transformers import GPT2Tokenizer, GPT2LMHeadModel
-
- tokenizer = GPT2Tokenizer.from_pretrained("iiBcai/gpt2", mirror='modelscope')
-
- # add the EOS token as PAD token to avoid warnings
- model = GPT2LMHeadModel.from_pretrained("iiBcai/gpt2", pad_token_id=tokenizer.eos_token_id, mirror='modelscope')
-
- # encode context the generation is conditioned on
- input_ids = tokenizer.encode('I enjoy walking with my cute dog', return_tensors='ms')
-
- mindspore.set_seed(0)
- # set top_k = 50 and set top_p = 0.95 and num_return_sequences = 3
- sample_outputs = model.generate(
- input_ids,
- do_sample=True,
- max_length=50,
- top_k=5,
- top_p=0.95,
- num_return_sequences=3
- )
-
- print("Output:\n" + 100 * '-')
- for i, sample_output in enumerate(sample_outputs):
- print("{}: {}".format(i, tokenizer.decode(sample_output, skip_special_tokens=True)))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。