在这个项目中,我训练了一个变压器模型来生成短笑话。然后,通过对推理方法进行轻微修改,我能够使用相同的模型,以便给定初始字符串作为输入,模型尝试以幽默的方式完成它。
有两个笔记本都执行相同的任务。
笑话生成结果
句子完成结果
结果
对于我们的任务,我们将使用 Kaggle 上提供的数据集。它是一个 csv,包含超过 200000 个从 Reddit 上删除的短笑话。
注意:由于该数据集只是从各个 Reddit 子版块中删除的,因此数据集中的大量笑话相当种族主义和性别歧视。由于任何人工智能都将其训练数据视为单一知识来源,因此应该预期我们的模型有时会产生类似的笑话。
一旦我们标记了我们的笑话字符串,我们就在标记化列表的末尾添加一个start_token
和一个end_token
。此外,由于我们的笑话字符串可能具有不同的长度,我们还在所有字符串中应用填充到指定的max_length
以便所有批次中的所有张量具有相似的形状。
相关代码可以在笔记本Joke Generation.ipynb
中找到。在此,我们将从 HuggingFace 库导入 GPT2Tokenizer 和 TFGPT2LMHead 模型。代码是用Tensorflow2编写的。笔记本上有注释,在适当的位置提供了代码的解释。此外,HuggingFace 文档还提供了关于模型的输入参数和返回值的良好文档。对于基于 PyTorch 的实现,请参阅 Tanul Singh 的 Humour.ai 存储库
相关代码可以在笔记本Joke_Completion_Pure_TF2_Implementation.ipynb
中找到。为了更深入地了解项目的工作原理,我尝试在没有外部库的情况下构建一个变压器。我参考了 Tensorflow 提供的 Transformers 教程,并将他们教程中提到的一些解释放在我的笔记本中,并进行了进一步的解释,以便很容易理解发生了什么。
我首先为我们的数据集构建了一个分词器,并使用它对字符串进行分词。然后,为Positional Encodings
和MultiHeadAttention
构建一个层。此外,我还使用Lambda layer
为我们的数据创建合适的掩码。
然后我创建了为我们的解码器构建单个decoder layer
方法。以下是单个解码器层的架构。
对于最终的transformer
模型,它获取输入标记,将其传递到 lamda 层以获取掩码,并将掩码和标记传递到我们的语言解码器,然后将其输出传递到密集层。以下是我们最终模型的架构。