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" 属性附加到 Doc
或 Token
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
结构中,我们会考虑将其添加为本机支持。
我正在尝试查找 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" 属性附加到 Doc
或 Token
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
结构中,我们会考虑将其添加为本机支持。