621. LLM 20 Questions | llm-20-questions
首先,感谢大家带来了一场有趣的比赛。尽管存在很多问题,但希望每个人都学到了东西。
我不太确定我的真实排名是多少,因为我的另一个几乎相同的 bot 在比赛的大部分时间里都卡在低谷,最终达到了 749 的 Elo 分数。这个 bot 除了多了一个问题外完全相同:"关键词是单个词吗?"。根据游戏历史记录,这个问题并不是很有帮助,不过看回放时 bot 的表现似乎并没有差太多。
尽管如此,我还是决定在比赛结束后 finally 贡献并发布我的解决方案。我一直从别人的总结文章中学到很多,所以希望有人会觉得这篇有用。
我认为参加任何比赛时设定学习目标相当重要。这样,即使比赛存在问题(黑客攻击、指标糟糕、评分不公平等)或现实生活中的义务阻止你投入足够的时间来获得好的排名,你也能从参加比赛中受益。这种学习心态让我的 Kaggle 体验变得更加愉快,因为你不再担心排名。
对于这次比赛,我想获得更多使用 LLM 的实践经验,因为我之前还没有像我希望的那样过多地摆弄它们。我开始时的具体目标是:
我认为我在比赛期间很好地实现了这些目标。
你可以在以下仓库中找到我的代码:
https://github.com/JoonasMaanonen/kaggle-llm-20-questions
我主要在本地和 Google 云实例上工作以获取 GPU 访问权限。就个人而言,在 Kaggle 内核内部工作感觉有点慢,因为我没有编辑器、git 或 vim 绑定。根据比赛的不同,我有时仍然会使用 Kaggle 内核。
我的回答者 bot 使用了 基础指令微调版的 LLama 3。我一开始使用的是能找到的最小模型 (Phi-3),因为我的第一个目标只是得到一个可提交的版本并学习 outlines 库。基于快速研究和浏览其他内核,我很快切换到了 Llama3。
我只对回答者做了提示工程,效果相当好。起初我尝试了几-shot 提示,但没有发现一致性。这让我相信,微调可能不是我在本次比赛中时间的最佳用途,因为其中涉及大量工作,而我的时间有限。
真正提高我回答者一致性的是使用思维链(Chain of Thought)提示。基本上,就是告诉模型 "一步步思考"。在使用思维链提示之前,即使是最简单的断言,模型也难以保持一致。然而,在让思维链起作用后,它非常一致地通过了 90% 的断言。
我认为这里最大的收获是创建快速评估套件来评估模型质量的好处。我只使用了 pytest 并创建了许多这样的测试用例:
assert (
self.model(get_observation("手电筒", questions=["这个东西是电子制品吗?"]))
== "yes"
)
这种方法允许我快速迭代提示,并即时评估更改的影响,而无需运行完整的游戏。我用这种方法相当成功地开发了猜测者和回答者的提示。然而,用这种方法评估提问者质量并不 trivial,所以在那里我更多地依赖于实际游戏播放和直观检查。
最初,我的大多数猜测测试都是基于地点类别,因为这些更容易构建。不幸的是,在地点类别被移除后,我不得不废弃这些测试。
这些 bot 也使用了与回答者相同的 LLama 3 模型。我也尝试了 Llama3.1,但感觉性能差不多甚至略差,所以我决定放弃它以保持简单。
我从纯 LLM 开始,几乎使用了上述所有基本提示技术。在检查了大量游戏后,我觉得模型在确定了物品的大致类别后,擅长找出关键词。然而,达到这个大致类别的路径通常效率很低,模型有时会问信息增益非常少的问题。我还觉得模型有时更多地遵循游戏历史而不是提示中的指令,尤其是当游戏历史变大时。
所有这些都让我得出结论,拥有高质量的游戏历史对于好的猜测和提问至关重要。我想到的第一个低 effort 想法是固定前 5-10 个问题和猜测,使用我认为模型应该问的问题类型。所以我决定试试那个。
我通过制作问题和猜测树固定了前 ~5-10 个游戏回合。起初我尝试了一点基本的 if else,但代码很快变得难以控制。这就是我决定构建一个数据结构入门课中的基本树的地方。
该方法的基本思想是根据答案递归遍历问题/猜测树,直到我们 hit 一个空节点。到达空节点后,LLM 从那里继续,它应该有一个坚实的游戏历史开始。以下是树看起来的样子的一小段代码片段:
question_tree_root = Node(
question="它是生物吗?",
yes_branch=living_things,
no_branch=Node(
question="它是一种食物或饮料吗?",
yes_branch=edible_things,
no_branch=basic_man_made_object,
guess="凿子",
),
guess="电锯",
)
我基于基本直觉构建了树,并根据自玩和游戏回放中观察到的失败案例添加了更多节点。
这种树的方法使得最终的 LLM 猜测和提问更加一致,因为游戏历史总是以一组合理的问题和猜测开始。我知道人们曾使用 RAG 为提示生成动态 few shot 示例并取得成功,所以我想这有点像那个想法的回声,但没有 RAG 部分。
此外,树生成了一些“免费”胜利,即只需遍历树而无需调用 LLM 即可实现正确猜测。我试图保持问题清晰简单,即使对于较差的回答者也能理解。我还从生物和食物开始构建树,那里的好问题相当直接。我觉得各种人造物品即使对于人类 bot 来说也很难确定。这就是为什么我试图专注于更快地赢得较简单的类别。
总的来说,我很高兴参加了这次比赛。不幸的是,排名可能不能准确反映 bot 的真实技能顺序,比赛期间的所有变化都很烦人。然而,作为竞争者,这是我们控制有限的事情。最后,我玩得很开心,学到了很多。
致以亲切的问候
Joonas