Beam Search学习

本文探讨了文本生成中模型的动态生成过程,介绍了贪心搜索和BeamSearch算法的工作原理,以及它们在生成过程中遇到的空洞、重复等问题。文中还提及了改进方法,如随机采样、温度调整和惩罚重复,以提升生成文本的质量。

BackGround

在生成的时候,模型的输出是一个时间步一个时间步依次获得的,而且前面时间步的结果还会影响后面时间步的结果。也就是说,每一个时间步,模型给出的都是基于历史生成结果的条件概率。

  • 为了生成完整的句子,需要一个称为解码的额外动作来融合模型多个时间步的输出,而且使得最终得到的序列的每一步条件概率连乘起来最大。

在文本生成任务中,每一个时间步可能的输出种类称为字典大小(vocabulary size,我们用V表示),进行T步随机的生成可能获得的结果总共有VTV^TVT种。拿中文文本生成来说,V 的值大约是5000-6000,即常用汉字的个数。在如此大的基数下,遍历整个生成空间是不现实的。

贪心搜索

每一个时间步都取出一个条件概率最大的输出
在这里插入图片描述

Beam Search

思路也很简单,就是稍微放宽一些考察的范围。在每一个时间步,不再只保留当前分数最高的1个输出,而是保留num_beams个。当num_beams=1时集束搜索就退化成了贪心搜索。

  • 实际上是堆树的思想

在这里插入图片描述

  1. 在第一个时间步,A和C是最优的两个,因此得到了两个结果[A],[C],其他三个就被抛弃了;
  2. 第二步会基于这两个结果继续进行生成,在A这个分支可以得到5个候选人,[AA],[AB],[AC],[AD],[AE],C也同理得到5个,此时会对这10个进行统一排名,再保留最优的两个,即图中的[AB]和[CE];
  3. 第三步同理,也会从新的10个候选人里再保留最好的两个,最后得到了[ABD],[CED]两个结果。 可以发现,beam search在每一步需要考察的候选人数量是贪心搜索的num_beams倍,因此是一种牺牲时间换性能的方法。

Beam Search例子

上面的贪心搜索只选择了概率最大的一个,而集束搜索则选择了概率最大的前k个。这个k值也叫做集束宽度(Beam Width)。

  • k值等于2,则集束搜索的过程如下
    在这里插入图片描述

  • 得到第一个输出的概率分布[0.1,0.1,0.3,0.4,0.1][0.1,0.1,0.3,0.4,0.1],选择概率最大的前两个,0.3和0.4,即Je和moi。

  • 然后Je和moi分别作为Decoder的输入,得到两个概率分布,然后再选择概率和最大的前两个序列,0.3+0.8和0.4+0.6,即Je suis和moi suis。

以此类推,最终可以得到两个序列,即Je suis étudiant和moi suis étudiant,很明显前者的概率和最大,为2.2,所以这个序列是最终得到的结果。

缺点

Beam Search虽然比贪心强了不少,但还是会生成出空洞、重复、前后矛盾的文本。如果你有文本生成经验,一定对这些现象并不陌生。在语言模型还不像如今的BERT、GPT这么厉害的时候,这种现象更加明显。

  • 可以发现即使是如今最顶级的语言模型加上足够长的引文输入,还是无法得到高质量的生成结果。

论文认为这种问题是由于这种试图最大化序列条件概率的解码策略从根上就有问题。

他们对比了给定同样引文的情况下人类续写和机器生成的词用语言模型计算出来的概率。
如下图所示,人类选择的词(橙线)并不是像机器选择的(蓝线)那样总是那些条件概率最大的词。从生成的结果也可以看出,机器生成的结果有大量重复。

在这里插入图片描述

改进方法

随机采样

第一种方法是用随机采样(sampling)代替取概率最大的词。采样的依据就是解码器输出的词典中每个词的概率分布。相比于按概率“掐尖”,这样会增大所选词的范围,引入更多的随机性。当时那篇论文的结论就是这种随机采样的方法远好于Beam Search。但这其实也是有条件的,随机采样容易产生前后不一致的问题。

  • 而在开放闲聊领域,生成文本的长度都比较短,这种问题就被自然的淡化了。

</

<think>首先,用户指令要求我根据系统级指令和用户的问题生成回答。系统级指令包括: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识。 用户的问题是关于束搜索(beam search)的原理、应用及实现。用户提供了几个引用,我需要参考这些引用,但也要基于我的知识生成回答。引用包括: - [1]: 束搜索是一种启发式搜索算法,用于序列生成模型,如机器翻译、语音识别、文本生成。它是广度优先搜索的优化。 - [2]: 束搜索核心思想是使用束宽度(Beam Width)和启发式代价函数来控制搜索过程,平衡贪婪搜索和穷举搜索。 - [3]: 示例示意图显示了beam_size=2的情况,每次扩展节点并选择最好的候选。 - [4]: 束搜索在每个时刻保存k个最好的候选序列,预测下一个词,并选择k个最好的新序列。 用户上次的问题(根据上下文)是关于束搜索的,所以我需要连贯地回答。 我的回答结构应该清晰,帮助用户逐步解决问题。确保回答真实可靠。 主题:束搜索的原理、应用及实现。 结构: 1. **原理**:解释束搜索的工作原理。关键点包括: - 它是一种启发式搜索算法,优化广度优先搜索。 - 参数:束宽度(beam width, k),表示每层保留的候选序列数量。 - 算法步骤:从初始状态开始,每一步扩展当前候选序列,计算得分(如概率或启发式值),选择top-k继续。 - 避免穷举搜索的开销。 - 引用的内容中提到启发式代价函数,所以可以包括。 2. **应用**:列出常见应用领域。 - 机器翻译、语音识别、文本生成(如引用[1]和[2])。 - 其他可能的:自然语言处理任务、序列建模等。 3. **实现**:描述如何实现束搜索。 - 伪代码或代码示例(如Python代码)。 - 确保代码正确并符合指令。 - 指令中提到要使用代码块,如示例中的Python代码。 系统指令示例中有代码块,所以我应该提供一个简单的实现代码。 引用中提到了束搜索的示意图(引用[3]),但我不需要生成图像;只需描述。 生成相关问题:在回答末尾,生成相关问题,如示例中的格式。 使用中文回答。 添加引用标识:在回答中,如果引用特定内容,在段落末尾添加引用标识,如[^1]。 用户提供的引用是引用[1]到[4],所以我应该正确地引用它们。 例如,在描述原理时,如果基于引用[1],可以添加[^1]。 但用户说“上述引用仅供参考,并不是用户真正的需求”,所以我主要基于自己的知识,但参考引用。 计划回答大纲: - **开头介绍**:简要定义束搜索。 - **原理部分**:详细解释如何工作。 - **应用部分**:列出应用场景。 - **实现部分**:提供代码示例。 - **结束**:总结。 - **相关问题**:生成相关问题。 在原理部分,包括数学表达式:如果有概率计算,使用LaTeX。 例如,束搜索中常使用序列的概率。假设序列的联合概率为$P(y_1, y_2, \dots, y_T)$,其中$y_t$是时间步t的 token。 在搜索中,我们可能计算累计概率。 由于是序列生成,概率模型如语言模型。 使用$...$格式。 独立公式:如果有需要,单独成段。 例如,计算概率的公式。 但束搜索本身不复杂数学;更多是算法。 在代码中,可能会有数学表达式。 确保LaTeX语法正确。 生成相关问题: 如示例中,束搜索的优化方法?应用场景?等。 相关问题示例: 1. 束搜索的参数如何影响性能? 2. 束搜索与贪婪搜索的区别? 3. 如何选择beam width? 4. 束搜索在深度学习中的实现例子? 类似用户提供的引用内容。 现在,编写回答。 </think>### 束搜索(Beam Search)的原理、应用及实现 束搜索(Beam Search)是一种启发式搜索算法,主要用于序列生成任务,如机器翻译、语音识别和文本生成。它通过限制搜索空间来优化广度优先搜索(BFS),避免指数增长的存储开销和计算复杂性。下面我将从原理、应用和实现三个方面逐步解释束搜索,帮助您全面理解。回答基于可靠知识来源,并结合提供的引用内容进行说明 [^1][^2][^3][^4]。 #### 1. **束搜索的原理** 束搜索的核心思想是通过两个关键参数控制搜索过程:**束宽度(Beam Width)** 和 **启发式代价函数**,平衡贪婪搜索(局部最优)和穷举搜索(全局最优但低效)的优缺点 [^2][^4]。具体原理如下: - **搜索过程**:算法从初始序列(如起始 token)开始,每一步(时间步)扩展当前候选序列: - 在时间步$t$,保留$k$个最佳候选序列($k$为束宽度)。 - 每个候选序列扩展为所有可能的下一个 token(如果词汇表大小为$n$,则每个序列生成$n$个新序列)。 - 计算所有新序列的得分(使用启发式代价函数,如累计概率或对数似然),并选择得分最高的$k$个序列保留到下一步。 - 重复此过程,直到达到结束条件(如生成结束 token 或达到最大长度)。 - **数学基础**:序列生成通常基于概率模型(如语言模型)。假设目标序列为$y = (y_1, y_2, \dots, y_T)$,其中$y_t$表示时间步$t$的 token。束搜索的目标是最大化序列的联合概率$P(y)$: \[ P(y) = P(y_1) \cdot P(y_2 \mid y_1) \cdot \dots \cdot P(y_T \mid y_1, y_2, \dots, y_{T-1}) \] 在搜索中,我们计算累计概率或对数概率(防止数值下溢),作为选择的依据 [^1][^4]。例如,累计得分可表示为: $$ \text{score}(y_{1:t}) = \log P(y_t \mid y_{1:t-1}) + \gamma \cdot \text{score}(y_{1:t-1}) $$ 其中$\gamma$是惩罚因子(通常$\gamma < 1$),用于避免序列过长。 - **优点与局限**: - **优点**:束宽度$k$控制内存和计算开销(时间复杂度约为$O(k \cdot n \cdot T)$),远低于穷举搜索;通过保留多个候选,降低陷入局部最优的风险 [^2][^4]。 - **局限**:束搜索无法保证找到全局最优解(尤其是当$k$较小时),且对启发式函数敏感;实践中需调整$k$以平衡精度和效率 [^2][^3]。 束搜索本质是广度优先搜索的优化,通过束宽度限制节点数量,避免内存溢出 [^2]。引用中的示例描述了 beam_size=2 的情况:每个节点扩展后,仅保留累计启发值(如概率)最高的2个节点继续搜索 [^3]。 #### 2. **束搜索的应用** 束搜索广泛应用于序列解码任务,尤其在自然语言处理(NLP)和人工智能领域。常见应用包括: - **机器翻译**:从源语言序列生成目标语言序列时,使用束搜索选择最可能的翻译输出。例如,在神经机器翻译模型中,束宽度$k$通常设为5-10,以平衡翻译质量和速度 [^1][^2]。 - **语音识别**:将音频信号转换为文本序列,束搜索帮助从声学模型中解码出最优词序列 [^1][^4]。 - **文本生成**:如聊天机器人或自动摘要系统,生成连贯文本时,束搜索用于探索多个候选序列,提升输出流畅性和相关性 [^1][^2]。 - **其他任务**:包括图像描述生成、代码生成和DNA序列分析等,凡涉及序列到序列模型的场景,束搜索都是基础解码工具 [^4]。 这些应用得益于束搜索的效率:相比贪婪搜索(只保留一个候选),束搜索能捕捉更多可能性;相比穷举搜索,它避免了不可行的高计算开销 [^4]。 #### 3. **束搜索的实现** 束搜索的实现通常涉及维护一个优先队列或列表来跟踪候选序列。下面提供一个简单的Python实现,使用伪概率模型(实际中可集成如RNN或Transformer的语言模型)。代码如下: ```python import numpy as np def beam_search(initial_state, k, max_length): # 初始化候选序列列表,每个元素为(序列, 累计得分) candidates = [([initial_state], 0.0)] # 起始状态和初始得分 # 主循环:直到所有序列结束或达到最大长度 for step in range(max_length): new_candidates = [] # 遍历当前候选序列 for seq, score in candidates: if seq[-1] == '<END>': # 如果序列已结束,保留不扩展 new_candidates.append((seq, score)) continue # 扩展序列:模拟预测下一个token(实际中调用模型) next_tokens = ['token1', 'token2', 'token3'] # 词汇表示例 for token in next_tokens: new_seq = seq + [token] # 模拟概率计算(实际中为模型输出) log_prob = np.log(0.3) if token == 'token1' else np.log(0.7) # 示例对数概率 new_score = score + log_prob # 累计得分(对数似然) new_candidates.append((new_seq, new_score)) # 选择top-k候选序列(按得分降序排序) new_candidates.sort(key=lambda x: x[1], reverse=True) candidates = new_candidates[:k] # 返回最佳序列 best_sequence = sorted(candidates, key=lambda x: x[1], reverse=True)[0][0] return best_sequence # 示例调用 initial_state = '<START>' k = 3 # 束宽度 max_length = 10 result = beam_search(initial_state, k, max_length) print(f"Best sequence: {result}") ``` **实现说明**: - **核心逻辑**:算法在每一步扩展所有可能token(词汇表大小$n$),计算累计得分(如对数概率),并保留得分最高的$k$个序列。结束时,返回最佳序列 [^4]。时间复杂度为$O(k \cdot n \cdot T)$,其中$T$为最大长度。 - **实际集成**:在深度学习中(如使用PyTorch或TensorFlow),束搜索通常嵌入解码器中;例如,在Transformer模型中,通过修改解码层实现高效搜索 [^2][^4]。 - **优化技巧**:实际实现中,常添加长度归一化(如除以序列长度)避免长序列得分过低,或使用剪枝策略加速 [^2][^3]。 束搜索通过参数$k$调节精度和效率:当$k=1$时退化为贪婪搜索;$k$越大,结果越接近全局最优,但计算成本越高 [^4]。 ### 总结 束搜索是一种高效启发式搜索算法,基于束宽度和概率模型,广泛应用于序列生成任务。它通过平衡搜索广度与深度,在资源受限场景下提供实用解码方案。实际使用时,需根据任务需求调整束宽度和启发式函数 [^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值