首页 > 解决方案 > spaCy在自定义组件中添加指向另一个令牌的指针

问题描述

我试图找出 token.head 和 token.children 是如何实现的。我想复制这个实现,因为我将一个自定义组件添加到我的 SRL 的 spaCy 管道。

也就是说,每个标记都可以指向它作为参数的谓词。直觉上,我认为这应该有点像 token.children ,其中(我认为)它返回实际依赖的子令牌对象的生成器。

我认为我不应该简单地存储该令牌的属性,因为这似乎不是非常有效的内存并且相当冗余。有谁知道实现这一点的正确方法?或者这是由 spaCy Underscore.set 方法隐式处理的?

谢谢!

标签: pointerstokenspacy

解决方案


Token对象只是一个视图——它有点像持有对对象的引用和Doc对令牌的索引。Span 对象也是这样。这样可以确保只有一个事实来源,并且只有一个数据副本。

您可以在spacy/structs.pxd文件中找到关键结构的定义。这定义了TokenC结构的属性。然后该Doc对象保存一个数组和一个长度。当Token您索引到Doc. Doc对象的数据定义在 中spacy/tokens/doc.pxd,令牌访问的实现在 中spacy/tokens/doc.pyx

解析树在 spaCy 中的编码方式有点不令人满意。我在追踪器上提出了一个问题——感觉应该有更好的解决方案。

我们所做的是编码头部相对于令牌的偏移量。所以如果你这样做&doc.c[i] + doc.c[i].head,你会得到一个指向头部的指针。那部分没问题。有点奇怪的部分是我们跟踪令牌子树的左右边缘,以及直接左右子节点的数量。为了得到最右边或最左边的孩子,我们在这个区域内导航。在实践中,这实际上工作得很好,因为我们正在处理一个连续的内存块,并且 Cython 中的循环很快。但它仍然感觉有点笨拙。

至于您作为用户能够做什么......如果您运行自己的 spaCy 分支,您可以愉快地在结构上定义自己的数据。但是你正在运行你自己的分叉。

无法将“真实”属性附加到DocorToken对象,因为它们被定义为 C 级类型 --- 因此它们的结构是静态定义的;它不是动态的。您可以对 the 进行子类化,Doc但这很丑陋:您还需要子类化。

这就是为什么我们有下划线属性和doc.user_data字典的原因。这确实是扩展对象的唯一方法。幸运的是,您不应该真正面临数据冗余问题。对象上没有存储任何内容Token。扩展的定义全局存储在Underscore类中。数据存储在Doc对象上,即使它适用于令牌 --- 同样,这Token是一个视图。它不能拥有任何东西。所以Doc必须注意我们为 token 分配了一些值i

如果您要定义树导航系统,我建议您考虑将其定义为您自己的 Cython 类,以便您可以使用结构。如果您使用本机 Python 类型,它将非常缓慢且非常大。如果将数据打包成 numpy 数组,表示会更紧凑,但编写代码将是一种相当痛苦的体验,而且性能可能不会很好。

简而言之:

  • 在 Cython 中定义您自己的类型。将数据放入 cdef 类拥有的结构中,并为类提供访问器方法。

  • 使用下划线属性访问来自 spaCy 的 Doc、Span 和 Token 对象的数据。

  • 如果您为 SRL 提供了一个引人注目的 API,并且可以将数据紧凑地编码到TokenC结构中,我们会考虑将其添加为原生支持。


推荐阅读