spaCy 在自定义组件中添加指向另一个标记的指针

spaCy adding pointer to another token in custom component

我正在尝试查找 token.head 和 token.children 是如何实现的。我想复制此实现,因为我将自定义组件添加到 SRL 的 spaCy 管道中。

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

我假设我不应该简单地存储该令牌的属性,因为这似乎不是非常有效的内存而且相当多余。有谁知道实现这个的正确方法?还是由 spaCy Underscore.set 方法隐式处理?

谢谢!

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

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

解析树在 spaCy 中的编码方式有点不尽如人意。我已经在追踪器上提出了这个问题---感觉应该有更好的解决方案。

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

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

无法将 "real" 属性附加到 DocToken object,因为它们被定义为 C-level 类型 ---所以它们的结构是静态定义的;它不是动态的。你可以 subclass the Doc 但这很丑陋:你还需要 subclass.

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

分配了一些值

如果您正在定义一个 tree-navigation 系统,我建议考虑将其定义为您自己的 Cython class,这样您就可以使用结构。如果您使用本机 Python 类型,它将非常慢并且非常大。如果将数据打包到numpy数组中表示会更紧凑,但是写代码会很痛苦,而且性能可能不会很好。

简而言之:

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

  • 使用下划线属性访问spaCy的Doc、Span和Token中的数据objects.

  • 如果您为 SRL 提出了一个令人信服的 API 并且数据可以紧凑地编码到 TokenC 结构中,我们会考虑将其添加为本机支持。