当前位置: 首页 > article >正文

基于Python的自然语言处理系列(39):Huggingface中的解码策略

        在自然语言生成任务中,如何选择下一步的单词或者词语对生成的文本质量影响巨大。Huggingface 提供了多种解码策略,可以在不同的场景下平衡流畅度、创造力以及生成效率。在这篇文章中,我们将逐步介绍 Huggingface 中的几种常见解码策略,包括贪婪搜索、Beam Search(束搜索)、采样、Top-K 采样以及 Top-p(核采样)。通过具体代码示例,我们将对比这些策略的效果,并讨论它们在实际应用中的利弊。

加载GPT-2模型

        我们首先加载 GPT-2 模型和对应的分词器。为了避免警告信息,我们将 EOS(End of Sequence,序列结束符)设置为 PAD(填充符)。

from transformers import GPT2LMHeadModel, GPT2Tokenizer

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")

# 将 EOS token 设置为 PAD token
model = GPT2LMHeadModel.from_pretrained("gpt2", pad_token_id=tokenizer.eos_token_id)

贪婪搜索(Greedy Search)

        贪婪搜索是一种最简单的解码方法。在每一步,贪婪搜索直接选择具有最高概率的下一个词语,直到达到设定的最大长度。这种策略虽然简单高效,但往往会导致模型重复生成相同的词组。

        让我们通过 GPT-2 模型来生成一段文本,给定的上下文是 I enjoy walking with my cute dog

# 编码输入
input_ids = tokenizer.encode('I enjoy walking with my cute dog', return_tensors='pt')

# 使用贪婪搜索生成文本,最大长度设为50
greedy_output = model.generate(input_ids, max_length=50)

print("输出:\n" + 100 * '-')
print(tokenizer.decode(greedy_output[0], skip_special_tokens=True))

        虽然生成的文本看似合理,但贪婪搜索容易出现重复生成的情况。这个问题在对话生成、故事生成等开放式任务中尤为突出。

Beam Search(束搜索)

        Beam Search 能够缓解贪婪搜索的局限性,通过在每个时间步跟踪 num_beams 个最有可能的候选词序列,直到所有序列都到达 EOS 标记为止。这种方法比贪婪搜索更有可能找到更优的词序列。        

# 激活束搜索,设定 beam 数量为 5
beam_output = model.generate(
    input_ids,  
    max_length=50, 
    num_beams=5, 
    early_stopping=True
)

print("输出:\n" + 100 * '-')
print(tokenizer.decode(beam_output[0], skip_special_tokens=True))

        尽管 Beam Search 生成的文本更连贯,但它仍然可能出现重复现象。为了进一步提升生成质量,我们可以通过引入 n-gram 惩罚机制来减少重复的出现。

# 设置 no_repeat_ngram_size 参数为 2,避免重复生成二元组
beam_output = model.generate(
    input_ids, 
    max_length=50, 
    num_beams=5, 
    no_repeat_ngram_size=2, 
    early_stopping=True
)

print("输出:\n" + 100 * '-')
print(tokenizer.decode(beam_output[0], skip_special_tokens=True))

        我们还可以通过设置 num_return_sequences 参数,生成多个不同的候选序列。

# 生成多个候选序列
beam_outputs = model.generate(
    input_ids, 
    max_length=50, 
    num_beams=5, 
    no_repeat_ngram_size=2, 
    num_return_sequences=3, 
    early_stopping=True
)

print("输出:\n" + 100 * '-')
for i, beam_output in enumerate(beam_outputs):
  print(f"{i}: {tokenizer.decode(beam_output, skip_special_tokens=True)}")

        虽然 Beam Search 能够生成更连贯的文本,但在开放式生成任务中,它的表现往往不如其他解码方法。

采样(Sampling)

        采样策略不再像贪婪搜索或束搜索那样总是选择概率最高的词语,而是从词汇表中根据每个词的概率随机选取下一个词。采样的多样性较高,但可能会生成不连贯的句子。

import torch

torch.manual_seed(0)

# 激活采样,关闭 Top-K 采样
sample_output = model.generate(
    input_ids, 
    do_sample=True, 
    max_length=50, 
    top_k=0
)

print("输出:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))

        由于采样的随机性,生成的文本可能会包含一些不连贯或不自然的句子。我们可以通过调整 temperature 参数来让生成更加连贯。

# 使用 temperature 减少不合理单词的生成
sample_output = model.generate(
    input_ids, 
    do_sample=True, 
    max_length=50, 
    top_k=0, 
    temperature=0.7
)

print("输出:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))

Top-K 采样

        Top-K 采样是采样的改进版,它限制每次采样只从 K 个概率最高的单词中选择,能够有效避免生成一些低概率的单词。

# 设置 top_k 为 50
sample_output = model.generate(
    input_ids, 
    do_sample=True, 
    max_length=50, 
    top_k=50
)

print("输出:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))

Top-p 采样(核采样)

        Top-p 采样根据概率阈值 p 选择最小数量的词汇,使其累积概率超过 p,然后在这些词中进行采样。这种动态的选择方法更具弹性,能够适应不同的词汇分布。

# 设置 top_p 为 0.92
sample_output = model.generate(
    input_ids, 
    do_sample=True, 
    max_length=50, 
    top_p=0.92, 
    top_k=0
)

print("输出:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))

        最后,我们还可以结合 Top-K 和 Top-p 采样,生成多个候选序列。

# 结合 top_k 和 top_p 并生成多个候选序列
sample_outputs = model.generate(
    input_ids,
    do_sample=True, 
    max_length=50, 
    top_k=50, 
    top_p=0.95, 
    num_return_sequences=3
)

print("输出:\n" + 100 * '-')
for i, sample_output in enumerate(sample_outputs):
  print(f"{i}: {tokenizer.decode(sample_output, skip_special_tokens=True)}")

结语

        通过这篇文章,我们深入了解了 Huggingface 提供的各种解码策略。从最简单的贪婪搜索到更为复杂的 Top-K 和 Top-p 采样,每种方法在不同的场景下都有其独特的优势。贪婪搜索和束搜索在生成固定长度输出的任务中表现较好,而 Top-p 和 Top-K 采样在开放式生成任务(如对话和故事生成)中更具表现力。根据具体应用场景选择合适的解码策略,能够显著提升文本生成的质量。

如果你觉得这篇博文对你有帮助,请点赞、收藏、关注我,并且可以打赏支持我!

欢迎关注我的后续博文,我将分享更多关于人工智能、自然语言处理和计算机视觉的精彩内容。

谢谢大家的支持!


http://www.kler.cn/news/360949.html

相关文章:

  • 标准/开源版本,长连接无法启动
  • HTTP协议讲解
  • vue3 的高频插件
  • 15分钟学Go 第8天:控制结构 - 循环
  • python-docx -- 对比两个表格的行数据
  • 一文详解“位运算“在算法中的应用
  • Leetcode 括号生成
  • IP协议相关技术
  • FPGA的发展前景如何,这个行业到底是怎么样的,让你一篇文章了解大概!!!
  • 【其他】无法启动phptudy服务,提示错误2:系统找不到指定的文件
  • SVN 小乌龟 下载地址
  • C++ 进阶:类相关特性的深入探讨
  • 面试题:Redis(七)
  • 群控系统服务端开发模式-开发前总结
  • 鸿蒙应用开发:全面认识鸿蒙系统
  • Redis 基础
  • 【Unity】什么是定点数?定点数的实现原理(个人复习笔记/侵删/不足之处欢迎斧正)
  • C++编程语言:抽象机制:特殊运算符(Bjarne Stroustrup)
  • 鸿蒙--应用首次启动
  • Idea插件-arthas idea