【问题标题】:How to fit a large words dictionary in a small space with least effect on accuracy?如何在对准确性影响最小的情况下在小空间中安装大字典?
【发布时间】:2016-05-03 18:17:36
【问题描述】:

我正在尝试使用仅允许 30kb 数据的微控制器来实现文字游戏。为此,我需要从特定的允许单词字典中查找单词,该字典在未压缩时大小接近 4 MB。

我不需要每次都给出正确答案,这样我就可以在准确性上妥协。有没有一种方法可以在 30kb 的空间中放入 4MB 的字典,同时将准确度损失降至最低

我已经按照here 的建议尝试使用优化的“trie” 数据结构,使用压缩的 trie 生成器 here 将大小从 4 MB 降低到 740 KB,但我在不丢弃大量单词的情况下,无法找到一种方法来使其更小。

“trie”总是会给我正确的答案。有没有一种通过权衡准确性来减小尺寸的方法,并制定出一个在大多数情况下可以给我正确答案的结构? 也许我可以使用机器学习模型或与之相关的东西?

我知道这几乎是不可能的。但是游戏的设计使您不需要准确的答案。即使是 25% 左右的准确度也是合理的。

我可能会省略最长的单词,直到字典适合那个大小。但在这种情况下,这可能不是最好的方法。

【问题讨论】:

  • "Arduino 的代码大小限制为 30kb" - 究竟是什么受到了这个限制?你的字典不应该嵌入到你的 Python 代码中。
  • 我同意你应该把字典放在你的数据部分
  • 取决于特定的 Arduino,他可能没有太多选择,字典必须在代码部分结束。我对他如何在 Arduino 上使用 Python 有点迷茫。这里唯一的选择可能是找到一个小得多的字典,这可能会使类似拼字游戏的游戏完全无法玩。用于工作的工具等等。
  • 我认为您可以更轻松地通过串行端口与 Arduino 通信。 Arduino 将管理拼字游戏板上的所有“控件”,但处理每个单词将在某些 PC 或 raspi 上远程完成。 python 库“serial”使通过串行端口与另一个设备通信变得非常容易。通过 Arduino 上的串口发送/接收数据就像 Serial.print()Serial.read() 一样简单。
  • @user2357112 很抱歉造成混乱。编辑了我的问题以使其更清楚。 :-)

标签: dictionary machine-learning lookup trie


【解决方案1】:

在 30kb 的空间中放入 4MB 的字典,并且准确度损失最小?

字典文件很可能是每行一个单词的格式,对吧?这是存储单词列表的一种非常有效的方法。

所以我会说,不,4MB 的数据永远不会放在 30kb 的空间中。没有压缩,没有有效存储,现在没有,永远也没有。

想一想:4MB 实际上是 30kb 限制大小的 100 倍。显然,您必须遍历字典在磁盘上,并可能缓存结果。

【讨论】:

  • 我完全同意。 4MB 的数据永远不会放在那里。但是,第一次尝试使我达到了 708 KB,这是我之前没有想到的。所以我在尝试是否可以进一步降低它。我可能会使用较小的字典。但这与减少单词相同 - 一个可行的选择,但我不确定在我的情况下是否是最佳选择。
  • 好吧,如果我是你,我会保留一个查找过的单词的缓存,然后遍历 磁盘上的文件 来查找它。你也可以使用一个小的数据库模块或其他东西。
【解决方案2】:

不幸的是,我不得不同意这里出现的共识。我写了一些类似的软件(一个拼字游戏机器人),所以我参考了我的代码并进行了一些计算。我使用的是 SOWPODS 字典,它实际上比您描述的要小得多 - 267,751 个单词,未压缩占用 2707014 个字节。

使用 trie 数据结构对于实现 AI 来玩像拼字游戏这样的游戏至关重要,不仅因为它减少了内存中字典的大小,而且因为基本结构大大降低了搜索功能的计算复杂性。当您尝试可能的排列时,您可以在碰到树中的叶子时立即停止。我提出这一点是因为如果您尝试为此使用 Arduino,则不可避免地还需要确保代码在速度方面非常高效。

但是为了使用 trie 来确保合理的性能,这也意味着您需要在节点之间建立链接,并且在 32 位架构上的简单实现中,这些链接每个将占用 4 个字节。您可能可以实现更高级的逻辑来减少节点以存储每个 2 个字节的偏移量(2^15 指向内存中的偏移量,额外的位指示该节点是否代表一个单词)。但即便如此,这意味着您需要 trie 拥有 15K 个节点(实际上更少,因为按理说您也需要一些代码。:)

我玩弄了限制单词的最大大小,看看需要什么才能将节点数量减少到足够多...坏消息,您最多只能存储最多 4 个字符的单词!这是每个最大尺寸的节点数:

15: 589315
14: 572754
13: 546969
12: 508959
11: 456252
10: 387321
9: 304186
8: 212237
7: 126700
6: 63605
5: 25776
4: 8208

因此,基本上,当您将字典的大小缩小到足够的程度时,使用更复杂的算法就不再有价值了。只是没有足够的内存让它工作。

针对使用机器学习模型的想法,我的经验是,构建一个可以达到甚至是合理精度的功能模型通常需要相当多的内存,而获得合理的性能需要中等强大的硬件,即使只有执行预测。 (培训非常昂贵,但您可以离线进行。)

根据所需的效率,即使从磁盘读取数据库也可能无法启动。缓存只能让你走这么远。

老实说,我认为@TypeKatz 的建议是最合理的。 Arduino 根本不是为这种应用程序设计的,因此最好的办法是将计算成本高、内存密集型的处理卸载到外部设备上。您可以通过串行端口使用连接的设备,或者投资购买 Wifi 防护罩并与附近的服务器通信。

无论如何,祝你好运!

【讨论】:

  • 非常感谢您的详细解答!我已经通过使用不需要解码的succinct data structure 来解决链接问题。所以我不需要重建链接,从而节省了我的全部记忆。
  • 感谢您的链接 - 非常有趣!尽管如此,我不确定这是否足以使板载处理可行。即使您将每个节点的数据压缩到每个字符 5 位,这仍然不足以容纳长度为 6 或更短的所有单词。 (63605 * 5 / 8 已经快 40kb。)这不包括编码链接或减轻不断操作单个位的性能影响所需的目录。老实说,这听起来是一个非常酷的项目,但我仍然建议制定一个涉及卸载处理的备份计划。
  • 完全同意。实际上,我把这个项目作为一个挑战,让村里的孩子们边玩边教他们英语。所以我受到整个设备成本的限制。使用 PC/Internet 是不可能的,因为几乎不存在连接性。所以,我能压缩的越多,我能得到的就越好。 :-)
  • 哦,太酷了!在这种情况下,为什么不使用针对那些学习英语的人的简化词典呢?例如Ogden's Basic English Word List。否则,您将在“disestablishmentarianism”和“myna”等很少使用的词上浪费空间。 :)
猜你喜欢
  • 2014-08-09
  • 2014-03-20
  • 1970-01-01
  • 2012-01-20
  • 1970-01-01
  • 2013-10-06
  • 2021-03-29
  • 1970-01-01
  • 2020-07-29
相关资源
最近更新 更多