我正在为范围连接语法编写一个CKY解析器。我想用树库作为语法,这样语法会很大。我用Python编写了一个原型1,当我模拟一个由几十个句子组成的树库时,它似乎可以很好地工作,但是内存的使用是不可接受的。我试着用C++编写,但到目前为止,我一直没有用C++,这是非常令人沮丧的。以下是一些数据(n是语法基于的句子数):
n mem
9 173M
18 486M
36 836M
这种增长模式是最好的优先算法所期望的,但是开销的大小是我关心的。根据heapy的数据,内存使用量比这些数字小10倍,valgrind报告了类似的情况。是什么导致了这种差异?我能用Python(或Cython)对此做些什么吗?也许是因为碎片化?或者是python字典的开销?在
背景知识:两种重要的数据结构是将边缘映射到概率的议程和将非终结点和位置映射到边缘的字典图表。这个议程是用heapdict(内部使用dict和heapq列表)实现的,这个图表有一个字典,将非终端和位置映射到边缘。议程经常被插入和删除,图表只得到插入和查找。我用这样的元组表示边:
^{pr2}$字符串是语法中的非终结符标签,位置被编码为位掩码。当一个成分不连续时,可能有多个位置。所以这个边可以代表对“is Mary happy”的分析,其中“is”和“happy”都属于VP。在本例中,图表字典按此边的第一个元素(“S”,111)编制索引。在一个新版本中,我尝试将此表示转换为可重用的内存:
(("S", "NP", "VP), (111, 100, 011))
我认为,如果第一部分与不同的位置结合使用,Python只会存储一次,尽管我不确定这是否正确。不管是哪种情况,似乎都没什么区别。在
基本上我想知道的是,是否值得进一步追问我的Python实现,包括用Cython和不同的数据结构来做事情,或者从C++中直接编写它是唯一可行的选择。在更新:经过一些改进,我不再有内存使用问题。我正在研究一个优化的Cython版本。对于提高代码效率的最有用的建议,我将给予奖励。在http://student.science.uva.nl/~acranenb/plcfrs_cython.html处有一个带注释的版本
1https://github.com/andreasvc/disco-dop/ --跑测试.py分析一些句子。需要Python2.6、nltk和heapdict
不一定:
您可能需要^{} 所有引用非终结符的字符串,因为您似乎在
^{pr2}$rcgrules.py
中创建了许多这样的字符串。如果您想intern
一个元组,那么首先将其转换为字符串:否则,您将不得不“复制”元组,而不是重新构造它们。在
(如果你是C++新手,那么改写这样的算法不太可能带来很多记忆上的好处。您必须首先评估各种哈希表实现,并了解其容器中的复制行为。我发现
boost::unordered_map
使用大量的小哈希表非常浪费。)在这些情况下,首先要做的是概述:
我注意到的第一件事是很少有函数来自cython模块本身。 他们大多来自树.py模块,也许这就是瓶颈。在
集中在cython方面,我看到了richcmp函数:
我们可以通过在方法声明中添加值的类型来优化它
^{pr2}$这就降低了价值
添加elif语法而不是单个if将启用the switch optimization of cython
获得:
想弄清楚在哪里树。py:399转换来自我发现这个函数里面兴奋剂花了那么多时间
现在我不确定树中的每个节点是否都是ChartItem,以及getitem值 正在其他地方使用,但添加了以下更改:
以及最具潜力的Parse内部:
我得到:
因此,下一步是优化heapify并从
推导公式可以进一步优化:
我将到此为止,尽管我有信心随着对问题的深入了解,我们可以继续优化。在
一系列的unittest将有助于断言每个优化不会引入任何细微的错误。在
注意,尽量用空格代替制表符。在
你试过用PyPy而不是CPython来运行应用程序吗?在
PyPy比CPython聪明得多,在注意到共性和避免与不必要的复制相关的内存开销方面。在
无论如何值得一试:http://pypy.org/
相关问题 更多 >
编程相关推荐