我已经使用LSTM模型创建了一个词级文本生成器。但在我的情况下,并非每个词都适合被选中。我希望它们能满足额外的条件:
- 每个词都有一个映射:如果一个字符是元音,则会写1,如果不是,则会写0(例如,overflow 将是
10100010
)。然后,生成的句子需要满足给定的结构,例如,01001100
(hi01
和 friend001100
)。 - 最后一个词的最后一个元音必须是指定的元音。假设是 e(那么 friend 就符合要求)。
因此,为了处理这种情况,我创建了一个具有以下结构的pandas数据框:
word last_vowel word_map----- --------- ----------hello o 01001stack a 00100jhon o 0010
这是我当前的工作流程:
- 根据句子结构,从数据框中选择一个与模式匹配的随机词。例如,如果句子结构是
0100100100100
,我们可以选择词 hello,因为它的元音结构是01001
。 - 从剩余结构中减去选中的词:
0100100100100
将变为00100100
,因为我们已经移除了开头的01001
(hello)。 - 从数据框中检索所有与剩余结构部分匹配的词,在这种情况下,stack
00100
和 jhon0010
。 - 将当前词句内容(目前只是 hello)传递给LSTM模型,它会检索每个词的权重。
- 但我不只是想选择最佳选项,我希望在第3点的选择中选择最佳选项。因此,我在该列表中选择估计值最高的词,在这种情况下是 stack。
- 从第2点重复操作,直到剩余的句子结构为空。
这个方法非常有效,但还有一个剩余的条件需要处理:句子的最后一个元音。
我处理这个问题的办法如下:
- 生成1000个句子,强制要求最后一个元音是指定的元音。
- 获取LSTM模型返回的权重的均方根误差。输出越好,权重就越高。
- 选择获取最高排名的句子。
你认为有更好的方法吗?也许是GAN或强化学习?
编辑:我认为另一种方法是添加WFST。我听说过pynini库,但我不知道如何将其应用到我的特定环境中。
回答:
如果你对你的方法感到满意,最简单的办法可能是你能够训练你的LSTM来处理反向序列,以便训练它给出前一个词的权重,而不是下一个词。在这种情况下,你可以使用你已经采用的方法,只是第一个子集的词将满足最后一个元音的约束。我不认为这能保证产生最佳结果。
现在,如果这种反转是不可能的,或者在阅读我的回答后,你发现这并不能找到最佳解决方案,那么我建议使用一种路径查找算法,类似于强化学习,但不像训练LSTM计算的权重那样是统计性的。你目前使用的是一种深度优先贪婪搜索,根据LSTM的输出,这可能甚至是最优的。假设LSTM给你保证单调增加的总和,并且在可接受的后续词之间变化不大(因为N-1和N序列之间的差异远大于第N个词的不同选项之间的差异)。在一般情况下,当没有明确的启发式方法来帮助你时,你将不得不进行详尽的搜索。如果你能提出一个可接受的启发式方法,你可以使用A*代替Dijkstra算法,在第一种选项中,它将根据你的启发式方法的优劣来加速搜索。
我认为这很清楚,但以防万一,你的图连通性是由你的约束序列定义的。初始节点(无词的0长度序列)与数据框中任何与约束序列开头匹配的词相连。所以你没有图作为数据结构,只是它的压缩描述作为这个约束。
编辑根据评论中的请求,这里提供了一些额外的细节。以下是几个选项:
-
多次应用Dijkstra算法。Dijkstra的搜索找到两个已知节点之间的最短路径,而在你的情况下,我们只有初始节点(无词的0长度序列),最终词是未知的。
- 找出所有可接受的最后一个词(那些同时满足模式和元音约束的词)。
- 对每一个这样的词应用Dijkstra搜索,找出每个词的最大词序列权重和。
- Dijkstra算法是为寻找最短路径而设计的,因此要直接应用它,你需要在每一步否定权重,并选择那些尚未访问的权重中最小的一个。
- 在找到所有解决方案(以你最初识别的那些最后一个词结尾的句子)后,选择最小的解决方案(这将是所有解决方案中最大的权重和)。
-
修改你现有的深度优先搜索以进行详尽搜索。
- 按照你在原始帖子里描述的那样进行搜索操作,如果最后一步给出一个解决方案(如果最后一个词的正确元音可用),记录权重。
- 回滚一步到前一个词,并在前一个词中选择第二好的选项。如果前一步没有解决方案,你可能能够丢弃所有相同长度的词。如果有解决方案,这取决于你的LSTM是否根据前一个词提供不同的权重。很可能它会这样做,在这种情况下,你必须对前一步的所有词执行该操作。
- 当你用完前一步的词时,向上移动一步,并从那里重新开始向下搜索。
- 你始终保持当前的赢家以及每一步未访问节点的列表,并进行详尽搜索。最终,你将找到最佳解决方案。