From 75f7c15187ecad9be9d018810beaa546508944af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Wed, 12 Jan 2022 13:38:52 +0100 Subject: [PATCH 001/123] Span/SpanGroup: wrap SpanC in shared_ptr (#9869) * Span/SpanGroup: wrap SpanC in shared_ptr When a Span that was retrieved from a SpanGroup was modified, these changes were not reflected in the SpanGroup because the underlying SpanC struct was copied. This change applies the solution proposed by @nrodnova, to wrap SpanC in a shared_ptr. This makes a SpanGroup and Spans derived from it share the same SpanC. So, changes made through a Span are visible in the SpanGroup as well. Fixes #9556 * Test that a SpanGroup is modified through its Spans * SpanGroup.push_back: remove nogil Modifying std::vector is not thread-safe. * C++ >= 11 does not allow const T in vector * Add Span.span_c as a shorthand for Span.c.get Since this method is cdef'ed, it is only visible from Cython, so we avoid using raw pointers in Python Replace existing uses of span.c.get() to use this new method. * Fix formatting * Style fix: pointer types * SpanGroup.to_bytes: reduce number of shared_ptr::get calls * Mark SpanGroup modification test with issue Co-authored-by: Sofie Van Landeghem Co-authored-by: Sofie Van Landeghem --- spacy/pipeline/_parser_internals/ner.pyx | 28 +++--- spacy/tests/doc/test_span.py | 14 ++- spacy/tokens/span.pxd | 11 ++- spacy/tokens/span.pyx | 110 +++++++++++++---------- spacy/tokens/span_group.pxd | 5 +- spacy/tokens/span_group.pyx | 21 +++-- 6 files changed, 115 insertions(+), 74 deletions(-) diff --git a/spacy/pipeline/_parser_internals/ner.pyx b/spacy/pipeline/_parser_internals/ner.pyx index 3edeff19a..87410de0f 100644 --- a/spacy/pipeline/_parser_internals/ner.pyx +++ b/spacy/pipeline/_parser_internals/ner.pyx @@ -1,6 +1,8 @@ import os import random from libc.stdint cimport int32_t +from libcpp.memory cimport shared_ptr +from libcpp.vector cimport vector from cymem.cymem cimport Pool from collections import Counter @@ -42,9 +44,7 @@ MOVE_NAMES[OUT] = 'O' cdef struct GoldNERStateC: Transition* ner - SpanC* negs - int32_t length - int32_t nr_neg + vector[shared_ptr[SpanC]] negs cdef class BiluoGold: @@ -77,8 +77,6 @@ cdef GoldNERStateC create_gold_state( negs = [] assert example.x.length > 0 gs.ner = mem.alloc(example.x.length, sizeof(Transition)) - gs.negs = mem.alloc(len(negs), sizeof(SpanC)) - gs.nr_neg = len(negs) ner_ents, ner_tags = example.get_aligned_ents_and_ner() for i, ner_tag in enumerate(ner_tags): gs.ner[i] = moves.lookup_transition(ner_tag) @@ -92,8 +90,8 @@ cdef GoldNERStateC create_gold_state( # In order to handle negative samples, we need to maintain the full # (start, end, label) triple. If we break it down to the 'isnt B-LOC' # thing, we'll get blocked if there's an incorrect prefix. - for i, neg in enumerate(negs): - gs.negs[i] = neg.c + for neg in negs: + gs.negs.push_back(neg.c) return gs @@ -410,6 +408,8 @@ cdef class Begin: cdef int g_act = gold.ner[b0].move cdef attr_t g_tag = gold.ner[b0].label + cdef shared_ptr[SpanC] span + if g_act == MISSING: pass elif g_act == BEGIN: @@ -427,8 +427,8 @@ cdef class Begin: # be correct or not. However, we can at least tell whether we're # going to be opening an entity where there's only one possible # L. - for span in gold.negs[:gold.nr_neg]: - if span.label == label and span.start == b0: + for span in gold.negs: + if span.get().label == label and span.get().start == b0: cost += 1 break return cost @@ -573,8 +573,9 @@ cdef class Last: # If we have negative-example entities, integrate them into the objective, # by marking actions that close an entity that we know is incorrect # as costly. - for span in gold.negs[:gold.nr_neg]: - if span.label == label and (span.end-1) == b0 and span.start == ent_start: + cdef shared_ptr[SpanC] span + for span in gold.negs: + if span.get().label == label and (span.get().end-1) == b0 and span.get().start == ent_start: cost += 1 break return cost @@ -638,8 +639,9 @@ cdef class Unit: # This is fairly straight-forward for U- entities, as we have a single # action cdef int b0 = s.B(0) - for span in gold.negs[:gold.nr_neg]: - if span.label == label and span.start == b0 and span.end == (b0+1): + cdef shared_ptr[SpanC] span + for span in gold.negs: + if span.get().label == label and span.get().start == b0 and span.get().end == (b0+1): cost += 1 break return cost diff --git a/spacy/tests/doc/test_span.py b/spacy/tests/doc/test_span.py index 10aba5b94..0e7730b65 100644 --- a/spacy/tests/doc/test_span.py +++ b/spacy/tests/doc/test_span.py @@ -4,7 +4,7 @@ from numpy.testing import assert_array_equal from spacy.attrs import ORTH, LENGTH from spacy.lang.en import English -from spacy.tokens import Doc, Span, Token +from spacy.tokens import Doc, Span, SpanGroup, Token from spacy.vocab import Vocab from spacy.util import filter_spans from thinc.api import get_current_ops @@ -163,6 +163,18 @@ def test_char_span(doc, i_sent, i, j, text): assert span.text == text +@pytest.mark.issue(9556) +def test_modify_span_group(doc): + group = SpanGroup(doc, spans=doc.ents) + for span in group: + span.start = 0 + span.label = doc.vocab.strings["TEST"] + + # Span changes must be reflected in the span group + assert group[0].start == 0 + assert group[0].label == doc.vocab.strings["TEST"] + + def test_spans_sent_spans(doc): sents = list(doc.sents) assert sents[0].start == 0 diff --git a/spacy/tokens/span.pxd b/spacy/tokens/span.pxd index 78bee0a8c..85553068e 100644 --- a/spacy/tokens/span.pxd +++ b/spacy/tokens/span.pxd @@ -1,3 +1,4 @@ +from libcpp.memory cimport shared_ptr cimport numpy as np from .doc cimport Doc @@ -7,19 +8,21 @@ from ..structs cimport SpanC cdef class Span: cdef readonly Doc doc - cdef SpanC c + cdef shared_ptr[SpanC] c cdef public _vector cdef public _vector_norm @staticmethod - cdef inline Span cinit(Doc doc, SpanC span): + cdef inline Span cinit(Doc doc, const shared_ptr[SpanC] &span): cdef Span self = Span.__new__( Span, doc, - start=span.start, - end=span.end + start=span.get().start, + end=span.get().end ) self.c = span return self cpdef np.ndarray to_array(self, object features) + + cdef SpanC* span_c(self) diff --git a/spacy/tokens/span.pyx b/spacy/tokens/span.pyx index cd02cab36..c8fb0d1a2 100644 --- a/spacy/tokens/span.pyx +++ b/spacy/tokens/span.pyx @@ -1,5 +1,6 @@ cimport numpy as np from libc.math cimport sqrt +from libcpp.memory cimport make_shared import numpy from thinc.api import get_array_module @@ -109,14 +110,14 @@ cdef class Span: end_char = start_char else: end_char = doc[end - 1].idx + len(doc[end - 1]) - self.c = SpanC( + self.c = make_shared[SpanC](SpanC( label=label, kb_id=kb_id, start=start, end=end, start_char=start_char, end_char=end_char, - ) + )) self._vector = vector self._vector_norm = vector_norm @@ -126,41 +127,46 @@ cdef class Span: return False else: return True + + cdef SpanC* span_c = self.span_c() + cdef SpanC* other_span_c = other.span_c() + # < if op == 0: - return self.c.start_char < other.c.start_char + return span_c.start_char < other_span_c.start_char # <= elif op == 1: - return self.c.start_char <= other.c.start_char + return span_c.start_char <= other_span_c.start_char # == elif op == 2: # Do the cheap comparisons first return ( - (self.c.start_char == other.c.start_char) and \ - (self.c.end_char == other.c.end_char) and \ - (self.c.label == other.c.label) and \ - (self.c.kb_id == other.c.kb_id) and \ + (span_c.start_char == other_span_c.start_char) and \ + (span_c.end_char == other_span_c.end_char) and \ + (span_c.label == other_span_c.label) and \ + (span_c.kb_id == other_span_c.kb_id) and \ (self.doc == other.doc) ) # != elif op == 3: # Do the cheap comparisons first return not ( - (self.c.start_char == other.c.start_char) and \ - (self.c.end_char == other.c.end_char) and \ - (self.c.label == other.c.label) and \ - (self.c.kb_id == other.c.kb_id) and \ + (span_c.start_char == other_span_c.start_char) and \ + (span_c.end_char == other_span_c.end_char) and \ + (span_c.label == other_span_c.label) and \ + (span_c.kb_id == other_span_c.kb_id) and \ (self.doc == other.doc) ) # > elif op == 4: - return self.c.start_char > other.c.start_char + return span_c.start_char > other_span_c.start_char # >= elif op == 5: - return self.c.start_char >= other.c.start_char + return span_c.start_char >= other_span_c.start_char def __hash__(self): - return hash((self.doc, self.c.start_char, self.c.end_char, self.c.label, self.c.kb_id)) + cdef SpanC* span_c = self.span_c() + return hash((self.doc, span_c.start_char, span_c.end_char, span_c.label, span_c.kb_id)) def __len__(self): """Get the number of tokens in the span. @@ -169,9 +175,10 @@ cdef class Span: DOCS: https://spacy.io/api/span#len """ - if self.c.end < self.c.start: + cdef SpanC* span_c = self.span_c() + if span_c.end < span_c.start: return 0 - return self.c.end - self.c.start + return span_c.end - span_c.start def __repr__(self): return self.text @@ -185,15 +192,16 @@ cdef class Span: DOCS: https://spacy.io/api/span#getitem """ + cdef SpanC* span_c = self.span_c() if isinstance(i, slice): start, end = normalize_slice(len(self), i.start, i.stop, i.step) return Span(self.doc, start + self.start, end + self.start) else: if i < 0: - token_i = self.c.end + i + token_i = span_c.end + i else: - token_i = self.c.start + i - if self.c.start <= token_i < self.c.end: + token_i = span_c.start + i + if span_c.start <= token_i < span_c.end: return self.doc[token_i] else: raise IndexError(Errors.E1002) @@ -205,7 +213,8 @@ cdef class Span: DOCS: https://spacy.io/api/span#iter """ - for i in range(self.c.start, self.c.end): + cdef SpanC* span_c = self.span_c() + for i in range(span_c.start, span_c.end): yield self.doc[i] def __reduce__(self): @@ -213,9 +222,10 @@ cdef class Span: @property def _(self): + cdef SpanC* span_c = self.span_c() """Custom extension attributes registered via `set_extension`.""" return Underscore(Underscore.span_extensions, self, - start=self.c.start_char, end=self.c.end_char) + start=span_c.start_char, end=span_c.end_char) def as_doc(self, *, bint copy_user_data=False, array_head=None, array=None): """Create a `Doc` object with a copy of the `Span`'s data. @@ -289,13 +299,14 @@ cdef class Span: cdef int length = len(array) cdef attr_t value cdef int i, head_col, ancestor_i + cdef SpanC* span_c = self.span_c() old_to_new_root = dict() if HEAD in attrs: head_col = attrs.index(HEAD) for i in range(length): # if the HEAD refers to a token outside this span, find a more appropriate ancestor token = self[i] - ancestor_i = token.head.i - self.c.start # span offset + ancestor_i = token.head.i - span_c.start # span offset if ancestor_i not in range(length): if DEP in attrs: array[i, attrs.index(DEP)] = dep @@ -303,7 +314,7 @@ cdef class Span: # try finding an ancestor within this span ancestors = token.ancestors for ancestor in ancestors: - ancestor_i = ancestor.i - self.c.start + ancestor_i = ancestor.i - span_c.start if ancestor_i in range(length): array[i, head_col] = ancestor_i - i @@ -332,7 +343,8 @@ cdef class Span: DOCS: https://spacy.io/api/span#get_lca_matrix """ - return numpy.asarray(_get_lca_matrix(self.doc, self.c.start, self.c.end)) + cdef SpanC* span_c = self.span_c() + return numpy.asarray(_get_lca_matrix(self.doc, span_c.start, span_c.end)) def similarity(self, other): """Make a semantic similarity estimate. The default estimate is cosine @@ -426,6 +438,9 @@ cdef class Span: else: raise ValueError(Errors.E030) + cdef SpanC* span_c(self): + return self.c.get() + @property def sents(self): """Obtain the sentences that contain this span. If the given span @@ -477,10 +492,13 @@ cdef class Span: DOCS: https://spacy.io/api/span#ents """ cdef Span ent + cdef SpanC* span_c = self.span_c() + cdef SpanC* ent_span_c ents = [] for ent in self.doc.ents: - if ent.c.start >= self.c.start: - if ent.c.end <= self.c.end: + ent_span_c = ent.span_c() + if ent_span_c.start >= span_c.start: + if ent_span_c.end <= span_c.end: ents.append(ent) else: break @@ -615,11 +633,12 @@ cdef class Span: # This should probably be called 'head', and the other one called # 'gov'. But we went with 'head' elsewhere, and now we're stuck =/ cdef int i + cdef SpanC* span_c = self.span_c() # First, we scan through the Span, and check whether there's a word # with head==0, i.e. a sentence root. If so, we can return it. The # longer the span, the more likely it contains a sentence root, and # in this case we return in linear time. - for i in range(self.c.start, self.c.end): + for i in range(span_c.start, span_c.end): if self.doc.c[i].head == 0: return self.doc[i] # If we don't have a sentence root, we do something that's not so @@ -630,15 +649,15 @@ cdef class Span: # think this should be okay. cdef int current_best = self.doc.length cdef int root = -1 - for i in range(self.c.start, self.c.end): - if self.c.start <= (i+self.doc.c[i].head) < self.c.end: + for i in range(span_c.start, span_c.end): + if span_c.start <= (i+self.doc.c[i].head) < span_c.end: continue words_to_root = _count_words_to_root(&self.doc.c[i], self.doc.length) if words_to_root < current_best: current_best = words_to_root root = i if root == -1: - return self.doc[self.c.start] + return self.doc[span_c.start] else: return self.doc[root] @@ -654,8 +673,9 @@ cdef class Span: the span. RETURNS (Span): The newly constructed object. """ - start_idx += self.c.start_char - end_idx += self.c.start_char + cdef SpanC* span_c = self.span_c() + start_idx += span_c.start_char + end_idx += span_c.start_char return self.doc.char_span(start_idx, end_idx, label=label, kb_id=kb_id, vector=vector) @property @@ -736,53 +756,53 @@ cdef class Span: property start: def __get__(self): - return self.c.start + return self.span_c().start def __set__(self, int start): if start < 0: raise IndexError("TODO") - self.c.start = start + self.span_c().start = start property end: def __get__(self): - return self.c.end + return self.span_c().end def __set__(self, int end): if end < 0: raise IndexError("TODO") - self.c.end = end + self.span_c().end = end property start_char: def __get__(self): - return self.c.start_char + return self.span_c().start_char def __set__(self, int start_char): if start_char < 0: raise IndexError("TODO") - self.c.start_char = start_char + self.span_c().start_char = start_char property end_char: def __get__(self): - return self.c.end_char + return self.span_c().end_char def __set__(self, int end_char): if end_char < 0: raise IndexError("TODO") - self.c.end_char = end_char + self.span_c().end_char = end_char property label: def __get__(self): - return self.c.label + return self.span_c().label def __set__(self, attr_t label): - self.c.label = label + self.span_c().label = label property kb_id: def __get__(self): - return self.c.kb_id + return self.span_c().kb_id def __set__(self, attr_t kb_id): - self.c.kb_id = kb_id + self.span_c().kb_id = kb_id property ent_id: """RETURNS (uint64): The entity ID.""" diff --git a/spacy/tokens/span_group.pxd b/spacy/tokens/span_group.pxd index 5074aa275..6b817578a 100644 --- a/spacy/tokens/span_group.pxd +++ b/spacy/tokens/span_group.pxd @@ -1,3 +1,4 @@ +from libcpp.memory cimport shared_ptr from libcpp.vector cimport vector from ..structs cimport SpanC @@ -5,6 +6,6 @@ cdef class SpanGroup: cdef public object _doc_ref cdef public str name cdef public dict attrs - cdef vector[SpanC] c + cdef vector[shared_ptr[SpanC]] c - cdef void push_back(self, SpanC span) nogil + cdef void push_back(self, const shared_ptr[SpanC] &span) diff --git a/spacy/tokens/span_group.pyx b/spacy/tokens/span_group.pyx index 6cfa75237..c310da785 100644 --- a/spacy/tokens/span_group.pyx +++ b/spacy/tokens/span_group.pyx @@ -5,6 +5,7 @@ import srsly from spacy.errors import Errors from .span cimport Span from libc.stdint cimport uint64_t, uint32_t, int32_t +from libcpp.memory cimport make_shared cdef class SpanGroup: @@ -135,9 +136,11 @@ cdef class SpanGroup: DOCS: https://spacy.io/api/spangroup#to_bytes """ + cdef SpanC* span_c output = {"name": self.name, "attrs": self.attrs, "spans": []} for i in range(self.c.size()): span = self.c[i] + span_c = span.get() # The struct.pack here is probably overkill, but it might help if # you're saving tonnes of spans, and it doesn't really add any # complexity. We do take care to specify little-endian byte order @@ -149,13 +152,13 @@ cdef class SpanGroup: # l: int32_t output["spans"].append(struct.pack( ">QQQllll", - span.id, - span.kb_id, - span.label, - span.start, - span.end, - span.start_char, - span.end_char + span_c.id, + span_c.kb_id, + span_c.label, + span_c.start, + span_c.end, + span_c.start_char, + span_c.end_char )) return srsly.msgpack_dumps(output) @@ -182,8 +185,8 @@ cdef class SpanGroup: span.end = items[4] span.start_char = items[5] span.end_char = items[6] - self.c.push_back(span) + self.c.push_back(make_shared[SpanC](span)) return self - cdef void push_back(self, SpanC span) nogil: + cdef void push_back(self, const shared_ptr[SpanC] &span): self.c.push_back(span) From 0e71bd973fa39e9b39f2ff4e023a42cde2064ff7 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Fri, 15 Apr 2022 15:34:58 +0200 Subject: [PATCH 002/123] Return doc offsets in Matcher on spans (#10576) The returned match offsets were only adjusted for `as_spans`, not generally. Because the `on_match` callbacks are always applied to the doc, the `Matcher` matches on spans should consistently use the doc offsets. --- spacy/matcher/matcher.pyx | 7 ++++--- spacy/tests/matcher/test_matcher_api.py | 13 ++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/spacy/matcher/matcher.pyx b/spacy/matcher/matcher.pyx index 745d7cf43..863bd198c 100644 --- a/spacy/matcher/matcher.pyx +++ b/spacy/matcher/matcher.pyx @@ -252,6 +252,10 @@ cdef class Matcher: # non-overlapping ones this `match` can be either (start, end) or # (start, end, alignments) depending on `with_alignments=` option. for key, *match in matches: + # Adjust span matches to doc offsets + if isinstance(doclike, Span): + match[0] += doclike.start + match[1] += doclike.start span_filter = self._filter.get(key) if span_filter is not None: pairs = pairs_by_id.get(key, []) @@ -282,9 +286,6 @@ cdef class Matcher: if as_spans: final_results = [] for key, start, end, *_ in final_matches: - if isinstance(doclike, Span): - start += doclike.start - end += doclike.start final_results.append(Span(doc, start, end, label=key)) elif with_alignments: # convert alignments List[Dict[str, int]] --> List[int] diff --git a/spacy/tests/matcher/test_matcher_api.py b/spacy/tests/matcher/test_matcher_api.py index c02d65cdf..9d401382f 100644 --- a/spacy/tests/matcher/test_matcher_api.py +++ b/spacy/tests/matcher/test_matcher_api.py @@ -591,9 +591,16 @@ def test_matcher_span(matcher): doc = Doc(matcher.vocab, words=text.split()) span_js = doc[:3] span_java = doc[4:] - assert len(matcher(doc)) == 2 - assert len(matcher(span_js)) == 1 - assert len(matcher(span_java)) == 1 + doc_matches = matcher(doc) + span_js_matches = matcher(span_js) + span_java_matches = matcher(span_java) + assert len(doc_matches) == 2 + assert len(span_js_matches) == 1 + assert len(span_java_matches) == 1 + + # match offsets always refer to the doc + assert doc_matches[0] == span_js_matches[0] + assert doc_matches[1] == span_java_matches[0] def test_matcher_as_spans(matcher): From ba18d2913d0cbab62fac71cf6e3f316caaf2fb2a Mon Sep 17 00:00:00 2001 From: Madeesh Kannan Date: Fri, 15 Jul 2022 11:14:08 +0200 Subject: [PATCH 003/123] `Morphology`/`Morphologizer` optimizations and refactoring (#11024) * `Morphology`: Refactor to use C types, reduce allocations, remove unused code * `Morphologzier`: Avoid unnecessary sorting of morpho features * `Morphologizer`: Remove execessive reallocations of labels, improve hash lookups of labels, coerce `numpy` numeric types to native ints Update docs * Remove unused method * Replace `unique_ptr` usage with `shared_ptr` * Add type annotations to internal Python methods, rename `hash` variable, fix typos * Add comment to clarify implementation detail * Fix return type * `Morphology`: Stop early when splitting fields and values --- spacy/morphology.pxd | 44 +++-- spacy/morphology.pyx | 267 ++++++++++++++++++------------ spacy/pipeline/morphologizer.pyx | 29 ++-- spacy/structs.pxd | 8 - spacy/tokens/morphanalysis.pxd | 7 +- spacy/tokens/morphanalysis.pyx | 36 ++-- spacy/tokens/token.pyx | 3 +- website/docs/api/morphologizer.md | 2 +- 8 files changed, 235 insertions(+), 161 deletions(-) diff --git a/spacy/morphology.pxd b/spacy/morphology.pxd index 8d449d065..63faab5be 100644 --- a/spacy/morphology.pxd +++ b/spacy/morphology.pxd @@ -1,23 +1,41 @@ -from cymem.cymem cimport Pool -from preshed.maps cimport PreshMap cimport numpy as np -from libc.stdint cimport uint64_t +from libc.stdint cimport uint32_t, uint64_t +from libcpp.unordered_map cimport unordered_map +from libcpp.vector cimport vector +from libcpp.memory cimport shared_ptr -from .structs cimport MorphAnalysisC from .strings cimport StringStore from .typedefs cimport attr_t, hash_t +cdef cppclass Feature: + hash_t field + hash_t value + + __init__(): + this.field = 0 + this.value = 0 + + +cdef cppclass MorphAnalysisC: + hash_t key + vector[Feature] features + + __init__(): + this.key = 0 + cdef class Morphology: - cdef readonly Pool mem cdef readonly StringStore strings - cdef PreshMap tags # Keyed by hash, value is pointer to tag + cdef unordered_map[hash_t, shared_ptr[MorphAnalysisC]] tags - cdef MorphAnalysisC create_morph_tag(self, field_feature_pairs) except * - cdef int insert(self, MorphAnalysisC tag) except -1 + cdef shared_ptr[MorphAnalysisC] _lookup_tag(self, hash_t tag_hash) + cdef void _intern_morph_tag(self, hash_t tag_key, feats) + cdef hash_t _add(self, features) + cdef str _normalize_features(self, features) + cdef str get_morph_str(self, hash_t morph_key) + cdef shared_ptr[MorphAnalysisC] get_morph_c(self, hash_t morph_key) - -cdef int check_feature(const MorphAnalysisC* morph, attr_t feature) nogil -cdef list list_features(const MorphAnalysisC* morph) -cdef np.ndarray get_by_field(const MorphAnalysisC* morph, attr_t field) -cdef int get_n_by_field(attr_t* results, const MorphAnalysisC* morph, attr_t field) nogil +cdef int check_feature(const shared_ptr[MorphAnalysisC] morph, attr_t feature) nogil +cdef list list_features(const shared_ptr[MorphAnalysisC] morph) +cdef np.ndarray get_by_field(const shared_ptr[MorphAnalysisC] morph, attr_t field) +cdef int get_n_by_field(attr_t* results, const shared_ptr[MorphAnalysisC] morph, attr_t field) nogil diff --git a/spacy/morphology.pyx b/spacy/morphology.pyx index c3ffc46a1..2c3be7b46 100644 --- a/spacy/morphology.pyx +++ b/spacy/morphology.pyx @@ -1,10 +1,10 @@ # cython: infer_types import numpy import warnings +from typing import Union, Tuple, List, Dict, Optional +from cython.operator cimport dereference as deref +from libcpp.memory cimport shared_ptr -from .attrs cimport POS - -from .parts_of_speech import IDS as POS_IDS from .errors import Warnings from . import symbols @@ -24,134 +24,187 @@ cdef class Morphology: EMPTY_MORPH = symbols.NAMES[symbols._] def __init__(self, StringStore strings): - self.mem = Pool() self.strings = strings - self.tags = PreshMap() def __reduce__(self): tags = set([self.get(self.strings[s]) for s in self.strings]) tags -= set([""]) return (unpickle_morphology, (self.strings, sorted(tags)), None, None) - def add(self, features): + cdef shared_ptr[MorphAnalysisC] _lookup_tag(self, hash_t tag_hash): + match = self.tags.find(tag_hash) + if match != self.tags.const_end(): + return deref(match).second + else: + return shared_ptr[MorphAnalysisC]() + + def _normalize_attr(self, attr_key : Union[int, str], attr_value : Union[int, str]) -> Optional[Tuple[str, Union[str, List[str]]]]: + if isinstance(attr_key, (int, str)) and isinstance(attr_value, (int, str)): + attr_key = self.strings.as_string(attr_key) + attr_value = self.strings.as_string(attr_value) + + # Preserve multiple values as a list + if self.VALUE_SEP in attr_value: + values = attr_value.split(self.VALUE_SEP) + values.sort() + attr_value = values + else: + warnings.warn(Warnings.W100.format(feature={attr_key: attr_value})) + return None + + return attr_key, attr_value + + def _str_to_normalized_feat_dict(self, feats: str) -> Dict[str, str]: + if not feats or feats == self.EMPTY_MORPH: + return {} + + out = [] + for feat in feats.split(self.FEATURE_SEP): + field, values = feat.split(self.FIELD_SEP, 1) + normalized_attr = self._normalize_attr(field, values) + if normalized_attr is None: + continue + out.append((normalized_attr[0], normalized_attr[1])) + out.sort(key=lambda x: x[0]) + return dict(out) + + def _dict_to_normalized_feat_dict(self, feats: Dict[Union[int, str], Union[int, str]]) -> Dict[str, str]: + out = [] + for field, values in feats.items(): + normalized_attr = self._normalize_attr(field, values) + if normalized_attr is None: + continue + out.append((normalized_attr[0], normalized_attr[1])) + out.sort(key=lambda x: x[0]) + return dict(out) + + + def _normalized_feat_dict_to_str(self, feats: Dict[str, str]) -> str: + norm_feats_string = self.FEATURE_SEP.join([ + self.FIELD_SEP.join([field, self.VALUE_SEP.join(values) if isinstance(values, list) else values]) + for field, values in feats.items() + ]) + return norm_feats_string or self.EMPTY_MORPH + + + cdef hash_t _add(self, features): """Insert a morphological analysis in the morphology table, if not already present. The morphological analysis may be provided in the UD FEATS format as a string or in the tag map dict format. Returns the hash of the new analysis. """ - cdef MorphAnalysisC* tag_ptr + cdef hash_t tag_hash = 0 + cdef shared_ptr[MorphAnalysisC] tag if isinstance(features, str): if features == "": features = self.EMPTY_MORPH - tag_ptr = self.tags.get(self.strings[features]) - if tag_ptr != NULL: - return tag_ptr.key - features = self.feats_to_dict(features) - if not isinstance(features, dict): + + tag_hash = self.strings[features] + tag = self._lookup_tag(tag_hash) + if tag: + return deref(tag).key + + features = self._str_to_normalized_feat_dict(features) + elif isinstance(features, dict): + features = self._dict_to_normalized_feat_dict(features) + else: warnings.warn(Warnings.W100.format(feature=features)) features = {} - string_features = {self.strings.as_string(field): self.strings.as_string(values) for field, values in features.items()} - # intified ("Field", "Field=Value") pairs - field_feature_pairs = [] - for field in sorted(string_features): - values = string_features[field] - for value in values.split(self.VALUE_SEP): - field_feature_pairs.append(( - self.strings.add(field), - self.strings.add(field + self.FIELD_SEP + value), - )) - cdef MorphAnalysisC tag = self.create_morph_tag(field_feature_pairs) + # the hash key for the tag is either the hash of the normalized UFEATS # string or the hash of an empty placeholder - norm_feats_string = self.normalize_features(features) - tag.key = self.strings.add(norm_feats_string) - self.insert(tag) - return tag.key + norm_feats_string = self._normalized_feat_dict_to_str(features) + tag_hash = self.strings.add(norm_feats_string) + tag = self._lookup_tag(tag_hash) + if tag: + return deref(tag).key - def normalize_features(self, features): + self._intern_morph_tag(tag_hash, features) + return tag_hash + + cdef void _intern_morph_tag(self, hash_t tag_key, feats): + # intified ("Field", "Field=Value") pairs where fields with multiple values have + # been split into individual tuples, e.g.: + # [("Field1", "Field1=Value1"), ("Field1", "Field1=Value2"), + # ("Field2", "Field2=Value3")] + field_feature_pairs = [] + + # Feat dict is normalized at this point. + for field, values in feats.items(): + field_key = self.strings.add(field) + if isinstance(values, list): + for value in values: + value_key = self.strings.add(field + self.FIELD_SEP + value) + field_feature_pairs.append((field_key, value_key)) + else: + # We could box scalar values into a list and use a common + # code path to generate features but that incurs a small + # but measurable allocation/iteration overhead (as this + # branch is taken often enough). + value_key = self.strings.add(field + self.FIELD_SEP + values) + field_feature_pairs.append((field_key, value_key)) + + num_features = len(field_feature_pairs) + cdef shared_ptr[MorphAnalysisC] tag = shared_ptr[MorphAnalysisC](new MorphAnalysisC()) + deref(tag).key = tag_key + deref(tag).features.resize(num_features) + + for i in range(num_features): + deref(tag).features[i].field = field_feature_pairs[i][0] + deref(tag).features[i].value = field_feature_pairs[i][1] + + self.tags[tag_key] = tag + + cdef str get_morph_str(self, hash_t morph_key): + cdef shared_ptr[MorphAnalysisC] tag = self._lookup_tag(morph_key) + if not tag: + return "" + else: + return self.strings[deref(tag).key] + + cdef shared_ptr[MorphAnalysisC] get_morph_c(self, hash_t morph_key): + return self._lookup_tag(morph_key) + + cdef str _normalize_features(self, features): """Create a normalized FEATS string from a features string or dict. features (Union[dict, str]): Features as dict or UFEATS string. RETURNS (str): Features as normalized UFEATS string. """ if isinstance(features, str): - features = self.feats_to_dict(features) - if not isinstance(features, dict): + features = self._str_to_normalized_feat_dict(features) + elif isinstance(features, dict): + features = self._dict_to_normalized_feat_dict(features) + else: warnings.warn(Warnings.W100.format(feature=features)) features = {} - features = self.normalize_attrs(features) - string_features = {self.strings.as_string(field): self.strings.as_string(values) for field, values in features.items()} - # normalized UFEATS string with sorted fields and values - norm_feats_string = self.FEATURE_SEP.join(sorted([ - self.FIELD_SEP.join([field, values]) - for field, values in string_features.items() - ])) - return norm_feats_string or self.EMPTY_MORPH - def normalize_attrs(self, attrs): - """Convert attrs dict so that POS is always by ID, other features are - by string. Values separated by VALUE_SEP are sorted. - """ - out = {} - attrs = dict(attrs) - for key, value in attrs.items(): - # convert POS value to ID - if key == POS or (isinstance(key, str) and key.upper() == "POS"): - if isinstance(value, str) and value.upper() in POS_IDS: - value = POS_IDS[value.upper()] - elif isinstance(value, int) and value not in POS_IDS.values(): - warnings.warn(Warnings.W100.format(feature={key: value})) - continue - out[POS] = value - # accept any string or ID fields and values and convert to strings - elif isinstance(key, (int, str)) and isinstance(value, (int, str)): - key = self.strings.as_string(key) - value = self.strings.as_string(value) - # sort values - if self.VALUE_SEP in value: - value = self.VALUE_SEP.join(sorted(value.split(self.VALUE_SEP))) - out[key] = value - else: - warnings.warn(Warnings.W100.format(feature={key: value})) - return out + return self._normalized_feat_dict_to_str(features) - cdef MorphAnalysisC create_morph_tag(self, field_feature_pairs) except *: - """Creates a MorphAnalysisC from a list of intified - ("Field", "Field=Value") tuples where fields with multiple values have - been split into individual tuples, e.g.: - [("Field1", "Field1=Value1"), ("Field1", "Field1=Value2"), - ("Field2", "Field2=Value3")] - """ - cdef MorphAnalysisC tag - tag.length = len(field_feature_pairs) - if tag.length > 0: - tag.fields = self.mem.alloc(tag.length, sizeof(attr_t)) - tag.features = self.mem.alloc(tag.length, sizeof(attr_t)) - for i, (field, feature) in enumerate(field_feature_pairs): - tag.fields[i] = field - tag.features[i] = feature - return tag + def add(self, features): + return self._add(features) - cdef int insert(self, MorphAnalysisC tag) except -1: - cdef hash_t key = tag.key - if self.tags.get(key) == NULL: - tag_ptr = self.mem.alloc(1, sizeof(MorphAnalysisC)) - tag_ptr[0] = tag - self.tags.set(key, tag_ptr) + def get(self, morph_key): + return self.get_morph_str(morph_key) - def get(self, hash_t morph): - tag = self.tags.get(morph) - if tag == NULL: - return "" - else: - return self.strings[tag.key] + def normalize_features(self, features): + return self._normalize_features(features) @staticmethod - def feats_to_dict(feats): + def feats_to_dict(feats, *, sort_values=True): if not feats or feats == Morphology.EMPTY_MORPH: return {} - return {field: Morphology.VALUE_SEP.join(sorted(values.split(Morphology.VALUE_SEP))) for field, values in - [feat.split(Morphology.FIELD_SEP) for feat in feats.split(Morphology.FEATURE_SEP)]} + + out = {} + for feat in feats.split(Morphology.FEATURE_SEP): + field, values = feat.split(Morphology.FIELD_SEP, 1) + if sort_values: + values = values.split(Morphology.VALUE_SEP) + values.sort() + values = Morphology.VALUE_SEP.join(values) + + out[field] = values + return out @staticmethod def dict_to_feats(feats_dict): @@ -160,34 +213,34 @@ cdef class Morphology: return Morphology.FEATURE_SEP.join(sorted([Morphology.FIELD_SEP.join([field, Morphology.VALUE_SEP.join(sorted(values.split(Morphology.VALUE_SEP)))]) for field, values in feats_dict.items()])) -cdef int check_feature(const MorphAnalysisC* morph, attr_t feature) nogil: +cdef int check_feature(const shared_ptr[MorphAnalysisC] morph, attr_t feature) nogil: cdef int i - for i in range(morph.length): - if morph.features[i] == feature: + for i in range(deref(morph).features.size()): + if deref(morph).features[i].value == feature: return True return False -cdef list list_features(const MorphAnalysisC* morph): +cdef list list_features(const shared_ptr[MorphAnalysisC] morph): cdef int i features = [] - for i in range(morph.length): - features.append(morph.features[i]) + for i in range(deref(morph).features.size()): + features.append(deref(morph).features[i].value) return features -cdef np.ndarray get_by_field(const MorphAnalysisC* morph, attr_t field): - cdef np.ndarray results = numpy.zeros((morph.length,), dtype="uint64") +cdef np.ndarray get_by_field(const shared_ptr[MorphAnalysisC] morph, attr_t field): + cdef np.ndarray results = numpy.zeros((deref(morph).features.size(),), dtype="uint64") n = get_n_by_field(results.data, morph, field) return results[:n] -cdef int get_n_by_field(attr_t* results, const MorphAnalysisC* morph, attr_t field) nogil: +cdef int get_n_by_field(attr_t* results, const shared_ptr[MorphAnalysisC] morph, attr_t field) nogil: cdef int n_results = 0 cdef int i - for i in range(morph.length): - if morph.fields[i] == field: - results[n_results] = morph.features[i] + for i in range(deref(morph).features.size()): + if deref(morph).features[i].field == field: + results[n_results] = deref(morph).features[i].value n_results += 1 return n_results diff --git a/spacy/pipeline/morphologizer.pyx b/spacy/pipeline/morphologizer.pyx index 24f98508f..eec1e42e1 100644 --- a/spacy/pipeline/morphologizer.pyx +++ b/spacy/pipeline/morphologizer.pyx @@ -127,8 +127,8 @@ class Morphologizer(Tagger): @property def labels(self): - """RETURNS (Tuple[str]): The labels currently added to the component.""" - return tuple(self.cfg["labels_morph"].keys()) + """RETURNS (Iterable[str]): The labels currently added to the component.""" + return self.cfg["labels_morph"].keys() @property def label_data(self) -> Dict[str, Dict[str, Union[str, float, int, None]]]: @@ -151,7 +151,7 @@ class Morphologizer(Tagger): # normalize label norm_label = self.vocab.morphology.normalize_features(label) # extract separate POS and morph tags - label_dict = Morphology.feats_to_dict(label) + label_dict = Morphology.feats_to_dict(label, sort_values=False) pos = label_dict.get(self.POS_FEAT, "") if self.POS_FEAT in label_dict: label_dict.pop(self.POS_FEAT) @@ -189,7 +189,7 @@ class Morphologizer(Tagger): continue morph = str(token.morph) # create and add the combined morph+POS label - morph_dict = Morphology.feats_to_dict(morph) + morph_dict = Morphology.feats_to_dict(morph, sort_values=False) if pos: morph_dict[self.POS_FEAT] = pos norm_label = self.vocab.strings[self.vocab.morphology.add(morph_dict)] @@ -206,7 +206,7 @@ class Morphologizer(Tagger): for i, token in enumerate(example.reference): pos = token.pos_ morph = str(token.morph) - morph_dict = Morphology.feats_to_dict(morph) + morph_dict = Morphology.feats_to_dict(morph, sort_values=False) if pos: morph_dict[self.POS_FEAT] = pos norm_label = self.vocab.strings[self.vocab.morphology.add(morph_dict)] @@ -231,26 +231,29 @@ class Morphologizer(Tagger): cdef Vocab vocab = self.vocab cdef bint overwrite = self.cfg["overwrite"] cdef bint extend = self.cfg["extend"] - labels = self.labels + + # We require random access for the upcoming ops, so we need + # to allocate a compatible container out of the iterable. + labels = tuple(self.labels) for i, doc in enumerate(docs): doc_tag_ids = batch_tag_ids[i] if hasattr(doc_tag_ids, "get"): doc_tag_ids = doc_tag_ids.get() for j, tag_id in enumerate(doc_tag_ids): - morph = labels[tag_id] + morph = labels[int(tag_id)] # set morph if doc.c[j].morph == 0 or overwrite or extend: if overwrite and extend: # morphologizer morph overwrites any existing features # while extending - extended_morph = Morphology.feats_to_dict(self.vocab.strings[doc.c[j].morph]) - extended_morph.update(Morphology.feats_to_dict(self.cfg["labels_morph"].get(morph, 0))) + extended_morph = Morphology.feats_to_dict(self.vocab.strings[doc.c[j].morph], sort_values=False) + extended_morph.update(Morphology.feats_to_dict(self.cfg["labels_morph"].get(morph, 0), sort_values=False)) doc.c[j].morph = self.vocab.morphology.add(extended_morph) elif extend: # existing features are preserved and any new features # are added - extended_morph = Morphology.feats_to_dict(self.cfg["labels_morph"].get(morph, 0)) - extended_morph.update(Morphology.feats_to_dict(self.vocab.strings[doc.c[j].morph])) + extended_morph = Morphology.feats_to_dict(self.cfg["labels_morph"].get(morph, 0), sort_values=False) + extended_morph.update(Morphology.feats_to_dict(self.vocab.strings[doc.c[j].morph], sort_values=False)) doc.c[j].morph = self.vocab.morphology.add(extended_morph) else: # clobber @@ -270,7 +273,7 @@ class Morphologizer(Tagger): DOCS: https://spacy.io/api/morphologizer#get_loss """ validate_examples(examples, "Morphologizer.get_loss") - loss_func = SequenceCategoricalCrossentropy(names=self.labels, normalize=False) + loss_func = SequenceCategoricalCrossentropy(names=tuple(self.labels), normalize=False) truths = [] for eg in examples: eg_truths = [] @@ -291,7 +294,7 @@ class Morphologizer(Tagger): label = None # Otherwise, generate the combined label else: - label_dict = Morphology.feats_to_dict(morph) + label_dict = Morphology.feats_to_dict(morph, sort_values=False) if pos: label_dict[self.POS_FEAT] = pos label = self.vocab.strings[self.vocab.morphology.add(label_dict)] diff --git a/spacy/structs.pxd b/spacy/structs.pxd index 86d5b67ed..b9b6f6ba8 100644 --- a/spacy/structs.pxd +++ b/spacy/structs.pxd @@ -58,14 +58,6 @@ cdef struct TokenC: hash_t ent_id -cdef struct MorphAnalysisC: - hash_t key - int length - - attr_t* fields - attr_t* features - - # Internal struct, for storage and disambiguation of entities. cdef struct KBEntryC: diff --git a/spacy/tokens/morphanalysis.pxd b/spacy/tokens/morphanalysis.pxd index 9510875c9..f866488ec 100644 --- a/spacy/tokens/morphanalysis.pxd +++ b/spacy/tokens/morphanalysis.pxd @@ -1,9 +1,12 @@ from ..vocab cimport Vocab from ..typedefs cimport hash_t -from ..structs cimport MorphAnalysisC +from ..morphology cimport MorphAnalysisC +from libcpp.memory cimport shared_ptr cdef class MorphAnalysis: cdef readonly Vocab vocab cdef readonly hash_t key - cdef MorphAnalysisC c + cdef shared_ptr[MorphAnalysisC] c + + cdef void _init_c(self, hash_t key) diff --git a/spacy/tokens/morphanalysis.pyx b/spacy/tokens/morphanalysis.pyx index a7d1f2e44..af0067f4e 100644 --- a/spacy/tokens/morphanalysis.pyx +++ b/spacy/tokens/morphanalysis.pyx @@ -5,7 +5,12 @@ from ..errors import Errors from ..morphology import Morphology from ..vocab cimport Vocab from ..typedefs cimport hash_t, attr_t -from ..morphology cimport list_features, check_feature, get_by_field +from ..morphology cimport list_features, check_feature, get_by_field, MorphAnalysisC +from libcpp.memory cimport shared_ptr +from cython.operator cimport dereference as deref + + +cdef shared_ptr[MorphAnalysisC] EMPTY_MORPH_TAG = shared_ptr[MorphAnalysisC](new MorphAnalysisC()) cdef class MorphAnalysis: @@ -13,39 +18,38 @@ cdef class MorphAnalysis: def __init__(self, Vocab vocab, features=dict()): self.vocab = vocab self.key = self.vocab.morphology.add(features) - analysis = self.vocab.morphology.tags.get(self.key) - if analysis is not NULL: - self.c = analysis[0] + self._init_c(self.key) + + cdef void _init_c(self, hash_t key): + cdef shared_ptr[MorphAnalysisC] analysis = self.vocab.morphology.get_morph_c(key) + if analysis: + self.c = analysis else: - memset(&self.c, 0, sizeof(self.c)) + self.c = EMPTY_MORPH_TAG @classmethod def from_id(cls, Vocab vocab, hash_t key): """Create a morphological analysis from a given ID.""" - cdef MorphAnalysis morph = MorphAnalysis.__new__(MorphAnalysis, vocab) + cdef MorphAnalysis morph = MorphAnalysis(vocab) morph.vocab = vocab morph.key = key - analysis = vocab.morphology.tags.get(key) - if analysis is not NULL: - morph.c = analysis[0] - else: - memset(&morph.c, 0, sizeof(morph.c)) + morph._init_c(key) return morph def __contains__(self, feature): """Test whether the morphological analysis contains some feature.""" cdef attr_t feat_id = self.vocab.strings.as_int(feature) - return check_feature(&self.c, feat_id) + return check_feature(self.c, feat_id) def __iter__(self): """Iterate over the features in the analysis.""" cdef attr_t feature - for feature in list_features(&self.c): + for feature in list_features(self.c): yield self.vocab.strings[feature] def __len__(self): """The number of features in the analysis.""" - return self.c.length + return deref(self.c).features.size() def __hash__(self): return self.key @@ -61,7 +65,7 @@ cdef class MorphAnalysis: def get(self, field): """Retrieve feature values by field.""" cdef attr_t field_id = self.vocab.strings.as_int(field) - cdef np.ndarray results = get_by_field(&self.c, field_id) + cdef np.ndarray results = get_by_field(self.c, field_id) features = [self.vocab.strings[result] for result in results] return [f.split(Morphology.FIELD_SEP)[1] for f in features] @@ -69,7 +73,7 @@ cdef class MorphAnalysis: """Produce a json serializable representation as a UD FEATS-style string. """ - morph_string = self.vocab.strings[self.c.key] + morph_string = self.vocab.strings[deref(self.c).key] if morph_string == self.vocab.morphology.EMPTY_MORPH: return "" return morph_string diff --git a/spacy/tokens/token.pyx b/spacy/tokens/token.pyx index d14930348..77906b83e 100644 --- a/spacy/tokens/token.pyx +++ b/spacy/tokens/token.pyx @@ -22,6 +22,7 @@ from .. import parts_of_speech from ..errors import Errors, Warnings from ..attrs import IOB_STRINGS from .underscore import Underscore, get_ext_args +from cython.operator cimport dereference as deref cdef class Token: @@ -230,7 +231,7 @@ cdef class Token: # Check that the morph has the same vocab if self.vocab != morph.vocab: raise ValueError(Errors.E1013) - self.c.morph = morph.c.key + self.c.morph = deref(morph.c).key def set_morph(self, features): cdef hash_t key diff --git a/website/docs/api/morphologizer.md b/website/docs/api/morphologizer.md index 434c56833..67a4f23b7 100644 --- a/website/docs/api/morphologizer.md +++ b/website/docs/api/morphologizer.md @@ -401,7 +401,7 @@ coarse-grained POS as the feature `POS`. | Name | Description | | ----------- | ------------------------------------------------------ | -| **RETURNS** | The labels added to the component. ~~Tuple[str, ...]~~ | +| **RETURNS** | The labels added to the component. ~~Iterable[str, ...]~~ | ## Morphologizer.label_data {#label_data tag="property" new="3"} From e581eeac347b93e9436ff0af3443bdb2e75d5c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Fri, 29 Jul 2022 15:12:19 +0200 Subject: [PATCH 004/123] precompute_hiddens/Parser: look up CPU ops once (v4) (#11068) * precompute_hiddens/Parser: look up CPU ops once * precompute_hiddens: make cpu_ops private --- spacy/ml/parser_model.pyx | 8 +++----- spacy/pipeline/transition_parser.pxd | 1 + spacy/pipeline/transition_parser.pyx | 8 ++------ 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/spacy/ml/parser_model.pyx b/spacy/ml/parser_model.pyx index 961bf4d70..055fa0bad 100644 --- a/spacy/ml/parser_model.pyx +++ b/spacy/ml/parser_model.pyx @@ -347,6 +347,7 @@ cdef class precompute_hiddens: cdef bint _is_synchronized cdef public object ops cdef public object numpy_ops + cdef public object _cpu_ops cdef np.ndarray _features cdef np.ndarray _cached cdef np.ndarray bias @@ -377,6 +378,7 @@ cdef class precompute_hiddens: self.nO = cached.shape[2] self.ops = lower_model.ops self.numpy_ops = NumpyOps() + self._cpu_ops = get_ops("cpu") if isinstance(self.ops, CupyOps) else self.ops assert activation in (None, "relu", "maxout") self.activation = activation self._is_synchronized = False @@ -439,11 +441,7 @@ cdef class precompute_hiddens: # - Output from backward on GPU bp_hiddens = self._bp_hiddens - cdef CBlas cblas - if isinstance(self.ops, CupyOps): - cblas = NUMPY_OPS.cblas() - else: - cblas = self.ops.cblas() + cdef CBlas cblas = self._cpu_ops.cblas() feat_weights = self.get_feat_weights() cdef int[:, ::1] ids = token_ids diff --git a/spacy/pipeline/transition_parser.pxd b/spacy/pipeline/transition_parser.pxd index 1521fde60..f20e69a6e 100644 --- a/spacy/pipeline/transition_parser.pxd +++ b/spacy/pipeline/transition_parser.pxd @@ -12,6 +12,7 @@ cdef class Parser(TrainablePipe): cdef public object _rehearsal_model cdef readonly TransitionSystem moves cdef public object _multitasks + cdef object _cpu_ops cdef void _parseC(self, CBlas cblas, StateC** states, WeightsC weights, SizesC sizes) nogil diff --git a/spacy/pipeline/transition_parser.pyx b/spacy/pipeline/transition_parser.pyx index 1327db2ce..340334b1a 100644 --- a/spacy/pipeline/transition_parser.pyx +++ b/spacy/pipeline/transition_parser.pyx @@ -123,6 +123,7 @@ cdef class Parser(TrainablePipe): self._rehearsal_model = None self.scorer = scorer + self._cpu_ops = get_ops("cpu") if isinstance(self.model.ops, CupyOps) else self.model.ops def __getnewargs_ex__(self): """This allows pickling the Parser and its keyword-only init arguments""" @@ -262,12 +263,7 @@ cdef class Parser(TrainablePipe): def greedy_parse(self, docs, drop=0.): cdef vector[StateC*] states cdef StateClass state - ops = self.model.ops - cdef CBlas cblas - if isinstance(ops, CupyOps): - cblas = NUMPY_OPS.cblas() - else: - cblas = ops.cblas() + cdef CBlas cblas = self._cpu_ops.cblas() self._ensure_labels_are_added(docs) set_dropout_rate(self.model, drop) batch = self.moves.init_batch(docs) From 5d54c0e32a4dbcf969953d8c2c2a5940dd4295d1 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Wed, 10 Aug 2022 11:44:05 +0200 Subject: [PATCH 005/123] Rename modules for consistency (#11286) * rename Python module to entity_ruler * rename Python module to attribute_ruler --- spacy/pipeline/__init__.py | 4 ++-- spacy/pipeline/{attributeruler.py => attribute_ruler.py} | 0 spacy/pipeline/{entityruler.py => entity_ruler.py} | 0 website/docs/api/attributeruler.md | 4 ++-- website/docs/api/entityruler.md | 4 ++-- website/docs/usage/saving-loading.md | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) rename spacy/pipeline/{attributeruler.py => attribute_ruler.py} (100%) rename spacy/pipeline/{entityruler.py => entity_ruler.py} (100%) diff --git a/spacy/pipeline/__init__.py b/spacy/pipeline/__init__.py index 26931606b..4744a989b 100644 --- a/spacy/pipeline/__init__.py +++ b/spacy/pipeline/__init__.py @@ -1,9 +1,9 @@ -from .attributeruler import AttributeRuler +from .attribute_ruler import AttributeRuler from .dep_parser import DependencyParser from .edit_tree_lemmatizer import EditTreeLemmatizer from .entity_linker import EntityLinker from .ner import EntityRecognizer -from .entityruler import EntityRuler +from .entity_ruler import EntityRuler from .lemmatizer import Lemmatizer from .morphologizer import Morphologizer from .pipe import Pipe diff --git a/spacy/pipeline/attributeruler.py b/spacy/pipeline/attribute_ruler.py similarity index 100% rename from spacy/pipeline/attributeruler.py rename to spacy/pipeline/attribute_ruler.py diff --git a/spacy/pipeline/entityruler.py b/spacy/pipeline/entity_ruler.py similarity index 100% rename from spacy/pipeline/entityruler.py rename to spacy/pipeline/entity_ruler.py diff --git a/website/docs/api/attributeruler.md b/website/docs/api/attributeruler.md index 965bffbcc..f56e15b29 100644 --- a/website/docs/api/attributeruler.md +++ b/website/docs/api/attributeruler.md @@ -1,7 +1,7 @@ --- title: AttributeRuler tag: class -source: spacy/pipeline/attributeruler.py +source: spacy/pipeline/attribute_ruler.py new: 3 teaser: 'Pipeline component for rule-based token attribute assignment' api_string_name: attribute_ruler @@ -34,7 +34,7 @@ how the component should be configured. You can override its settings via the | `validate` | Whether patterns should be validated (passed to the `Matcher`). Defaults to `False`. ~~bool~~ | ```python -%%GITHUB_SPACY/spacy/pipeline/attributeruler.py +%%GITHUB_SPACY/spacy/pipeline/attribute_ruler.py ``` ## AttributeRuler.\_\_init\_\_ {#init tag="method"} diff --git a/website/docs/api/entityruler.md b/website/docs/api/entityruler.md index c2ba33f01..ef7acbbf1 100644 --- a/website/docs/api/entityruler.md +++ b/website/docs/api/entityruler.md @@ -1,7 +1,7 @@ --- title: EntityRuler tag: class -source: spacy/pipeline/entityruler.py +source: spacy/pipeline/entity_ruler.py new: 2.1 teaser: 'Pipeline component for rule-based named entity recognition' api_string_name: entity_ruler @@ -64,7 +64,7 @@ how the component should be configured. You can override its settings via the | `scorer` | The scoring method. Defaults to [`spacy.scorer.get_ner_prf`](/api/scorer#get_ner_prf). ~~Optional[Callable]~~ | ```python -%%GITHUB_SPACY/spacy/pipeline/entityruler.py +%%GITHUB_SPACY/spacy/pipeline/entity_ruler.py ``` ## EntityRuler.\_\_init\_\_ {#init tag="method"} diff --git a/website/docs/usage/saving-loading.md b/website/docs/usage/saving-loading.md index 0fd713a49..9a4b584a3 100644 --- a/website/docs/usage/saving-loading.md +++ b/website/docs/usage/saving-loading.md @@ -195,7 +195,7 @@ the data to and from a JSON file. > > To see custom serialization methods in action, check out the new > [`EntityRuler`](/api/entityruler) component and its -> [source](%%GITHUB_SPACY/spacy/pipeline/entityruler.py). Patterns added to the +> [source](%%GITHUB_SPACY/spacy/pipeline/entity_ruler.py). Patterns added to the > component will be saved to a `.jsonl` file if the pipeline is serialized to > disk, and to a bytestring if the pipeline is serialized to bytes. This allows > saving out a pipeline with a rule-based entity recognizer and including all From 551e73ccfc30ffe9904592d05ec80573d7a56122 Mon Sep 17 00:00:00 2001 From: antonpibm <51074867+antonpibm@users.noreply.github.com> Date: Thu, 11 Aug 2022 12:26:26 +0300 Subject: [PATCH 006/123] Match private networks as URLs (#11121) --- spacy/lang/tokenizer_exceptions.py | 4 ---- spacy/tests/tokenizer/test_urls.py | 5 ++++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spacy/lang/tokenizer_exceptions.py b/spacy/lang/tokenizer_exceptions.py index d76fe4262..a5e388ca8 100644 --- a/spacy/lang/tokenizer_exceptions.py +++ b/spacy/lang/tokenizer_exceptions.py @@ -17,10 +17,6 @@ URL_PATTERN = ( r"(?:\S+(?::\S*)?@)?" r"(?:" # IP address exclusion - # private & local networks - r"(?!(?:10|127)(?:\.\d{1,3}){3})" - r"(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})" - r"(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})" # IP address dotted notation octets # excludes loopback network 0.0.0.0 # excludes reserved space >= 224.0.0.0 diff --git a/spacy/tests/tokenizer/test_urls.py b/spacy/tests/tokenizer/test_urls.py index 57e970f87..3d8c7b085 100644 --- a/spacy/tests/tokenizer/test_urls.py +++ b/spacy/tests/tokenizer/test_urls.py @@ -33,6 +33,9 @@ URLS_SHOULD_MATCH = [ "http://userid:password@example.com/", "http://142.42.1.1/", "http://142.42.1.1:8080/", + "http://10.140.12.13/foo", + "http://10.140.12.13/foo/bar?arg1=baz&arg2=taz", + "http://10.1.1.1", "http://foo.com/blah_(wikipedia)#cite-1", "http://foo.com/blah_(wikipedia)_blah#cite-1", "http://foo.com/unicode_(✪)_in_parens", @@ -94,6 +97,7 @@ URLS_SHOULD_NOT_MATCH = [ "http://foo.bar/foo(bar)baz quux", "http://-error-.invalid/", "http://a.b-.co", + # Loopback and broadcast addresses should be excluded "http://0.0.0.0", "http://10.1.1.0", "http://10.1.1.255", @@ -102,7 +106,6 @@ URLS_SHOULD_NOT_MATCH = [ "http://3628126748", "http://.www.foo.bar/", "http://.www.foo.bar./", - "http://10.1.1.1", "NASDAQ:GOOG", "http://-a.b.co", pytest.param("foo.com", marks=pytest.mark.xfail()), From d757dec5c4fc7618dac7a7831504f7611ff75eb4 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Wed, 17 Aug 2022 12:13:54 +0200 Subject: [PATCH 007/123] Remove intify_attrs(_do_deprecated) (#11319) --- spacy/attrs.pyx | 71 +--------------------------------- spacy/tests/lang/test_attrs.py | 8 ---- spacy/tokenizer.pyx | 4 +- spacy/vocab.pyx | 3 +- 4 files changed, 4 insertions(+), 82 deletions(-) diff --git a/spacy/attrs.pyx b/spacy/attrs.pyx index dc8eed7c3..7b6fd9e94 100644 --- a/spacy/attrs.pyx +++ b/spacy/attrs.pyx @@ -97,7 +97,7 @@ NAMES = [key for key, value in sorted(IDS.items(), key=lambda item: item[1])] locals().update(IDS) -def intify_attrs(stringy_attrs, strings_map=None, _do_deprecated=False): +def intify_attrs(stringy_attrs, strings_map=None): """ Normalize a dictionary of attributes, converting them to ints. @@ -109,75 +109,6 @@ def intify_attrs(stringy_attrs, strings_map=None, _do_deprecated=False): converted to ints. """ inty_attrs = {} - if _do_deprecated: - if "F" in stringy_attrs: - stringy_attrs["ORTH"] = stringy_attrs.pop("F") - if "L" in stringy_attrs: - stringy_attrs["LEMMA"] = stringy_attrs.pop("L") - if "pos" in stringy_attrs: - stringy_attrs["TAG"] = stringy_attrs.pop("pos") - if "morph" in stringy_attrs: - morphs = stringy_attrs.pop("morph") - if "number" in stringy_attrs: - stringy_attrs.pop("number") - if "tenspect" in stringy_attrs: - stringy_attrs.pop("tenspect") - morph_keys = [ - "PunctType", - "PunctSide", - "Other", - "Degree", - "AdvType", - "Number", - "VerbForm", - "PronType", - "Aspect", - "Tense", - "PartType", - "Poss", - "Hyph", - "ConjType", - "NumType", - "Foreign", - "VerbType", - "NounType", - "Gender", - "Mood", - "Negative", - "Tense", - "Voice", - "Abbr", - "Derivation", - "Echo", - "Foreign", - "NameType", - "NounType", - "NumForm", - "NumValue", - "PartType", - "Polite", - "StyleVariant", - "PronType", - "AdjType", - "Person", - "Variant", - "AdpType", - "Reflex", - "Negative", - "Mood", - "Aspect", - "Case", - "Polarity", - "PrepCase", - "Animacy", # U20 - ] - for key in morph_keys: - if key in stringy_attrs: - stringy_attrs.pop(key) - elif key.lower() in stringy_attrs: - stringy_attrs.pop(key.lower()) - elif key.upper() in stringy_attrs: - stringy_attrs.pop(key.upper()) for name, value in stringy_attrs.items(): int_key = intify_attr(name) if int_key is not None: diff --git a/spacy/tests/lang/test_attrs.py b/spacy/tests/lang/test_attrs.py index 1c27c1744..1e1bae08c 100644 --- a/spacy/tests/lang/test_attrs.py +++ b/spacy/tests/lang/test_attrs.py @@ -26,14 +26,6 @@ def test_attrs_idempotence(text): assert intify_attrs(int_attrs) == {LEMMA: 10, IS_ALPHA: True} -@pytest.mark.parametrize("text", ["dog"]) -def test_attrs_do_deprecated(text): - int_attrs = intify_attrs( - {"F": text, "is_alpha": True}, strings_map={text: 10}, _do_deprecated=True - ) - assert int_attrs == {ORTH: 10, IS_ALPHA: True} - - def test_attrs_ent_iob_intify(): int_attrs = intify_attrs({"ENT_IOB": ""}) assert int_attrs == {ENT_IOB: 0} diff --git a/spacy/tokenizer.pyx b/spacy/tokenizer.pyx index 0e75b5f7a..972633a2f 100644 --- a/spacy/tokenizer.pyx +++ b/spacy/tokenizer.pyx @@ -582,7 +582,7 @@ cdef class Tokenizer: substrings (iterable): A sequence of dicts, where each dict describes a token and its attributes. """ - attrs = [intify_attrs(spec, _do_deprecated=True) for spec in substrings] + attrs = [intify_attrs(spec) for spec in substrings] orth = "".join([spec[ORTH] for spec in attrs]) if chunk != orth: raise ValueError(Errors.E997.format(chunk=chunk, orth=orth, token_attrs=substrings)) @@ -650,7 +650,7 @@ cdef class Tokenizer: url_match = re.compile("a^").match special_cases = {} for orth, special_tokens in self.rules.items(): - special_cases[orth] = [intify_attrs(special_token, strings_map=self.vocab.strings, _do_deprecated=True) for special_token in special_tokens] + special_cases[orth] = [intify_attrs(special_token, strings_map=self.vocab.strings) for special_token in special_tokens] tokens = [] for substring in text.split(): suffixes = [] diff --git a/spacy/vocab.pyx b/spacy/vocab.pyx index 428cadd82..af7d97933 100644 --- a/spacy/vocab.pyx +++ b/spacy/vocab.pyx @@ -268,8 +268,7 @@ cdef class Vocab: cdef int i tokens = self.mem.alloc(len(substrings) + 1, sizeof(TokenC)) for i, props in enumerate(substrings): - props = intify_attrs(props, strings_map=self.strings, - _do_deprecated=True) + props = intify_attrs(props, strings_map=self.strings) token = &tokens[i] # Set the special tokens up to have arbitrary attributes lex = self.get_by_orth(self.mem, props[ORTH]) From 1a5be637150cfa10253456fba277801c711118a1 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Mon, 22 Aug 2022 15:52:24 +0200 Subject: [PATCH 008/123] Cleanup Cython structs (#11337) * cleanup Tokenizer fields * remove unused object from vocab * remove IS_OOV_DEPRECATED * add back in as FLAG13 * FLAG 18 instead * import fix * fix clumpsy fingers * revert symbol changes in favor of #11352 * bint instead of bool --- spacy/tokenizer.pxd | 6 +----- spacy/tokenizer.pyx | 9 ++++----- spacy/vocab.pxd | 1 - spacy/vocab.pyi | 1 - spacy/vocab.pyx | 7 ++----- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/spacy/tokenizer.pxd b/spacy/tokenizer.pxd index e6a072053..86e62ddbf 100644 --- a/spacy/tokenizer.pxd +++ b/spacy/tokenizer.pxd @@ -23,11 +23,7 @@ cdef class Tokenizer: cdef object _infix_finditer cdef object _rules cdef PhraseMatcher _special_matcher - # TODO convert to bool in v4 - cdef int _faster_heuristics - # TODO next one is unused and should be removed in v4 - # https://github.com/explosion/spaCy/pull/9150 - cdef int _unused_int2 + cdef bint _faster_heuristics cdef Doc _tokenize_affixes(self, str string, bint with_special_cases) cdef int _apply_special_cases(self, Doc doc) except -1 diff --git a/spacy/tokenizer.pyx b/spacy/tokenizer.pyx index 972633a2f..49ce6171a 100644 --- a/spacy/tokenizer.pyx +++ b/spacy/tokenizer.pyx @@ -8,7 +8,6 @@ from preshed.maps cimport PreshMap cimport cython import re -import warnings from .tokens.doc cimport Doc from .strings cimport hash_string @@ -16,9 +15,9 @@ from .lexeme cimport EMPTY_LEXEME from .attrs import intify_attrs from .symbols import ORTH, NORM -from .errors import Errors, Warnings +from .errors import Errors from . import util -from .util import registry, get_words_and_spaces +from .util import get_words_and_spaces from .attrs import intify_attrs from .symbols import ORTH from .scorer import Scorer @@ -128,10 +127,10 @@ cdef class Tokenizer: property faster_heuristics: def __get__(self): - return bool(self._faster_heuristics) + return self._faster_heuristics def __set__(self, faster_heuristics): - self._faster_heuristics = bool(faster_heuristics) + self._faster_heuristics = faster_heuristics self._reload_special_cases() def __reduce__(self): diff --git a/spacy/vocab.pxd b/spacy/vocab.pxd index 9c951b2b7..815de0765 100644 --- a/spacy/vocab.pxd +++ b/spacy/vocab.pxd @@ -32,7 +32,6 @@ cdef class Vocab: cdef public object writing_system cdef public object get_noun_chunks cdef readonly int length - cdef public object _unused_object # TODO remove in v4, see #9150 cdef public object lex_attr_getters cdef public object cfg diff --git a/spacy/vocab.pyi b/spacy/vocab.pyi index 4cc359c47..41964703b 100644 --- a/spacy/vocab.pyi +++ b/spacy/vocab.pyi @@ -72,7 +72,6 @@ def unpickle_vocab( sstore: StringStore, vectors: Any, morphology: Any, - _unused_object: Any, lex_attr_getters: Any, lookups: Any, get_noun_chunks: Any, diff --git a/spacy/vocab.pyx b/spacy/vocab.pyx index af7d97933..d780dec0d 100644 --- a/spacy/vocab.pyx +++ b/spacy/vocab.pyx @@ -558,21 +558,18 @@ def pickle_vocab(vocab): sstore = vocab.strings vectors = vocab.vectors morph = vocab.morphology - _unused_object = vocab._unused_object lex_attr_getters = srsly.pickle_dumps(vocab.lex_attr_getters) lookups = vocab.lookups get_noun_chunks = vocab.get_noun_chunks return (unpickle_vocab, - (sstore, vectors, morph, _unused_object, lex_attr_getters, lookups, get_noun_chunks)) + (sstore, vectors, morph, lex_attr_getters, lookups, get_noun_chunks)) -def unpickle_vocab(sstore, vectors, morphology, _unused_object, - lex_attr_getters, lookups, get_noun_chunks): +def unpickle_vocab(sstore, vectors, morphology, lex_attr_getters, lookups, get_noun_chunks): cdef Vocab vocab = Vocab() vocab.vectors = vectors vocab.strings = sstore vocab.morphology = morphology - vocab._unused_object = _unused_object vocab.lex_attr_getters = srsly.pickle_loads(lex_attr_getters) vocab.lookups = lookups vocab.get_noun_chunks = get_noun_chunks From bb0e1788781af6dcb3ff53f169e4e2d0c9330247 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Mon, 22 Aug 2022 20:28:57 +0200 Subject: [PATCH 009/123] Make Span/Doc.ents more consistent for ent_kb_id and ent_id (#11328) * Map `Span.id` to `Token.ent_id` in all cases when setting `Doc.ents` * Reset `Token.ent_id` and `Token.ent_kb_id` when setting `Doc.ents` * Make `Span.ent_id` an alias of `Span.id` rather than a read-only view of the root token's `ent_id` annotation --- spacy/tests/doc/test_add_entities.py | 27 +++++++++++++++++ spacy/tests/doc/test_span.py | 20 ++++++++++++ spacy/tokens/doc.pyx | 12 ++++++-- spacy/tokens/span.pyi | 20 +++++++----- spacy/tokens/span.pyx | 37 +++++++++++------------ website/docs/api/span.md | 4 +-- website/docs/api/token.md | 4 +-- website/docs/usage/rule-based-matching.md | 6 ++-- 8 files changed, 94 insertions(+), 36 deletions(-) diff --git a/spacy/tests/doc/test_add_entities.py b/spacy/tests/doc/test_add_entities.py index 231b7c2a8..30d66115f 100644 --- a/spacy/tests/doc/test_add_entities.py +++ b/spacy/tests/doc/test_add_entities.py @@ -45,6 +45,33 @@ def test_ents_reset(en_vocab): assert [t.ent_iob_ for t in doc] == orig_iobs +def test_ents_clear(en_vocab): + """Ensure that removing entities clears token attributes""" + text = ["Louisiana", "Office", "of", "Conservation"] + doc = Doc(en_vocab, words=text) + entity = Span(doc, 0, 4, label=391, span_id="TEST") + doc.ents = [entity] + doc.ents = [] + for token in doc: + assert token.ent_iob == 2 + assert token.ent_type == 0 + assert token.ent_id == 0 + assert token.ent_kb_id == 0 + doc.ents = [entity] + doc.set_ents([], default="missing") + for token in doc: + assert token.ent_iob == 0 + assert token.ent_type == 0 + assert token.ent_id == 0 + assert token.ent_kb_id == 0 + doc.set_ents([], default="blocked") + for token in doc: + assert token.ent_iob == 3 + assert token.ent_type == 0 + assert token.ent_id == 0 + assert token.ent_kb_id == 0 + + def test_add_overlapping_entities(en_vocab): text = ["Louisiana", "Office", "of", "Conservation"] doc = Doc(en_vocab, words=text) diff --git a/spacy/tests/doc/test_span.py b/spacy/tests/doc/test_span.py index c6303c52d..1a2f3cdcd 100644 --- a/spacy/tests/doc/test_span.py +++ b/spacy/tests/doc/test_span.py @@ -692,3 +692,23 @@ def test_span_group_copy(doc): assert len(doc.spans["test"]) == 3 # check that the copy spans were not modified and this is an isolated doc assert len(doc_copy.spans["test"]) == 2 + + +@pytest.mark.issue(11113) +def test_span_ent_id(en_tokenizer): + doc = en_tokenizer("a b c d") + doc.ents = [Span(doc, 1, 3, label="A", span_id="ID0")] + span = doc.ents[0] + assert doc[1].ent_id_ == "ID0" + + # setting Span.id sets Token.ent_id + span.id_ = "ID1" + doc.ents = [span] + assert doc.ents[0].ent_id_ == "ID1" + assert doc[1].ent_id_ == "ID1" + + # Span.ent_id is an alias of Span.id + span.ent_id_ = "ID2" + doc.ents = [span] + assert doc.ents[0].ent_id_ == "ID2" + assert doc[1].ent_id_ == "ID2" diff --git a/spacy/tokens/doc.pyx b/spacy/tokens/doc.pyx index d9a104ac8..8432f7c60 100644 --- a/spacy/tokens/doc.pyx +++ b/spacy/tokens/doc.pyx @@ -808,27 +808,33 @@ cdef class Doc: self.c[i].ent_iob = 1 self.c[i].ent_type = span.label self.c[i].ent_kb_id = span.kb_id - # for backwards compatibility in v3, only set ent_id from - # span.id if it's set, otherwise don't override - self.c[i].ent_id = span.id if span.id else self.c[i].ent_id + self.c[i].ent_id = span.id for span in blocked: for i in range(span.start, span.end): self.c[i].ent_iob = 3 self.c[i].ent_type = 0 + self.c[i].ent_kb_id = 0 + self.c[i].ent_id = 0 for span in missing: for i in range(span.start, span.end): self.c[i].ent_iob = 0 self.c[i].ent_type = 0 + self.c[i].ent_kb_id = 0 + self.c[i].ent_id = 0 for span in outside: for i in range(span.start, span.end): self.c[i].ent_iob = 2 self.c[i].ent_type = 0 + self.c[i].ent_kb_id = 0 + self.c[i].ent_id = 0 # Set tokens outside of all provided spans if default != SetEntsDefault.unmodified: for i in range(self.length): if i not in seen_tokens: self.c[i].ent_type = 0 + self.c[i].ent_kb_id = 0 + self.c[i].ent_id = 0 if default == SetEntsDefault.outside: self.c[i].ent_iob = 2 elif default == SetEntsDefault.missing: diff --git a/spacy/tokens/span.pyi b/spacy/tokens/span.pyi index 617e3d19d..28b627c32 100644 --- a/spacy/tokens/span.pyi +++ b/spacy/tokens/span.pyi @@ -115,17 +115,23 @@ class Span: end: int start_char: int end_char: int - label: int - kb_id: int - ent_id: int - ent_id_: str + @property + def label(self) -> int: ... + @property + def kb_id(self) -> int: ... @property def id(self) -> int: ... @property - def id_(self) -> str: ... + def ent_id(self) -> int: ... @property def orth_(self) -> str: ... @property def lemma_(self) -> str: ... - label_: str - kb_id_: str + @property + def label_(self) -> str: ... + @property + def kb_id_(self) -> str: ... + @property + def id_(self) -> str: ... + @property + def ent_id_(self) -> str: ... diff --git a/spacy/tokens/span.pyx b/spacy/tokens/span.pyx index dd6ba99a8..89d9727e9 100644 --- a/spacy/tokens/span.pyx +++ b/spacy/tokens/span.pyx @@ -802,28 +802,18 @@ cdef class Span: property id: def __get__(self): - cdef SpanC* span_c = self.span_c() - return span_c.id + return self.span_c().id def __set__(self, attr_t id): - cdef SpanC* span_c = self.span_c() - span_c.id = id + self.span_c().id = id property ent_id: - """RETURNS (uint64): The entity ID.""" + """Alias for the span's ID.""" def __get__(self): - return self.root.ent_id + return self.id - def __set__(self, hash_t key): - raise NotImplementedError(Errors.E200.format(attr="ent_id")) - - property ent_id_: - """RETURNS (str): The (string) entity ID.""" - def __get__(self): - return self.root.ent_id_ - - def __set__(self, str key): - raise NotImplementedError(Errors.E200.format(attr="ent_id_")) + def __set__(self, attr_t ent_id): + self.id = ent_id @property def orth_(self): @@ -839,7 +829,7 @@ cdef class Span: return "".join([t.lemma_ + t.whitespace_ for t in self]).strip() property label_: - """RETURNS (str): The span's label.""" + """The span's label.""" def __get__(self): return self.doc.vocab.strings[self.label] @@ -847,7 +837,7 @@ cdef class Span: self.label = self.doc.vocab.strings.add(label_) property kb_id_: - """RETURNS (str): The span's KB ID.""" + """The span's KB ID.""" def __get__(self): return self.doc.vocab.strings[self.kb_id] @@ -855,13 +845,22 @@ cdef class Span: self.kb_id = self.doc.vocab.strings.add(kb_id_) property id_: - """RETURNS (str): The span's ID.""" + """The span's ID.""" def __get__(self): return self.doc.vocab.strings[self.id] def __set__(self, str id_): self.id = self.doc.vocab.strings.add(id_) + property ent_id_: + """Alias for the span's ID.""" + def __get__(self): + return self.id_ + + def __set__(self, str ent_id_): + self.id_ = ent_id_ + + cdef int _count_words_to_root(const TokenC* token, int sent_length) except -1: # Don't allow spaces to be the root, if there are diff --git a/website/docs/api/span.md b/website/docs/api/span.md index 89f608994..be522c31f 100644 --- a/website/docs/api/span.md +++ b/website/docs/api/span.md @@ -561,8 +561,8 @@ overlaps with will be returned. | `lemma_` | The span's lemma. Equivalent to `"".join(token.text_with_ws for token in span)`. ~~str~~ | | `kb_id` | The hash value of the knowledge base ID referred to by the span. ~~int~~ | | `kb_id_` | The knowledge base ID referred to by the span. ~~str~~ | -| `ent_id` | The hash value of the named entity the root token is an instance of. ~~int~~ | -| `ent_id_` | The string ID of the named entity the root token is an instance of. ~~str~~ | +| `ent_id` | Alias for `id`: the hash value of the span's ID. ~~int~~ | +| `ent_id_` | Alias for `id_`: the span's ID. ~~str~~ | | `id` | The hash value of the span's ID. ~~int~~ | | `id_` | The span's ID. ~~str~~ | | `sentiment` | A scalar value indicating the positivity or negativity of the span. ~~float~~ | diff --git a/website/docs/api/token.md b/website/docs/api/token.md index d43cd3ff1..73447e4d3 100644 --- a/website/docs/api/token.md +++ b/website/docs/api/token.md @@ -425,8 +425,8 @@ The L2 norm of the token's vector representation. | `ent_iob_` | IOB code of named entity tag. "B" means the token begins an entity, "I" means it is inside an entity, "O" means it is outside an entity, and "" means no entity tag is set. ~~str~~ | | `ent_kb_id` 2.2 | Knowledge base ID that refers to the named entity this token is a part of, if any. ~~int~~ | | `ent_kb_id_` 2.2 | Knowledge base ID that refers to the named entity this token is a part of, if any. ~~str~~ | -| `ent_id` | ID of the entity the token is an instance of, if any. Currently not used, but potentially for coreference resolution. ~~int~~ | -| `ent_id_` | ID of the entity the token is an instance of, if any. Currently not used, but potentially for coreference resolution. ~~str~~ | +| `ent_id` | ID of the entity the token is an instance of, if any. ~~int~~ | +| `ent_id_` | ID of the entity the token is an instance of, if any. ~~str~~ | | `lemma` | Base form of the token, with no inflectional suffixes. ~~int~~ | | `lemma_` | Base form of the token, with no inflectional suffixes. ~~str~~ | | `norm` | The token's norm, i.e. a normalized form of the token text. Can be set in the language's [tokenizer exceptions](/usage/linguistic-features#language-data). ~~int~~ | diff --git a/website/docs/usage/rule-based-matching.md b/website/docs/usage/rule-based-matching.md index f096890cb..bf1891df1 100644 --- a/website/docs/usage/rule-based-matching.md +++ b/website/docs/usage/rule-based-matching.md @@ -1367,14 +1367,14 @@ patterns = [{"label": "ORG", "pattern": "Apple", "id": "apple"}, ruler.add_patterns(patterns) doc1 = nlp("Apple is opening its first big office in San Francisco.") -print([(ent.text, ent.label_, ent.ent_id_) for ent in doc1.ents]) +print([(ent.text, ent.label_, ent.id_) for ent in doc1.ents]) doc2 = nlp("Apple is opening its first big office in San Fran.") -print([(ent.text, ent.label_, ent.ent_id_) for ent in doc2.ents]) +print([(ent.text, ent.label_, ent.id_) for ent in doc2.ents]) ``` If the `id` attribute is included in the [`EntityRuler`](/api/entityruler) -patterns, the `ent_id_` property of the matched entity is set to the `id` given +patterns, the `id_` property of the matched entity is set to the `id` given in the patterns. So in the example above it's easy to identify that "San Francisco" and "San Fran" are both the same entity. From 2a558a7cdcdaf817228154754c93b79642dc2bcd Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Fri, 26 Aug 2022 10:11:18 +0200 Subject: [PATCH 010/123] Switch to mecab-ko as default Korean tokenizer (#11294) * Switch to mecab-ko as default Korean tokenizer Switch to the (confusingly-named) mecab-ko python module for default Korean tokenization. Maintain the previous `natto-py` tokenizer as `spacy.KoreanNattoTokenizer.v1`. * Temporarily run tests with mecab-ko tokenizer * Fix types * Fix duplicate test names * Update requirements test * Revert "Temporarily run tests with mecab-ko tokenizer" This reverts commit d2083e7044403a2046f902b125a147525b703e29. * Add mecab_args setting, fix pickle for KoreanNattoTokenizer * Fix length check * Update docs * Formatting * Update natto-py error message Co-authored-by: Paul O'Leary McCann Co-authored-by: Paul O'Leary McCann --- setup.cfg | 2 +- spacy/lang/ko/__init__.py | 121 +++++++++++++++++----- spacy/tests/conftest.py | 16 ++- spacy/tests/lang/ko/test_lemmatization.py | 8 ++ spacy/tests/lang/ko/test_serialize.py | 20 ++++ spacy/tests/lang/ko/test_tokenizer.py | 42 +++++++- spacy/tests/package/test_requirements.py | 2 +- website/docs/usage/models.md | 35 ++++++- 8 files changed, 212 insertions(+), 34 deletions(-) diff --git a/setup.cfg b/setup.cfg index 708300b04..8bce8cff2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -114,7 +114,7 @@ ja = sudachipy>=0.5.2,!=0.6.1 sudachidict_core>=20211220 ko = - natto-py>=0.9.0 + mecab-ko>=1.0.0 th = pythainlp>=2.0 diff --git a/spacy/lang/ko/__init__.py b/spacy/lang/ko/__init__.py index 0e02e4a2d..1220aa141 100644 --- a/spacy/lang/ko/__init__.py +++ b/spacy/lang/ko/__init__.py @@ -18,34 +18,23 @@ DEFAULT_CONFIG = """ [nlp.tokenizer] @tokenizers = "spacy.ko.KoreanTokenizer" +mecab_args = "" """ @registry.tokenizers("spacy.ko.KoreanTokenizer") -def create_tokenizer(): +def create_tokenizer(mecab_args: str): def korean_tokenizer_factory(nlp): - return KoreanTokenizer(nlp.vocab) + return KoreanTokenizer(nlp.vocab, mecab_args=mecab_args) return korean_tokenizer_factory class KoreanTokenizer(DummyTokenizer): - def __init__(self, vocab: Vocab): + def __init__(self, vocab: Vocab, *, mecab_args: str = ""): self.vocab = vocab - self._mecab = try_mecab_import() # type: ignore[func-returns-value] - self._mecab_tokenizer = None - - @property - def mecab_tokenizer(self): - # This is a property so that initializing a pipeline with blank:ko is - # possible without actually requiring mecab-ko, e.g. to run - # `spacy init vectors ko` for a pipeline that will have a different - # tokenizer in the end. The languages need to match for the vectors - # to be imported and there's no way to pass a custom config to - # `init vectors`. - if self._mecab_tokenizer is None: - self._mecab_tokenizer = self._mecab("-F%f[0],%f[7]") - return self._mecab_tokenizer + mecab = try_mecab_import() + self.mecab_tokenizer = mecab.Tagger(mecab_args) def __reduce__(self): return KoreanTokenizer, (self.vocab,) @@ -68,13 +57,15 @@ class KoreanTokenizer(DummyTokenizer): def detailed_tokens(self, text: str) -> Iterator[Dict[str, Any]]: # 품사 태그(POS)[0], 의미 부류(semantic class)[1], 종성 유무(jongseong)[2], 읽기(reading)[3], # 타입(type)[4], 첫번째 품사(start pos)[5], 마지막 품사(end pos)[6], 표현(expression)[7], * - for node in self.mecab_tokenizer.parse(text, as_nodes=True): - if node.is_eos(): + for line in self.mecab_tokenizer.parse(text).split("\n"): + if line == "EOS": break - surface = node.surface - feature = node.feature - tag, _, expr = feature.partition(",") - lemma, _, remainder = expr.partition("/") + surface, _, expr = line.partition("\t") + features = expr.split("/")[0].split(",") + tag = features[0] + lemma = "*" + if len(features) >= 8: + lemma = features[7] if lemma == "*": lemma = surface yield {"surface": surface, "lemma": lemma, "tag": tag} @@ -97,20 +88,94 @@ class Korean(Language): Defaults = KoreanDefaults -def try_mecab_import() -> None: +def try_mecab_import(): try: - from natto import MeCab + import mecab_ko as MeCab return MeCab except ImportError: raise ImportError( 'The Korean tokenizer ("spacy.ko.KoreanTokenizer") requires ' - "[mecab-ko](https://bitbucket.org/eunjeon/mecab-ko/src/master/README.md), " - "[mecab-ko-dic](https://bitbucket.org/eunjeon/mecab-ko-dic), " - "and [natto-py](https://github.com/buruzaemon/natto-py)" + "the python package `mecab-ko`: pip install mecab-ko" ) from None +@registry.tokenizers("spacy.KoreanNattoTokenizer.v1") +def create_natto_tokenizer(): + def korean_natto_tokenizer_factory(nlp): + return KoreanNattoTokenizer(nlp.vocab) + + return korean_natto_tokenizer_factory + + +class KoreanNattoTokenizer(DummyTokenizer): + def __init__(self, vocab: Vocab): + self.vocab = vocab + self._mecab = self._try_mecab_import() # type: ignore[func-returns-value] + self._mecab_tokenizer = None + + @property + def mecab_tokenizer(self): + # This is a property so that initializing a pipeline with blank:ko is + # possible without actually requiring mecab-ko, e.g. to run + # `spacy init vectors ko` for a pipeline that will have a different + # tokenizer in the end. The languages need to match for the vectors + # to be imported and there's no way to pass a custom config to + # `init vectors`. + if self._mecab_tokenizer is None: + self._mecab_tokenizer = self._mecab("-F%f[0],%f[7]") + return self._mecab_tokenizer + + def __reduce__(self): + return KoreanNattoTokenizer, (self.vocab,) + + def __call__(self, text: str) -> Doc: + dtokens = list(self.detailed_tokens(text)) + surfaces = [dt["surface"] for dt in dtokens] + doc = Doc(self.vocab, words=surfaces, spaces=list(check_spaces(text, surfaces))) + for token, dtoken in zip(doc, dtokens): + first_tag, sep, eomi_tags = dtoken["tag"].partition("+") + token.tag_ = first_tag # stem(어간) or pre-final(선어말 어미) + if token.tag_ in TAG_MAP: + token.pos = TAG_MAP[token.tag_][POS] + else: + token.pos = X + token.lemma_ = dtoken["lemma"] + doc.user_data["full_tags"] = [dt["tag"] for dt in dtokens] + return doc + + def detailed_tokens(self, text: str) -> Iterator[Dict[str, Any]]: + # 품사 태그(POS)[0], 의미 부류(semantic class)[1], 종성 유무(jongseong)[2], 읽기(reading)[3], + # 타입(type)[4], 첫번째 품사(start pos)[5], 마지막 품사(end pos)[6], 표현(expression)[7], * + for node in self.mecab_tokenizer.parse(text, as_nodes=True): + if node.is_eos(): + break + surface = node.surface + feature = node.feature + tag, _, expr = feature.partition(",") + lemma, _, remainder = expr.partition("/") + if lemma == "*" or lemma == "": + lemma = surface + yield {"surface": surface, "lemma": lemma, "tag": tag} + + def score(self, examples): + validate_examples(examples, "KoreanTokenizer.score") + return Scorer.score_tokenization(examples) + + def _try_mecab_import(self): + try: + from natto import MeCab + + return MeCab + except ImportError: + raise ImportError( + 'The Korean Natto tokenizer ("spacy.ko.KoreanNattoTokenizer") requires ' + "[mecab-ko](https://bitbucket.org/eunjeon/mecab-ko/src/master/README.md), " + "[mecab-ko-dic](https://bitbucket.org/eunjeon/mecab-ko-dic), " + "and [natto-py](https://github.com/buruzaemon/natto-py)" + ) from None + + def check_spaces(text, tokens): prev_end = -1 start = 0 diff --git a/spacy/tests/conftest.py b/spacy/tests/conftest.py index e70fcd6dd..92810118a 100644 --- a/spacy/tests/conftest.py +++ b/spacy/tests/conftest.py @@ -239,7 +239,7 @@ def hsb_tokenizer(): @pytest.fixture(scope="session") def ko_tokenizer(): - pytest.importorskip("natto") + pytest.importorskip("mecab_ko") return get_lang_class("ko")().tokenizer @@ -256,6 +256,20 @@ def ko_tokenizer_tokenizer(): return nlp.tokenizer +@pytest.fixture(scope="session") +def ko_tokenizer_natto(): + pytest.importorskip("natto") + config = { + "nlp": { + "tokenizer": { + "@tokenizers": "spacy.KoreanNattoTokenizer.v1", + } + } + } + nlp = get_lang_class("ko").from_config(config) + return nlp.tokenizer + + @pytest.fixture(scope="session") def lb_tokenizer(): return get_lang_class("lb")().tokenizer diff --git a/spacy/tests/lang/ko/test_lemmatization.py b/spacy/tests/lang/ko/test_lemmatization.py index 7782ca4bc..0c389b9ce 100644 --- a/spacy/tests/lang/ko/test_lemmatization.py +++ b/spacy/tests/lang/ko/test_lemmatization.py @@ -7,3 +7,11 @@ import pytest def test_ko_lemmatizer_assigns(ko_tokenizer, word, lemma): test_lemma = ko_tokenizer(word)[0].lemma_ assert test_lemma == lemma + + +@pytest.mark.parametrize( + "word,lemma", [("새로운", "새롭"), ("빨간", "빨갛"), ("클수록", "크"), ("뭡니까", "뭣"), ("됐다", "되")] +) +def test_ko_lemmatizer_natto_assigns(ko_tokenizer_natto, word, lemma): + test_lemma = ko_tokenizer_natto(word)[0].lemma_ + assert test_lemma == lemma diff --git a/spacy/tests/lang/ko/test_serialize.py b/spacy/tests/lang/ko/test_serialize.py index 75288fcc5..35d28d42a 100644 --- a/spacy/tests/lang/ko/test_serialize.py +++ b/spacy/tests/lang/ko/test_serialize.py @@ -22,3 +22,23 @@ def test_ko_tokenizer_pickle(ko_tokenizer): b = pickle.dumps(ko_tokenizer) ko_tokenizer_re = pickle.loads(b) assert ko_tokenizer.to_bytes() == ko_tokenizer_re.to_bytes() + + +def test_ko_tokenizer_natto_serialize(ko_tokenizer_natto): + tokenizer_bytes = ko_tokenizer_natto.to_bytes() + nlp = Korean() + nlp.tokenizer.from_bytes(tokenizer_bytes) + assert tokenizer_bytes == nlp.tokenizer.to_bytes() + + with make_tempdir() as d: + file_path = d / "tokenizer" + ko_tokenizer_natto.to_disk(file_path) + nlp = Korean() + nlp.tokenizer.from_disk(file_path) + assert tokenizer_bytes == nlp.tokenizer.to_bytes() + + +def test_ko_tokenizer_natto_pickle(ko_tokenizer_natto): + b = pickle.dumps(ko_tokenizer_natto) + ko_tokenizer_natto_re = pickle.loads(b) + assert ko_tokenizer_natto.to_bytes() == ko_tokenizer_natto_re.to_bytes() diff --git a/spacy/tests/lang/ko/test_tokenizer.py b/spacy/tests/lang/ko/test_tokenizer.py index 6e06e405e..e7f8a5c0d 100644 --- a/spacy/tests/lang/ko/test_tokenizer.py +++ b/spacy/tests/lang/ko/test_tokenizer.py @@ -19,6 +19,8 @@ POS_TESTS = [("서울 타워 근처에 살고 있습니다.", "PROPN ADP VERB X NOUN ADV VERB AUX X PUNCT")] # fmt: on +# tests for ko_tokenizer (default KoreanTokenizer) + @pytest.mark.parametrize("text,expected_tokens", TOKENIZER_TESTS) def test_ko_tokenizer(ko_tokenizer, text, expected_tokens): @@ -44,7 +46,7 @@ def test_ko_tokenizer_pos(ko_tokenizer, text, expected_pos): assert pos == expected_pos.split() -def test_ko_empty_doc(ko_tokenizer): +def test_ko_tokenizer_empty_doc(ko_tokenizer): tokens = ko_tokenizer("") assert len(tokens) == 0 @@ -55,6 +57,44 @@ def test_ko_tokenizer_unknown_tag(ko_tokenizer): assert tokens[1].pos_ == "X" +# same tests for ko_tokenizer_natto (KoreanNattoTokenizer) + + +@pytest.mark.parametrize("text,expected_tokens", TOKENIZER_TESTS) +def test_ko_tokenizer_natto(ko_tokenizer_natto, text, expected_tokens): + tokens = [token.text for token in ko_tokenizer_natto(text)] + assert tokens == expected_tokens.split() + + +@pytest.mark.parametrize("text,expected_tags", TAG_TESTS) +def test_ko_tokenizer_natto_tags(ko_tokenizer_natto, text, expected_tags): + tags = [token.tag_ for token in ko_tokenizer_natto(text)] + assert tags == expected_tags.split() + + +@pytest.mark.parametrize("text,expected_tags", FULL_TAG_TESTS) +def test_ko_tokenizer_natto_full_tags(ko_tokenizer_natto, text, expected_tags): + tags = ko_tokenizer_natto(text).user_data["full_tags"] + assert tags == expected_tags.split() + + +@pytest.mark.parametrize("text,expected_pos", POS_TESTS) +def test_ko_tokenizer_natto_pos(ko_tokenizer_natto, text, expected_pos): + pos = [token.pos_ for token in ko_tokenizer_natto(text)] + assert pos == expected_pos.split() + + +def test_ko_tokenizer_natto_empty_doc(ko_tokenizer_natto): + tokens = ko_tokenizer_natto("") + assert len(tokens) == 0 + + +@pytest.mark.issue(10535) +def test_ko_tokenizer_natto_unknown_tag(ko_tokenizer_natto): + tokens = ko_tokenizer_natto("미닛 리피터") + assert tokens[1].pos_ == "X" + + # fmt: off SPACY_TOKENIZER_TESTS = [ ("있다.", "있다 ."), diff --git a/spacy/tests/package/test_requirements.py b/spacy/tests/package/test_requirements.py index e20227455..c0b9d4dc6 100644 --- a/spacy/tests/package/test_requirements.py +++ b/spacy/tests/package/test_requirements.py @@ -21,7 +21,7 @@ def test_build_dependencies(): # ignore language-specific packages that shouldn't be installed by all libs_ignore_setup = [ "fugashi", - "natto-py", + "mecab-ko", "pythainlp", "sudachipy", "sudachidict_core", diff --git a/website/docs/usage/models.md b/website/docs/usage/models.md index 56992e7e3..a2bf72d02 100644 --- a/website/docs/usage/models.md +++ b/website/docs/usage/models.md @@ -268,18 +268,49 @@ used for training the current [Japanese pipelines](/models/ja). ### Korean language support {#korean} -> #### mecab-ko tokenizer +There are currently three built-in options for Korean tokenization, two based on +[mecab-ko](https://bitbucket.org/eunjeon/mecab-ko/src/master/README.md) and one +using the rule-based tokenizer. + +> #### Default mecab-ko tokenizer > > ```python +> # uses mecab-ko-dic > nlp = spacy.blank("ko") +> +> # with custom mecab args +> mecab_args = "-d /path/to/dicdir -u /path/to/userdic" +> config = {"nlp": {"tokenizer": {"mecab_args": mecab_args}}} +> nlp = spacy.blank("ko", config=config) > ``` -The default MeCab-based Korean tokenizer requires: +The default MeCab-based Korean tokenizer requires the python package +[`mecab-ko`](https://pypi.org/project/mecab-ko/) and no further system +requirements. + +The `natto-py` MeCab-based tokenizer (the previous default for spaCy v3.4 and +earlier) is available as `spacy.KoreanNattoTokenizer.v1`. It requires: - [mecab-ko](https://bitbucket.org/eunjeon/mecab-ko/src/master/README.md) - [mecab-ko-dic](https://bitbucket.org/eunjeon/mecab-ko-dic) - [natto-py](https://github.com/buruzaemon/natto-py) +To use this tokenizer, edit `[nlp.tokenizer]` in your config: + +> #### natto-py MeCab-ko tokenizer +> +> ```python +> config = {"nlp": {"tokenizer": {"@tokenizers": "spacy.KoreanNattoTokenizer.v1"}}} +> nlp = spacy.blank("ko", config=config) +> ``` + +```ini +### config.cfg +[nlp] +lang = "ko" +tokenizer = {"@tokenizers" = "spacy.KoreanNattoTokenizer.v1"} +``` + For some Korean datasets and tasks, the [rule-based tokenizer](/usage/linguistic-features#tokenization) is better-suited than MeCab. To configure a Korean pipeline with the rule-based tokenizer: From 4bce8fa7557d86d61347da501fe2f62424f7d44c Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Mon, 29 Aug 2022 13:23:24 +0200 Subject: [PATCH 011/123] Remove setup_requires from setup.cfg (#11384) * Remove setup_requires from setup.cfg * Update requirements test to ignore cython in setup.cfg --- setup.cfg | 8 -------- spacy/tests/package/test_requirements.py | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/setup.cfg b/setup.cfg index 8bce8cff2..41172a339 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,14 +31,6 @@ project_urls = zip_safe = false include_package_data = true python_requires = >=3.6 -setup_requires = - cython>=0.25,<3.0 - numpy>=1.15.0 - # We also need our Cython packages here to compile against - cymem>=2.0.2,<2.1.0 - preshed>=3.0.2,<3.1.0 - murmurhash>=0.28.0,<1.1.0 - thinc>=8.1.0,<8.2.0 install_requires = # Our libraries spacy-legacy>=3.0.9,<3.1.0 diff --git a/spacy/tests/package/test_requirements.py b/spacy/tests/package/test_requirements.py index c0b9d4dc6..4e2a1c7e7 100644 --- a/spacy/tests/package/test_requirements.py +++ b/spacy/tests/package/test_requirements.py @@ -4,8 +4,8 @@ from pathlib import Path def test_build_dependencies(): # Check that library requirements are pinned exactly the same across different setup files. - # TODO: correct checks for numpy rather than ignoring libs_ignore_requirements = [ + "cython", "pytest", "pytest-timeout", "mock", From 98a916e01aa4b7e87feb9893c8874ecf322fb4a2 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Tue, 30 Aug 2022 13:56:35 +0200 Subject: [PATCH 012/123] Make stable private modules public and adjust names (#11353) * Make stable private modules public and adjust names * `spacy.ml._character_embed` -> `spacy.ml.character_embed` * `spacy.ml._precomputable_affine` -> `spacy.ml.precomputable_affine` * `spacy.tokens._serialize` -> `spacy.tokens.doc_bin` * `spacy.tokens._retokenize` -> `spacy.tokens.retokenize` * `spacy.tokens._dict_proxies` -> `spacy.tokens.span_groups` * Skip _precomputable_affine * retokenize -> retokenizer * Fix imports --- setup.py | 2 +- spacy/ml/{_character_embed.py => character_embed.py} | 0 spacy/ml/models/tok2vec.py | 4 ++-- spacy/pipeline/attribute_ruler.py | 2 +- spacy/tests/pipeline/test_models.py | 2 +- spacy/tests/pipeline/test_spancat.py | 2 +- spacy/tests/serialize/test_serialize_span_groups.py | 2 +- spacy/tokens/__init__.py | 2 +- spacy/tokens/doc.pyi | 4 ++-- spacy/tokens/doc.pyx | 6 +++--- spacy/tokens/{_serialize.py => doc_bin.py} | 2 +- spacy/tokens/{_retokenize.pyi => retokenizer.pyi} | 0 spacy/tokens/{_retokenize.pyx => retokenizer.pyx} | 0 spacy/tokens/{_dict_proxies.py => span_groups.py} | 0 14 files changed, 14 insertions(+), 14 deletions(-) rename spacy/ml/{_character_embed.py => character_embed.py} (100%) rename spacy/tokens/{_serialize.py => doc_bin.py} (99%) rename spacy/tokens/{_retokenize.pyi => retokenizer.pyi} (100%) rename spacy/tokens/{_retokenize.pyx => retokenizer.pyx} (100%) rename spacy/tokens/{_dict_proxies.py => span_groups.py} (100%) diff --git a/setup.py b/setup.py index ec1bd35fa..8e0ef93d4 100755 --- a/setup.py +++ b/setup.py @@ -60,7 +60,7 @@ MOD_NAMES = [ "spacy.tokens.span_group", "spacy.tokens.graph", "spacy.tokens.morphanalysis", - "spacy.tokens._retokenize", + "spacy.tokens.retokenizer", "spacy.matcher.matcher", "spacy.matcher.phrasematcher", "spacy.matcher.dependencymatcher", diff --git a/spacy/ml/_character_embed.py b/spacy/ml/character_embed.py similarity index 100% rename from spacy/ml/_character_embed.py rename to spacy/ml/character_embed.py diff --git a/spacy/ml/models/tok2vec.py b/spacy/ml/models/tok2vec.py index 30c7360ff..79772ad80 100644 --- a/spacy/ml/models/tok2vec.py +++ b/spacy/ml/models/tok2vec.py @@ -7,7 +7,7 @@ from thinc.api import expand_window, residual, Maxout, Mish, PyTorchLSTM from ...tokens import Doc from ...util import registry from ...errors import Errors -from ...ml import _character_embed +from ...ml import character_embed from ..staticvectors import StaticVectors from ..featureextractor import FeatureExtractor from ...pipeline.tok2vec import Tok2VecListener @@ -226,7 +226,7 @@ def CharacterEmbed( if feature is None: raise ValueError(Errors.E911.format(feat=feature)) char_embed = chain( - _character_embed.CharacterEmbed(nM=nM, nC=nC), + character_embed.CharacterEmbed(nM=nM, nC=nC), cast(Model[List[Floats2d], Ragged], list2ragged()), ) feature_extractor: Model[List[Doc], Ragged] = chain( diff --git a/spacy/pipeline/attribute_ruler.py b/spacy/pipeline/attribute_ruler.py index 0d9494865..ac998a61d 100644 --- a/spacy/pipeline/attribute_ruler.py +++ b/spacy/pipeline/attribute_ruler.py @@ -11,7 +11,7 @@ from ..matcher import Matcher from ..scorer import Scorer from ..symbols import IDS from ..tokens import Doc, Span -from ..tokens._retokenize import normalize_token_attrs, set_token_attrs +from ..tokens.retokenizer import normalize_token_attrs, set_token_attrs from ..vocab import Vocab from ..util import SimpleFrozenList, registry from .. import util diff --git a/spacy/tests/pipeline/test_models.py b/spacy/tests/pipeline/test_models.py index e3fd28d0f..50ad94422 100644 --- a/spacy/tests/pipeline/test_models.py +++ b/spacy/tests/pipeline/test_models.py @@ -9,7 +9,7 @@ from thinc.types import Array2d, Ragged from spacy.lang.en import English from spacy.ml import FeatureExtractor, StaticVectors -from spacy.ml._character_embed import CharacterEmbed +from spacy.ml.character_embed import CharacterEmbed from spacy.tokens import Doc diff --git a/spacy/tests/pipeline/test_spancat.py b/spacy/tests/pipeline/test_spancat.py index 15256a763..95e9aeb57 100644 --- a/spacy/tests/pipeline/test_spancat.py +++ b/spacy/tests/pipeline/test_spancat.py @@ -7,7 +7,7 @@ from spacy import util from spacy.lang.en import English from spacy.language import Language from spacy.tokens import SpanGroup -from spacy.tokens._dict_proxies import SpanGroups +from spacy.tokens.span_groups import SpanGroups from spacy.training import Example from spacy.util import fix_random_seed, registry, make_tempdir diff --git a/spacy/tests/serialize/test_serialize_span_groups.py b/spacy/tests/serialize/test_serialize_span_groups.py index 85313fcdc..c1c910fa1 100644 --- a/spacy/tests/serialize/test_serialize_span_groups.py +++ b/spacy/tests/serialize/test_serialize_span_groups.py @@ -1,7 +1,7 @@ import pytest from spacy.tokens import Span, SpanGroup -from spacy.tokens._dict_proxies import SpanGroups +from spacy.tokens.span_groups import SpanGroups @pytest.mark.issue(10685) diff --git a/spacy/tokens/__init__.py b/spacy/tokens/__init__.py index 64090925d..cb0911283 100644 --- a/spacy/tokens/__init__.py +++ b/spacy/tokens/__init__.py @@ -2,7 +2,7 @@ from .doc import Doc from .token import Token from .span import Span from .span_group import SpanGroup -from ._serialize import DocBin +from .doc_bin import DocBin from .morphanalysis import MorphAnalysis __all__ = ["Doc", "Token", "Span", "SpanGroup", "DocBin", "MorphAnalysis"] diff --git a/spacy/tokens/doc.pyi b/spacy/tokens/doc.pyi index a40fa74aa..ae1324a8a 100644 --- a/spacy/tokens/doc.pyi +++ b/spacy/tokens/doc.pyi @@ -4,8 +4,8 @@ from cymem.cymem import Pool from thinc.types import Floats1d, Floats2d, Ints2d from .span import Span from .token import Token -from ._dict_proxies import SpanGroups -from ._retokenize import Retokenizer +from .span_groups import SpanGroups +from .retokenizer import Retokenizer from ..lexeme import Lexeme from ..vocab import Vocab from .underscore import Underscore diff --git a/spacy/tokens/doc.pyx b/spacy/tokens/doc.pyx index 3c69b6ad8..2956f357c 100644 --- a/spacy/tokens/doc.pyx +++ b/spacy/tokens/doc.pyx @@ -19,7 +19,7 @@ import warnings from .span cimport Span from .token cimport MISSING_DEP -from ._dict_proxies import SpanGroups +from .span_groups import SpanGroups from .token cimport Token from ..lexeme cimport Lexeme, EMPTY_LEXEME from ..typedefs cimport attr_t, flags_t @@ -35,8 +35,8 @@ from .. import util from .. import parts_of_speech from .. import schemas from .underscore import Underscore, get_ext_args -from ._retokenize import Retokenizer -from ._serialize import ALL_ATTRS as DOCBIN_ALL_ATTRS +from .retokenizer import Retokenizer +from .doc_bin import ALL_ATTRS as DOCBIN_ALL_ATTRS from ..util import get_words_and_spaces DEF PADDING = 5 diff --git a/spacy/tokens/_serialize.py b/spacy/tokens/doc_bin.py similarity index 99% rename from spacy/tokens/_serialize.py rename to spacy/tokens/doc_bin.py index c4e8f26f4..c107aa25d 100644 --- a/spacy/tokens/_serialize.py +++ b/spacy/tokens/doc_bin.py @@ -12,7 +12,7 @@ from ..compat import copy_reg from ..attrs import SPACY, ORTH, intify_attr, IDS from ..errors import Errors from ..util import ensure_path, SimpleFrozenList -from ._dict_proxies import SpanGroups +from .span_groups import SpanGroups # fmt: off ALL_ATTRS = ("ORTH", "NORM", "TAG", "HEAD", "DEP", "ENT_IOB", "ENT_TYPE", "ENT_KB_ID", "ENT_ID", "LEMMA", "MORPH", "POS", "SENT_START") diff --git a/spacy/tokens/_retokenize.pyi b/spacy/tokens/retokenizer.pyi similarity index 100% rename from spacy/tokens/_retokenize.pyi rename to spacy/tokens/retokenizer.pyi diff --git a/spacy/tokens/_retokenize.pyx b/spacy/tokens/retokenizer.pyx similarity index 100% rename from spacy/tokens/_retokenize.pyx rename to spacy/tokens/retokenizer.pyx diff --git a/spacy/tokens/_dict_proxies.py b/spacy/tokens/span_groups.py similarity index 100% rename from spacy/tokens/_dict_proxies.py rename to spacy/tokens/span_groups.py From 698b8b495f1baf2e30e2f622f4725c047feb03d1 Mon Sep 17 00:00:00 2001 From: Paul O'Leary McCann Date: Tue, 30 Aug 2022 22:40:31 +0900 Subject: [PATCH 013/123] Update/remove old Matcher syntax (#11370) * Clean up old Matcher call style related stuff In v2 Matcher.add was called with (key, on_match, *patterns). In v3 this was changed to (key, patterns, *, on_match=None), but there were various points where the old call syntax was documented or handled specially. This removes all those. The Matcher itself didn't need any code changes, as it just gives a generic type error. However the PhraseMatcher required some changes because it would automatically "fix" the old call style. Surprisingly, the tokenizer was still using the old call style in one place. After these changes tests failed in two places: 1. one test for the "new" call style, including the "old" call style. I removed this test. 2. deserializing the PhraseMatcher fails because the input docs are a set. I am not sure why 2 is happening - I guess it's a quirk of the serialization format? - so for now I just convert the set to a list when deserializing. The check that the input Docs are a List in the PhraseMatcher is a new check, but makes it parallel with the other Matchers, which seemed like the right thing to do. * Add notes related to input docs / deserialization type * Remove Typing import * Remove old note about call style change * Apply suggestions from code review Co-authored-by: Adriane Boyd * Use separate method for setting internal doc representations In addition to the title change, this changes the internal dict to be a defaultdict, instead of a dict with frequent use of setdefault. * Add _add_from_arrays for unpickling * Cleanup around adding from arrays This moves adding to internal structures into the private batch method, and removes the single-add method. This has one behavioral change for `add`, in that if something is wrong with the list of input Docs (such as one of the items not being a Doc), valid items before the invalid one will not be added. Also the callback will not be updated if anything is invalid. This change should not be significant. This also adds a test to check failure when given a non-Doc. * Update spacy/matcher/phrasematcher.pyx Co-authored-by: Adriane Boyd Co-authored-by: Adriane Boyd --- spacy/errors.py | 7 +- spacy/matcher/dependencymatcher.pyx | 6 +- spacy/matcher/matcher.pyx | 6 +- spacy/matcher/phrasematcher.pyi | 9 ++ spacy/matcher/phrasematcher.pyx | 113 +++++++++++---------- spacy/tests/matcher/test_phrase_matcher.py | 29 ++---- spacy/tokenizer.pyx | 2 +- website/docs/api/matcher.md | 16 +-- website/docs/api/phrasematcher.md | 22 +--- 9 files changed, 95 insertions(+), 115 deletions(-) diff --git a/spacy/errors.py b/spacy/errors.py index 608305a06..17346425c 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -487,7 +487,7 @@ class Errors(metaclass=ErrorsWithCodes): "Current DocBin: {current}\nOther DocBin: {other}") E169 = ("Can't find module: {module}") E170 = ("Cannot apply transition {name}: invalid for the current state.") - E171 = ("Matcher.add received invalid 'on_match' callback argument: expected " + E171 = ("{name}.add received invalid 'on_match' callback argument: expected " "callable or None, but got: {arg_type}") E175 = ("Can't remove rule for unknown match pattern ID: {key}") E176 = ("Alias '{alias}' is not defined in the Knowledge Base.") @@ -738,7 +738,7 @@ class Errors(metaclass=ErrorsWithCodes): "loaded nlp object, but got: {source}") E947 = ("`Matcher.add` received invalid `greedy` argument: expected " "a string value from {expected} but got: '{arg}'") - E948 = ("`Matcher.add` received invalid 'patterns' argument: expected " + E948 = ("`{name}.add` received invalid 'patterns' argument: expected " "a list, but got: {arg_type}") E949 = ("Unable to align tokens for the predicted and reference docs. It " "is only possible to align the docs when both texts are the same " @@ -941,6 +941,9 @@ class Errors(metaclass=ErrorsWithCodes): E1043 = ("Expected None or a value in range [{range_start}, {range_end}] for entity linker threshold, but got " "{value}.") + # v4 error strings + E4000 = ("Expected a Doc as input, but got: '{type}'") + # Deprecated model shortcuts, only used in errors and warnings OLD_MODEL_SHORTCUTS = { diff --git a/spacy/matcher/dependencymatcher.pyx b/spacy/matcher/dependencymatcher.pyx index 74c2d002f..4c6004907 100644 --- a/spacy/matcher/dependencymatcher.pyx +++ b/spacy/matcher/dependencymatcher.pyx @@ -165,9 +165,9 @@ cdef class DependencyMatcher: on_match (callable): Optional callback executed on match. """ if on_match is not None and not hasattr(on_match, "__call__"): - raise ValueError(Errors.E171.format(arg_type=type(on_match))) - if patterns is None or not isinstance(patterns, List): # old API - raise ValueError(Errors.E948.format(arg_type=type(patterns))) + raise ValueError(Errors.E171.format(name="DependencyMatcher", arg_type=type(on_match))) + if patterns is None or not isinstance(patterns, List): + raise ValueError(Errors.E948.format(name="DependencyMatcher", arg_type=type(patterns))) for pattern in patterns: if len(pattern) == 0: raise ValueError(Errors.E012.format(key=key)) diff --git a/spacy/matcher/matcher.pyx b/spacy/matcher/matcher.pyx index fcbcee02c..bee087260 100644 --- a/spacy/matcher/matcher.pyx +++ b/spacy/matcher/matcher.pyx @@ -110,9 +110,9 @@ cdef class Matcher: """ errors = {} if on_match is not None and not hasattr(on_match, "__call__"): - raise ValueError(Errors.E171.format(arg_type=type(on_match))) - if patterns is None or not isinstance(patterns, List): # old API - raise ValueError(Errors.E948.format(arg_type=type(patterns))) + raise ValueError(Errors.E171.format(name="Matcher", arg_type=type(on_match))) + if patterns is None or not isinstance(patterns, List): + raise ValueError(Errors.E948.format(name="Matcher", arg_type=type(patterns))) if greedy is not None and greedy not in ["FIRST", "LONGEST"]: raise ValueError(Errors.E947.format(expected=["FIRST", "LONGEST"], arg=greedy)) for i, pattern in enumerate(patterns): diff --git a/spacy/matcher/phrasematcher.pyi b/spacy/matcher/phrasematcher.pyi index 68e3386e4..670c87409 100644 --- a/spacy/matcher/phrasematcher.pyi +++ b/spacy/matcher/phrasematcher.pyi @@ -20,6 +20,15 @@ class PhraseMatcher: Callable[[Matcher, Doc, int, List[Tuple[Any, ...]]], Any] ] = ..., ) -> None: ... + def _add_from_arrays( + self, + key: str, + specs: List[List[int]], + *, + on_match: Optional[ + Callable[[Matcher, Doc, int, List[Tuple[Any, ...]]], Any] + ] = ..., + ) -> None: ... def remove(self, key: str) -> None: ... @overload def __call__( diff --git a/spacy/matcher/phrasematcher.pyx b/spacy/matcher/phrasematcher.pyx index 382029872..ebe1213c7 100644 --- a/spacy/matcher/phrasematcher.pyx +++ b/spacy/matcher/phrasematcher.pyx @@ -1,4 +1,6 @@ # cython: infer_types=True, profile=True +from typing import List +from collections import defaultdict from libc.stdint cimport uintptr_t from preshed.maps cimport map_init, map_set, map_get, map_clear, map_iter @@ -39,7 +41,7 @@ cdef class PhraseMatcher: """ self.vocab = vocab self._callbacks = {} - self._docs = {} + self._docs = defaultdict(set) self._validate = validate self.mem = Pool() @@ -155,66 +157,24 @@ cdef class PhraseMatcher: del self._callbacks[key] del self._docs[key] - def add(self, key, docs, *_docs, on_match=None): - """Add a match-rule to the phrase-matcher. A match-rule consists of: an ID - key, an on_match callback, and one or more patterns. - Since spaCy v2.2.2, PhraseMatcher.add takes a list of patterns as the - second argument, with the on_match callback as an optional keyword - argument. + def _add_from_arrays(self, key, specs, *, on_match=None): + """Add a preprocessed list of specs, with an optional callback. key (str): The match ID. - docs (list): List of `Doc` objects representing match patterns. + specs (List[List[int]]): A list of lists of hashes to match. on_match (callable): Callback executed on match. - *_docs (Doc): For backwards compatibility: list of patterns to add - as variable arguments. Will be ignored if a list of patterns is - provided as the second argument. - - DOCS: https://spacy.io/api/phrasematcher#add """ - if docs is None or hasattr(docs, "__call__"): # old API - on_match = docs - docs = _docs - - _ = self.vocab[key] - self._callbacks[key] = on_match - self._docs.setdefault(key, set()) - cdef MapStruct* current_node cdef MapStruct* internal_node cdef void* result - if isinstance(docs, Doc): - raise ValueError(Errors.E179.format(key=key)) - for doc in docs: - if len(doc) == 0: - continue - if isinstance(doc, Doc): - attrs = (TAG, POS, MORPH, LEMMA, DEP) - has_annotation = {attr: doc.has_annotation(attr) for attr in attrs} - for attr in attrs: - if self.attr == attr and not has_annotation[attr]: - if attr == TAG: - pipe = "tagger" - elif attr in (POS, MORPH): - pipe = "morphologizer or tagger+attribute_ruler" - elif attr == LEMMA: - pipe = "lemmatizer" - elif attr == DEP: - pipe = "parser" - error_msg = Errors.E155.format(pipe=pipe, attr=self.vocab.strings.as_string(attr)) - raise ValueError(error_msg) - if self._validate and any(has_annotation.values()) \ - and self.attr not in attrs: - string_attr = self.vocab.strings[self.attr] - warnings.warn(Warnings.W012.format(key=key, attr=string_attr)) - keyword = self._convert_to_array(doc) - else: - keyword = doc - self._docs[key].add(tuple(keyword)) + self._callbacks[key] = on_match + for spec in specs: + self._docs[key].add(tuple(spec)) current_node = self.c_map - for token in keyword: + for token in spec: if token == self._terminal_hash: warnings.warn(Warnings.W021) break @@ -233,6 +193,57 @@ cdef class PhraseMatcher: result = internal_node map_set(self.mem, result, self.vocab.strings[key], NULL) + + def add(self, key, docs, *, on_match=None): + """Add a match-rule to the phrase-matcher. A match-rule consists of: an ID + key, a list of one or more patterns, and (optionally) an on_match callback. + + key (str): The match ID. + docs (list): List of `Doc` objects representing match patterns. + on_match (callable): Callback executed on match. + + If any of the input Docs are invalid, no internal state will be updated. + + DOCS: https://spacy.io/api/phrasematcher#add + """ + if isinstance(docs, Doc): + raise ValueError(Errors.E179.format(key=key)) + if docs is None or not isinstance(docs, List): + raise ValueError(Errors.E948.format(name="PhraseMatcher", arg_type=type(docs))) + if on_match is not None and not hasattr(on_match, "__call__"): + raise ValueError(Errors.E171.format(name="PhraseMatcher", arg_type=type(on_match))) + + _ = self.vocab[key] + specs = [] + + for doc in docs: + if len(doc) == 0: + continue + if not isinstance(doc, Doc): + raise ValueError(Errors.E4000.format(type=type(doc))) + + attrs = (TAG, POS, MORPH, LEMMA, DEP) + has_annotation = {attr: doc.has_annotation(attr) for attr in attrs} + for attr in attrs: + if self.attr == attr and not has_annotation[attr]: + if attr == TAG: + pipe = "tagger" + elif attr in (POS, MORPH): + pipe = "morphologizer or tagger+attribute_ruler" + elif attr == LEMMA: + pipe = "lemmatizer" + elif attr == DEP: + pipe = "parser" + error_msg = Errors.E155.format(pipe=pipe, attr=self.vocab.strings.as_string(attr)) + raise ValueError(error_msg) + if self._validate and any(has_annotation.values()) \ + and self.attr not in attrs: + string_attr = self.vocab.strings[self.attr] + warnings.warn(Warnings.W012.format(key=key, attr=string_attr)) + specs.append(self._convert_to_array(doc)) + + self._add_from_arrays(key, specs, on_match=on_match) + def __call__(self, object doclike, *, as_spans=False): """Find all sequences matching the supplied patterns on the `Doc`. @@ -345,7 +356,7 @@ def unpickle_matcher(vocab, docs, callbacks, attr): matcher = PhraseMatcher(vocab, attr=attr) for key, specs in docs.items(): callback = callbacks.get(key, None) - matcher.add(key, specs, on_match=callback) + matcher._add_from_arrays(key, specs, on_match=callback) return matcher diff --git a/spacy/tests/matcher/test_phrase_matcher.py b/spacy/tests/matcher/test_phrase_matcher.py index 8a8d9eb84..b462b1878 100644 --- a/spacy/tests/matcher/test_phrase_matcher.py +++ b/spacy/tests/matcher/test_phrase_matcher.py @@ -198,28 +198,6 @@ def test_phrase_matcher_contains(en_vocab): assert "TEST2" not in matcher -def test_phrase_matcher_add_new_api(en_vocab): - doc = Doc(en_vocab, words=["a", "b"]) - patterns = [Doc(en_vocab, words=["a"]), Doc(en_vocab, words=["a", "b"])] - matcher = PhraseMatcher(en_vocab) - matcher.add("OLD_API", None, *patterns) - assert len(matcher(doc)) == 2 - matcher = PhraseMatcher(en_vocab) - on_match = Mock() - matcher.add("OLD_API_CALLBACK", on_match, *patterns) - assert len(matcher(doc)) == 2 - assert on_match.call_count == 2 - # New API: add(key: str, patterns: List[List[dict]], on_match: Callable) - matcher = PhraseMatcher(en_vocab) - matcher.add("NEW_API", patterns) - assert len(matcher(doc)) == 2 - matcher = PhraseMatcher(en_vocab) - on_match = Mock() - matcher.add("NEW_API_CALLBACK", patterns, on_match=on_match) - assert len(matcher(doc)) == 2 - assert on_match.call_count == 2 - - def test_phrase_matcher_repeated_add(en_vocab): matcher = PhraseMatcher(en_vocab) # match ID only gets added once @@ -468,6 +446,13 @@ def test_phrase_matcher_deprecated(en_vocab): assert "spaCy v3.0" in str(record.list[0].message) +def test_phrase_matcher_non_doc(en_vocab): + matcher = PhraseMatcher(en_vocab) + doc = Doc(en_vocab, words=["hello", "world"]) + with pytest.raises(ValueError): + matcher.add("TEST", [doc, "junk"]) + + @pytest.mark.parametrize("attr", ["SENT_START", "IS_SENT_START"]) def test_phrase_matcher_sent_start(en_vocab, attr): _ = PhraseMatcher(en_vocab, attr=attr) # noqa: F841 diff --git a/spacy/tokenizer.pyx b/spacy/tokenizer.pyx index 49ce6171a..ff8d85ac7 100644 --- a/spacy/tokenizer.pyx +++ b/spacy/tokenizer.pyx @@ -614,7 +614,7 @@ cdef class Tokenizer: self._rules[string] = substrings self._flush_cache() if not self.faster_heuristics or self.find_prefix(string) or self.find_infix(string) or self.find_suffix(string) or " " in string: - self._special_matcher.add(string, None, self._tokenize_affixes(string, False)) + self._special_matcher.add(string, [self._tokenize_affixes(string, False)]) def _reload_special_cases(self): self._flush_cache() diff --git a/website/docs/api/matcher.md b/website/docs/api/matcher.md index 8cc446c6a..ff6923cf2 100644 --- a/website/docs/api/matcher.md +++ b/website/docs/api/matcher.md @@ -64,7 +64,7 @@ matched: > ``` | OP | Description | -|---------|------------------------------------------------------------------------| +| ------- | ---------------------------------------------------------------------- | | `!` | Negate the pattern, by requiring it to match exactly 0 times. | | `?` | Make the pattern optional, by allowing it to match 0 or 1 times. | | `+` | Require the pattern to match 1 or more times. | @@ -204,20 +204,6 @@ will be overwritten. > matches = matcher(doc) > ``` - - -As of spaCy v3.0, `Matcher.add` takes a list of patterns as the second argument -(instead of a variable number of arguments). The `on_match` callback becomes an -optional keyword argument. - -```diff -patterns = [[{"TEXT": "Google"}, {"TEXT": "Now"}], [{"TEXT": "GoogleNow"}]] -- matcher.add("GoogleNow", on_match, *patterns) -+ matcher.add("GoogleNow", patterns, on_match=on_match) -``` - - - | Name | Description | | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `match_id` | An ID for the thing you're matching. ~~str~~ | diff --git a/website/docs/api/phrasematcher.md b/website/docs/api/phrasematcher.md index 2cef9ac2a..b06198916 100644 --- a/website/docs/api/phrasematcher.md +++ b/website/docs/api/phrasematcher.md @@ -116,10 +116,10 @@ Check whether the matcher contains rules for a match ID. ## PhraseMatcher.add {#add tag="method"} Add a rule to the matcher, consisting of an ID key, one or more patterns, and a -callback function to act on the matches. The callback function will receive the -arguments `matcher`, `doc`, `i` and `matches`. If a pattern already exists for -the given ID, the patterns will be extended. An `on_match` callback will be -overwritten. +optional callback function to act on the matches. The callback function will +receive the arguments `matcher`, `doc`, `i` and `matches`. If a pattern already +exists for the given ID, the patterns will be extended. An `on_match` callback +will be overwritten. > #### Example > @@ -134,20 +134,6 @@ overwritten. > matches = matcher(doc) > ``` - - -As of spaCy v3.0, `PhraseMatcher.add` takes a list of patterns as the second -argument (instead of a variable number of arguments). The `on_match` callback -becomes an optional keyword argument. - -```diff -patterns = [nlp("health care reform"), nlp("healthcare reform")] -- matcher.add("HEALTH", on_match, *patterns) -+ matcher.add("HEALTH", patterns, on_match=on_match) -``` - - - | Name | Description | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | An ID for the thing you're matching. ~~str~~ | From 4a615cacd2af35bbbcf9e735da19ce92480b6cf6 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Fri, 2 Sep 2022 09:08:40 +0200 Subject: [PATCH 014/123] Consolidate and freeze symbols (#11352) * Consolidate and freeze symbols Instead of having symbol values defined in three potentially conflicting places (`spacy.attrs`, `spacy.parts_of_speech`, `spacy.symbols`), define all symbols in `spacy.symbols` and reference those values in `spacy.attrs` and `spacy.parts_of_speech`. Remove deprecated and placeholder symbols from `spacy.attrs.IDS`. Make `spacy.attrs.NAMES` and `spacy.symbols.NAMES` reverse dicts rather than lists in order to support future use of hash values in `attr_id_t`. Minor changes: * Use `uint64_t` for attrs in `Doc.to_array` to support future use of hash values * Remove unneeded attrs filter for error message in `Doc.to_array` * Remove unused attr `SENT_END` * Handle dynamic size of attr_id_t in Doc.to_array * Undo added warnings * Refactor to make Doc.to_array more similar to Doc.from_array * Improve refactoring --- spacy/attrs.pxd | 129 +++------- spacy/attrs.pyx | 49 +--- spacy/parts_of_speech.pxd | 38 +-- spacy/schemas.py | 2 +- spacy/strings.pyx | 4 +- spacy/symbols.pxd | 15 +- spacy/symbols.pyx | 6 +- spacy/tests/test_symbols.py | 467 ++++++++++++++++++++++++++++++++++++ spacy/tokens/doc.pyx | 20 +- 9 files changed, 551 insertions(+), 179 deletions(-) create mode 100644 spacy/tests/test_symbols.py diff --git a/spacy/attrs.pxd b/spacy/attrs.pxd index 33d5372de..b8a7a1f08 100644 --- a/spacy/attrs.pxd +++ b/spacy/attrs.pxd @@ -1,98 +1,49 @@ -# Reserve 64 values for flag features from . cimport symbols cdef enum attr_id_t: - NULL_ATTR - IS_ALPHA - IS_ASCII - IS_DIGIT - IS_LOWER - IS_PUNCT - IS_SPACE - IS_TITLE - IS_UPPER - LIKE_URL - LIKE_NUM - LIKE_EMAIL - IS_STOP - IS_OOV_DEPRECATED - IS_BRACKET - IS_QUOTE - IS_LEFT_PUNCT - IS_RIGHT_PUNCT - IS_CURRENCY + NULL_ATTR = 0 + IS_ALPHA = symbols.IS_ALPHA + IS_ASCII = symbols.IS_ASCII + IS_DIGIT = symbols.IS_DIGIT + IS_LOWER = symbols.IS_LOWER + IS_PUNCT = symbols.IS_PUNCT + IS_SPACE = symbols.IS_SPACE + IS_TITLE = symbols.IS_TITLE + IS_UPPER = symbols.IS_UPPER + LIKE_URL = symbols.LIKE_URL + LIKE_NUM = symbols.LIKE_NUM + LIKE_EMAIL = symbols.LIKE_EMAIL + IS_STOP = symbols.IS_STOP + IS_BRACKET = symbols.IS_BRACKET + IS_QUOTE = symbols.IS_QUOTE + IS_LEFT_PUNCT = symbols.IS_LEFT_PUNCT + IS_RIGHT_PUNCT = symbols.IS_RIGHT_PUNCT + IS_CURRENCY = symbols.IS_CURRENCY - FLAG19 = 19 - FLAG20 - FLAG21 - FLAG22 - FLAG23 - FLAG24 - FLAG25 - FLAG26 - FLAG27 - FLAG28 - FLAG29 - FLAG30 - FLAG31 - FLAG32 - FLAG33 - FLAG34 - FLAG35 - FLAG36 - FLAG37 - FLAG38 - FLAG39 - FLAG40 - FLAG41 - FLAG42 - FLAG43 - FLAG44 - FLAG45 - FLAG46 - FLAG47 - FLAG48 - FLAG49 - FLAG50 - FLAG51 - FLAG52 - FLAG53 - FLAG54 - FLAG55 - FLAG56 - FLAG57 - FLAG58 - FLAG59 - FLAG60 - FLAG61 - FLAG62 - FLAG63 + ID = symbols.ID + ORTH = symbols.ORTH + LOWER = symbols.LOWER + NORM = symbols.NORM + SHAPE = symbols.SHAPE + PREFIX = symbols.PREFIX + SUFFIX = symbols.SUFFIX - ID - ORTH - LOWER - NORM - SHAPE - PREFIX - SUFFIX + LENGTH = symbols.LENGTH + CLUSTER = symbols.CLUSTER + LEMMA = symbols.LEMMA + POS = symbols.POS + TAG = symbols.TAG + DEP = symbols.DEP + ENT_IOB = symbols.ENT_IOB + ENT_TYPE = symbols.ENT_TYPE + HEAD = symbols.HEAD + SENT_START = symbols.SENT_START + SPACY = symbols.SPACY + PROB = symbols.PROB - LENGTH - CLUSTER - LEMMA - POS - TAG - DEP - ENT_IOB - ENT_TYPE - HEAD - SENT_START - SPACY - PROB - - LANG + LANG = symbols.LANG ENT_KB_ID = symbols.ENT_KB_ID - MORPH + MORPH = symbols.MORPH ENT_ID = symbols.ENT_ID - IDX - SENT_END \ No newline at end of file + IDX = symbols.IDX diff --git a/spacy/attrs.pyx b/spacy/attrs.pyx index 7b6fd9e94..9b0ae3400 100644 --- a/spacy/attrs.pyx +++ b/spacy/attrs.pyx @@ -16,57 +16,11 @@ IDS = { "LIKE_NUM": LIKE_NUM, "LIKE_EMAIL": LIKE_EMAIL, "IS_STOP": IS_STOP, - "IS_OOV_DEPRECATED": IS_OOV_DEPRECATED, "IS_BRACKET": IS_BRACKET, "IS_QUOTE": IS_QUOTE, "IS_LEFT_PUNCT": IS_LEFT_PUNCT, "IS_RIGHT_PUNCT": IS_RIGHT_PUNCT, "IS_CURRENCY": IS_CURRENCY, - "FLAG19": FLAG19, - "FLAG20": FLAG20, - "FLAG21": FLAG21, - "FLAG22": FLAG22, - "FLAG23": FLAG23, - "FLAG24": FLAG24, - "FLAG25": FLAG25, - "FLAG26": FLAG26, - "FLAG27": FLAG27, - "FLAG28": FLAG28, - "FLAG29": FLAG29, - "FLAG30": FLAG30, - "FLAG31": FLAG31, - "FLAG32": FLAG32, - "FLAG33": FLAG33, - "FLAG34": FLAG34, - "FLAG35": FLAG35, - "FLAG36": FLAG36, - "FLAG37": FLAG37, - "FLAG38": FLAG38, - "FLAG39": FLAG39, - "FLAG40": FLAG40, - "FLAG41": FLAG41, - "FLAG42": FLAG42, - "FLAG43": FLAG43, - "FLAG44": FLAG44, - "FLAG45": FLAG45, - "FLAG46": FLAG46, - "FLAG47": FLAG47, - "FLAG48": FLAG48, - "FLAG49": FLAG49, - "FLAG50": FLAG50, - "FLAG51": FLAG51, - "FLAG52": FLAG52, - "FLAG53": FLAG53, - "FLAG54": FLAG54, - "FLAG55": FLAG55, - "FLAG56": FLAG56, - "FLAG57": FLAG57, - "FLAG58": FLAG58, - "FLAG59": FLAG59, - "FLAG60": FLAG60, - "FLAG61": FLAG61, - "FLAG62": FLAG62, - "FLAG63": FLAG63, "ID": ID, "ORTH": ORTH, "LOWER": LOWER, @@ -92,8 +46,7 @@ IDS = { } -# ATTR IDs, in order of the symbol -NAMES = [key for key, value in sorted(IDS.items(), key=lambda item: item[1])] +NAMES = {v: k for k, v in IDS.items()} locals().update(IDS) diff --git a/spacy/parts_of_speech.pxd b/spacy/parts_of_speech.pxd index 0bf5b4789..67390ad63 100644 --- a/spacy/parts_of_speech.pxd +++ b/spacy/parts_of_speech.pxd @@ -3,22 +3,22 @@ from . cimport symbols cpdef enum univ_pos_t: NO_TAG = 0 ADJ = symbols.ADJ - ADP - ADV - AUX - CONJ - CCONJ # U20 - DET - INTJ - NOUN - NUM - PART - PRON - PROPN - PUNCT - SCONJ - SYM - VERB - X - EOL - SPACE + ADP = symbols.ADP + ADV = symbols.ADV + AUX = symbols.AUX + CONJ = symbols.CONJ + CCONJ = symbols.CCONJ # U20 + DET = symbols.DET + INTJ = symbols.INTJ + NOUN = symbols.NOUN + NUM = symbols.NUM + PART = symbols.PART + PRON = symbols.PRON + PROPN = symbols.PROPN + PUNCT = symbols.PUNCT + SCONJ = symbols.SCONJ + SYM = symbols.SYM + VERB = symbols.VERB + X = symbols.X + EOL = symbols.EOL + SPACE = symbols.SPACE diff --git a/spacy/schemas.py b/spacy/schemas.py index 048082134..a38421fa0 100644 --- a/spacy/schemas.py +++ b/spacy/schemas.py @@ -144,7 +144,7 @@ def validate_init_settings( def validate_token_pattern(obj: list) -> List[str]: # Try to convert non-string keys (e.g. {ORTH: "foo"} -> {"ORTH": "foo"}) - get_key = lambda k: NAMES[k] if isinstance(k, int) and k < len(NAMES) else k + get_key = lambda k: NAMES[k] if isinstance(k, int) and k in NAMES else k if isinstance(obj, list): converted = [] for pattern in obj: diff --git a/spacy/strings.pyx b/spacy/strings.pyx index c5f218342..e86682733 100644 --- a/spacy/strings.pyx +++ b/spacy/strings.pyx @@ -147,7 +147,7 @@ cdef class StringStore: elif _try_coerce_to_hash(string_or_id, &str_hash): if str_hash == 0: return "" - elif str_hash < len(SYMBOLS_BY_INT): + elif str_hash in SYMBOLS_BY_INT: return SYMBOLS_BY_INT[str_hash] else: utf8str = self._map.get(str_hash) @@ -223,7 +223,7 @@ cdef class StringStore: # TODO: Raise an error instead return self._map.get(string_or_id) is not NULL - if str_hash < len(SYMBOLS_BY_INT): + if str_hash in SYMBOLS_BY_INT: return True else: return self._map.get(str_hash) is not NULL diff --git a/spacy/symbols.pxd b/spacy/symbols.pxd index bc15d9b80..f5d7784dc 100644 --- a/spacy/symbols.pxd +++ b/spacy/symbols.pxd @@ -1,5 +1,6 @@ +# DO NOT EDIT! The symbols are frozen as of spaCy v3.0.0. cdef enum symbol_t: - NIL + NIL = 0 IS_ALPHA IS_ASCII IS_DIGIT @@ -65,7 +66,7 @@ cdef enum symbol_t: FLAG62 FLAG63 - ID + ID = 64 ORTH LOWER NORM @@ -385,7 +386,7 @@ cdef enum symbol_t: DEPRECATED275 DEPRECATED276 - PERSON + PERSON = 380 NORP FACILITY ORG @@ -405,7 +406,7 @@ cdef enum symbol_t: ORDINAL CARDINAL - acomp + acomp = 398 advcl advmod agent @@ -458,12 +459,12 @@ cdef enum symbol_t: rcmod root xcomp - acl - ENT_KB_ID + ENT_KB_ID = 452 MORPH ENT_ID IDX - _ + _ = 456 + # DO NOT ADD ANY NEW SYMBOLS! diff --git a/spacy/symbols.pyx b/spacy/symbols.pyx index b0345c710..fbfc6f10d 100644 --- a/spacy/symbols.pyx +++ b/spacy/symbols.pyx @@ -469,11 +469,7 @@ IDS = { } -def sort_nums(x): - return x[1] - - -NAMES = [it[0] for it in sorted(IDS.items(), key=sort_nums)] +NAMES = {v: k for k, v in IDS.items()} # Unfortunate hack here, to work around problem with long cpdef enum # (which is generating an enormous amount of C++ in Cython 0.24+) # We keep the enum cdef, and just make sure the names are available to Python diff --git a/spacy/tests/test_symbols.py b/spacy/tests/test_symbols.py new file mode 100644 index 000000000..fb034acca --- /dev/null +++ b/spacy/tests/test_symbols.py @@ -0,0 +1,467 @@ +import pytest +from spacy.symbols import IDS, NAMES + +V3_SYMBOLS = { + "": 0, + "IS_ALPHA": 1, + "IS_ASCII": 2, + "IS_DIGIT": 3, + "IS_LOWER": 4, + "IS_PUNCT": 5, + "IS_SPACE": 6, + "IS_TITLE": 7, + "IS_UPPER": 8, + "LIKE_URL": 9, + "LIKE_NUM": 10, + "LIKE_EMAIL": 11, + "IS_STOP": 12, + "IS_OOV_DEPRECATED": 13, + "IS_BRACKET": 14, + "IS_QUOTE": 15, + "IS_LEFT_PUNCT": 16, + "IS_RIGHT_PUNCT": 17, + "IS_CURRENCY": 18, + "FLAG19": 19, + "FLAG20": 20, + "FLAG21": 21, + "FLAG22": 22, + "FLAG23": 23, + "FLAG24": 24, + "FLAG25": 25, + "FLAG26": 26, + "FLAG27": 27, + "FLAG28": 28, + "FLAG29": 29, + "FLAG30": 30, + "FLAG31": 31, + "FLAG32": 32, + "FLAG33": 33, + "FLAG34": 34, + "FLAG35": 35, + "FLAG36": 36, + "FLAG37": 37, + "FLAG38": 38, + "FLAG39": 39, + "FLAG40": 40, + "FLAG41": 41, + "FLAG42": 42, + "FLAG43": 43, + "FLAG44": 44, + "FLAG45": 45, + "FLAG46": 46, + "FLAG47": 47, + "FLAG48": 48, + "FLAG49": 49, + "FLAG50": 50, + "FLAG51": 51, + "FLAG52": 52, + "FLAG53": 53, + "FLAG54": 54, + "FLAG55": 55, + "FLAG56": 56, + "FLAG57": 57, + "FLAG58": 58, + "FLAG59": 59, + "FLAG60": 60, + "FLAG61": 61, + "FLAG62": 62, + "FLAG63": 63, + "ID": 64, + "ORTH": 65, + "LOWER": 66, + "NORM": 67, + "SHAPE": 68, + "PREFIX": 69, + "SUFFIX": 70, + "LENGTH": 71, + "CLUSTER": 72, + "LEMMA": 73, + "POS": 74, + "TAG": 75, + "DEP": 76, + "ENT_IOB": 77, + "ENT_TYPE": 78, + "ENT_ID": 454, + "ENT_KB_ID": 452, + "HEAD": 79, + "SENT_START": 80, + "SPACY": 81, + "PROB": 82, + "LANG": 83, + "IDX": 455, + "ADJ": 84, + "ADP": 85, + "ADV": 86, + "AUX": 87, + "CONJ": 88, + "CCONJ": 89, + "DET": 90, + "INTJ": 91, + "NOUN": 92, + "NUM": 93, + "PART": 94, + "PRON": 95, + "PROPN": 96, + "PUNCT": 97, + "SCONJ": 98, + "SYM": 99, + "VERB": 100, + "X": 101, + "EOL": 102, + "SPACE": 103, + "DEPRECATED001": 104, + "DEPRECATED002": 105, + "DEPRECATED003": 106, + "DEPRECATED004": 107, + "DEPRECATED005": 108, + "DEPRECATED006": 109, + "DEPRECATED007": 110, + "DEPRECATED008": 111, + "DEPRECATED009": 112, + "DEPRECATED010": 113, + "DEPRECATED011": 114, + "DEPRECATED012": 115, + "DEPRECATED013": 116, + "DEPRECATED014": 117, + "DEPRECATED015": 118, + "DEPRECATED016": 119, + "DEPRECATED017": 120, + "DEPRECATED018": 121, + "DEPRECATED019": 122, + "DEPRECATED020": 123, + "DEPRECATED021": 124, + "DEPRECATED022": 125, + "DEPRECATED023": 126, + "DEPRECATED024": 127, + "DEPRECATED025": 128, + "DEPRECATED026": 129, + "DEPRECATED027": 130, + "DEPRECATED028": 131, + "DEPRECATED029": 132, + "DEPRECATED030": 133, + "DEPRECATED031": 134, + "DEPRECATED032": 135, + "DEPRECATED033": 136, + "DEPRECATED034": 137, + "DEPRECATED035": 138, + "DEPRECATED036": 139, + "DEPRECATED037": 140, + "DEPRECATED038": 141, + "DEPRECATED039": 142, + "DEPRECATED040": 143, + "DEPRECATED041": 144, + "DEPRECATED042": 145, + "DEPRECATED043": 146, + "DEPRECATED044": 147, + "DEPRECATED045": 148, + "DEPRECATED046": 149, + "DEPRECATED047": 150, + "DEPRECATED048": 151, + "DEPRECATED049": 152, + "DEPRECATED050": 153, + "DEPRECATED051": 154, + "DEPRECATED052": 155, + "DEPRECATED053": 156, + "DEPRECATED054": 157, + "DEPRECATED055": 158, + "DEPRECATED056": 159, + "DEPRECATED057": 160, + "DEPRECATED058": 161, + "DEPRECATED059": 162, + "DEPRECATED060": 163, + "DEPRECATED061": 164, + "DEPRECATED062": 165, + "DEPRECATED063": 166, + "DEPRECATED064": 167, + "DEPRECATED065": 168, + "DEPRECATED066": 169, + "DEPRECATED067": 170, + "DEPRECATED068": 171, + "DEPRECATED069": 172, + "DEPRECATED070": 173, + "DEPRECATED071": 174, + "DEPRECATED072": 175, + "DEPRECATED073": 176, + "DEPRECATED074": 177, + "DEPRECATED075": 178, + "DEPRECATED076": 179, + "DEPRECATED077": 180, + "DEPRECATED078": 181, + "DEPRECATED079": 182, + "DEPRECATED080": 183, + "DEPRECATED081": 184, + "DEPRECATED082": 185, + "DEPRECATED083": 186, + "DEPRECATED084": 187, + "DEPRECATED085": 188, + "DEPRECATED086": 189, + "DEPRECATED087": 190, + "DEPRECATED088": 191, + "DEPRECATED089": 192, + "DEPRECATED090": 193, + "DEPRECATED091": 194, + "DEPRECATED092": 195, + "DEPRECATED093": 196, + "DEPRECATED094": 197, + "DEPRECATED095": 198, + "DEPRECATED096": 199, + "DEPRECATED097": 200, + "DEPRECATED098": 201, + "DEPRECATED099": 202, + "DEPRECATED100": 203, + "DEPRECATED101": 204, + "DEPRECATED102": 205, + "DEPRECATED103": 206, + "DEPRECATED104": 207, + "DEPRECATED105": 208, + "DEPRECATED106": 209, + "DEPRECATED107": 210, + "DEPRECATED108": 211, + "DEPRECATED109": 212, + "DEPRECATED110": 213, + "DEPRECATED111": 214, + "DEPRECATED112": 215, + "DEPRECATED113": 216, + "DEPRECATED114": 217, + "DEPRECATED115": 218, + "DEPRECATED116": 219, + "DEPRECATED117": 220, + "DEPRECATED118": 221, + "DEPRECATED119": 222, + "DEPRECATED120": 223, + "DEPRECATED121": 224, + "DEPRECATED122": 225, + "DEPRECATED123": 226, + "DEPRECATED124": 227, + "DEPRECATED125": 228, + "DEPRECATED126": 229, + "DEPRECATED127": 230, + "DEPRECATED128": 231, + "DEPRECATED129": 232, + "DEPRECATED130": 233, + "DEPRECATED131": 234, + "DEPRECATED132": 235, + "DEPRECATED133": 236, + "DEPRECATED134": 237, + "DEPRECATED135": 238, + "DEPRECATED136": 239, + "DEPRECATED137": 240, + "DEPRECATED138": 241, + "DEPRECATED139": 242, + "DEPRECATED140": 243, + "DEPRECATED141": 244, + "DEPRECATED142": 245, + "DEPRECATED143": 246, + "DEPRECATED144": 247, + "DEPRECATED145": 248, + "DEPRECATED146": 249, + "DEPRECATED147": 250, + "DEPRECATED148": 251, + "DEPRECATED149": 252, + "DEPRECATED150": 253, + "DEPRECATED151": 254, + "DEPRECATED152": 255, + "DEPRECATED153": 256, + "DEPRECATED154": 257, + "DEPRECATED155": 258, + "DEPRECATED156": 259, + "DEPRECATED157": 260, + "DEPRECATED158": 261, + "DEPRECATED159": 262, + "DEPRECATED160": 263, + "DEPRECATED161": 264, + "DEPRECATED162": 265, + "DEPRECATED163": 266, + "DEPRECATED164": 267, + "DEPRECATED165": 268, + "DEPRECATED166": 269, + "DEPRECATED167": 270, + "DEPRECATED168": 271, + "DEPRECATED169": 272, + "DEPRECATED170": 273, + "DEPRECATED171": 274, + "DEPRECATED172": 275, + "DEPRECATED173": 276, + "DEPRECATED174": 277, + "DEPRECATED175": 278, + "DEPRECATED176": 279, + "DEPRECATED177": 280, + "DEPRECATED178": 281, + "DEPRECATED179": 282, + "DEPRECATED180": 283, + "DEPRECATED181": 284, + "DEPRECATED182": 285, + "DEPRECATED183": 286, + "DEPRECATED184": 287, + "DEPRECATED185": 288, + "DEPRECATED186": 289, + "DEPRECATED187": 290, + "DEPRECATED188": 291, + "DEPRECATED189": 292, + "DEPRECATED190": 293, + "DEPRECATED191": 294, + "DEPRECATED192": 295, + "DEPRECATED193": 296, + "DEPRECATED194": 297, + "DEPRECATED195": 298, + "DEPRECATED196": 299, + "DEPRECATED197": 300, + "DEPRECATED198": 301, + "DEPRECATED199": 302, + "DEPRECATED200": 303, + "DEPRECATED201": 304, + "DEPRECATED202": 305, + "DEPRECATED203": 306, + "DEPRECATED204": 307, + "DEPRECATED205": 308, + "DEPRECATED206": 309, + "DEPRECATED207": 310, + "DEPRECATED208": 311, + "DEPRECATED209": 312, + "DEPRECATED210": 313, + "DEPRECATED211": 314, + "DEPRECATED212": 315, + "DEPRECATED213": 316, + "DEPRECATED214": 317, + "DEPRECATED215": 318, + "DEPRECATED216": 319, + "DEPRECATED217": 320, + "DEPRECATED218": 321, + "DEPRECATED219": 322, + "DEPRECATED220": 323, + "DEPRECATED221": 324, + "DEPRECATED222": 325, + "DEPRECATED223": 326, + "DEPRECATED224": 327, + "DEPRECATED225": 328, + "DEPRECATED226": 329, + "DEPRECATED227": 330, + "DEPRECATED228": 331, + "DEPRECATED229": 332, + "DEPRECATED230": 333, + "DEPRECATED231": 334, + "DEPRECATED232": 335, + "DEPRECATED233": 336, + "DEPRECATED234": 337, + "DEPRECATED235": 338, + "DEPRECATED236": 339, + "DEPRECATED237": 340, + "DEPRECATED238": 341, + "DEPRECATED239": 342, + "DEPRECATED240": 343, + "DEPRECATED241": 344, + "DEPRECATED242": 345, + "DEPRECATED243": 346, + "DEPRECATED244": 347, + "DEPRECATED245": 348, + "DEPRECATED246": 349, + "DEPRECATED247": 350, + "DEPRECATED248": 351, + "DEPRECATED249": 352, + "DEPRECATED250": 353, + "DEPRECATED251": 354, + "DEPRECATED252": 355, + "DEPRECATED253": 356, + "DEPRECATED254": 357, + "DEPRECATED255": 358, + "DEPRECATED256": 359, + "DEPRECATED257": 360, + "DEPRECATED258": 361, + "DEPRECATED259": 362, + "DEPRECATED260": 363, + "DEPRECATED261": 364, + "DEPRECATED262": 365, + "DEPRECATED263": 366, + "DEPRECATED264": 367, + "DEPRECATED265": 368, + "DEPRECATED266": 369, + "DEPRECATED267": 370, + "DEPRECATED268": 371, + "DEPRECATED269": 372, + "DEPRECATED270": 373, + "DEPRECATED271": 374, + "DEPRECATED272": 375, + "DEPRECATED273": 376, + "DEPRECATED274": 377, + "DEPRECATED275": 378, + "DEPRECATED276": 379, + "PERSON": 380, + "NORP": 381, + "FACILITY": 382, + "ORG": 383, + "GPE": 384, + "LOC": 385, + "PRODUCT": 386, + "EVENT": 387, + "WORK_OF_ART": 388, + "LANGUAGE": 389, + "DATE": 391, + "TIME": 392, + "PERCENT": 393, + "MONEY": 394, + "QUANTITY": 395, + "ORDINAL": 396, + "CARDINAL": 397, + "acomp": 398, + "advcl": 399, + "advmod": 400, + "agent": 401, + "amod": 402, + "appos": 403, + "attr": 404, + "aux": 405, + "auxpass": 406, + "cc": 407, + "ccomp": 408, + "complm": 409, + "conj": 410, + "cop": 411, + "csubj": 412, + "csubjpass": 413, + "dep": 414, + "det": 415, + "dobj": 416, + "expl": 417, + "hmod": 418, + "hyph": 419, + "infmod": 420, + "intj": 421, + "iobj": 422, + "mark": 423, + "meta": 424, + "neg": 425, + "nmod": 426, + "nn": 427, + "npadvmod": 428, + "nsubj": 429, + "nsubjpass": 430, + "num": 431, + "number": 432, + "oprd": 433, + "obj": 434, + "obl": 435, + "parataxis": 436, + "partmod": 437, + "pcomp": 438, + "pobj": 439, + "poss": 440, + "possessive": 441, + "preconj": 442, + "prep": 443, + "prt": 444, + "punct": 445, + "quantmod": 446, + "rcmod": 448, + "relcl": 447, + "root": 449, + "xcomp": 450, + "acl": 451, + "LAW": 390, + "MORPH": 453, + "_": 456, +} + + +def test_frozen_symbols(): + assert IDS == V3_SYMBOLS + assert NAMES == {v: k for k, v in IDS.items()} diff --git a/spacy/tokens/doc.pyx b/spacy/tokens/doc.pyx index 2956f357c..85d76efb3 100644 --- a/spacy/tokens/doc.pyx +++ b/spacy/tokens/doc.pyx @@ -974,22 +974,26 @@ cdef class Doc: py_attr_ids = [(IDS[id_.upper()] if hasattr(id_, "upper") else id_) for id_ in py_attr_ids] except KeyError as msg: - keys = [k for k in IDS.keys() if not k.startswith("FLAG")] + keys = list(IDS.keys()) raise KeyError(Errors.E983.format(dict="IDS", key=msg, keys=keys)) from None # Make an array from the attributes --- otherwise our inner loop is # Python dict iteration. - cdef np.ndarray attr_ids = numpy.asarray(py_attr_ids, dtype="i") - output = numpy.ndarray(shape=(self.length, len(attr_ids)), dtype=numpy.uint64) + cdef Pool mem = Pool() + cdef int n_attrs = len(py_attr_ids) + cdef attr_id_t* c_attr_ids + if n_attrs > 0: + c_attr_ids = mem.alloc(n_attrs, sizeof(attr_id_t)) + for i, attr_id in enumerate(py_attr_ids): + c_attr_ids[i] = attr_id + output = numpy.ndarray(shape=(self.length, n_attrs), dtype=numpy.uint64) c_output = output.data - c_attr_ids = attr_ids.data cdef TokenC* token - cdef int nr_attr = attr_ids.shape[0] for i in range(self.length): token = &self.c[i] - for j in range(nr_attr): - c_output[i*nr_attr + j] = get_token_attr(token, c_attr_ids[j]) + for j in range(n_attrs): + c_output[i*n_attrs + j] = get_token_attr(token, c_attr_ids[j]) # Handle 1d case - return output if len(attr_ids) >= 2 else output.reshape((self.length,)) + return output if n_attrs >= 2 else output.reshape((self.length,)) def count_by(self, attr_id_t attr_id, exclude=None, object counts=None): """Count the frequencies of a given attribute. Produces a dict of From efdbb722c5072e2137f13408e0bc0e3976715a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Tue, 13 Sep 2022 09:51:12 +0200 Subject: [PATCH 015/123] Store activations in `Doc`s when `save_activations` is enabled (#11002) * Store activations in Doc when `store_activations` is enabled This change adds the new `activations` attribute to `Doc`. This attribute can be used by trainable pipes to store their activations, probabilities, and guesses for downstream users. As an example, this change modifies the `tagger` and `senter` pipes to add an `store_activations` option. When this option is enabled, the probabilities and guesses are stored in `set_annotations`. * Change type of `store_activations` to `Union[bool, List[str]]` When the value is: - A bool: all activations are stored when set to `True`. - A List[str]: the activations named in the list are stored * Formatting fixes in Tagger * Support store_activations in spancat and morphologizer * Make Doc.activations type visible to MyPy * textcat/textcat_multilabel: add store_activations option * trainable_lemmatizer/entity_linker: add store_activations option * parser/ner: do not currently support returning activations * Extend tagger and senter tests So that they, like the other tests, also check that we get no activations if no activations were requested. * Document `Doc.activations` and `store_activations` in the relevant pipes * Start errors/warnings at higher numbers to avoid merge conflicts Between the master and v4 branches. * Add `store_activations` to docstrings. * Replace store_activations setter by set_store_activations method Setters that take a different type than what the getter returns are still problematic for MyPy. Replace the setter by a method, so that type inference works everywhere. * Use dict comprehension suggested by @svlandeg * Revert "Use dict comprehension suggested by @svlandeg" This reverts commit 6e7b958f7060397965176c69649e5414f1f24988. * EntityLinker: add type annotations to _add_activations * _store_activations: make kwarg-only, remove doc_scores_lens arg * set_annotations: add type annotations * Apply suggestions from code review Co-authored-by: Sofie Van Landeghem * TextCat.predict: return dict * Make the `TrainablePipe.store_activations` property a bool This means that we can also bring back `store_activations` setter. * Remove `TrainablePipe.activations` We do not need to enumerate the activations anymore since `store_activations` is `bool`. * Add type annotations for activations in predict/set_annotations * Rename `TrainablePipe.store_activations` to `save_activations` * Error E1400 is not used anymore This error was used when activations were still `Union[bool, List[str]]`. * Change wording in API docs after store -> save change * docs: tag (save_)activations as new in spaCy 4.0 * Fix copied line in morphologizer activations test * Don't train in any test_save_activations test * Rename activations - "probs" -> "probabilities" - "guesses" -> "label_ids", except in the edit tree lemmatizer, where "guesses" -> "tree_ids". * Remove unused W400 warning. This warning was used when we still allowed the user to specify which activations to save. * Formatting fixes Co-authored-by: Sofie Van Landeghem * Replace "kb_ids" by a constant * spancat: replace a cast by an assertion * Fix EOF spacing * Fix comments in test_save_activations tests * Do not set RNG seed in activation saving tests * Revert "spancat: replace a cast by an assertion" This reverts commit 0bd5730d16432443a2b247316928d4f789ad8741. Co-authored-by: Sofie Van Landeghem --- spacy/pipeline/edit_tree_lemmatizer.py | 29 ++++- spacy/pipeline/entity_linker.py | 108 ++++++++++++++++-- spacy/pipeline/morphologizer.pyx | 29 ++++- spacy/pipeline/senter.pyx | 33 ++++-- spacy/pipeline/spancat.py | 30 ++++- spacy/pipeline/tagger.pyx | 37 ++++-- spacy/pipeline/textcat.py | 33 ++++-- spacy/pipeline/textcat_multilabel.py | 14 ++- spacy/pipeline/trainable_pipe.pxd | 1 + spacy/pipeline/trainable_pipe.pyx | 11 +- .../pipeline/test_edit_tree_lemmatizer.py | 25 ++++ spacy/tests/pipeline/test_entity_linker.py | 68 ++++++++++- spacy/tests/pipeline/test_morphologizer.py | 24 ++++ spacy/tests/pipeline/test_senter.py | 25 ++++ spacy/tests/pipeline/test_spancat.py | 20 ++++ spacy/tests/pipeline/test_tagger.py | 22 ++++ spacy/tests/pipeline/test_textcat.py | 43 ++++++- spacy/tokens/doc.pxd | 2 + spacy/tokens/doc.pyi | 3 +- spacy/tokens/doc.pyx | 1 + website/docs/api/doc.md | 33 +++--- website/docs/api/edittreelemmatizer.md | 17 +-- website/docs/api/entitylinker.md | 27 ++--- website/docs/api/morphologizer.md | 17 +-- website/docs/api/sentencerecognizer.md | 11 +- website/docs/api/spancategorizer.md | 17 +-- website/docs/api/tagger.md | 13 ++- website/docs/api/textcategorizer.md | 17 +-- 28 files changed, 580 insertions(+), 130 deletions(-) diff --git a/spacy/pipeline/edit_tree_lemmatizer.py b/spacy/pipeline/edit_tree_lemmatizer.py index b7d615f6d..37aa9663b 100644 --- a/spacy/pipeline/edit_tree_lemmatizer.py +++ b/spacy/pipeline/edit_tree_lemmatizer.py @@ -7,7 +7,7 @@ import numpy as np import srsly from thinc.api import Config, Model, SequenceCategoricalCrossentropy -from thinc.types import Floats2d, Ints1d, Ints2d +from thinc.types import ArrayXd, Floats2d, Ints1d from ._edit_tree_internals.edit_trees import EditTrees from ._edit_tree_internals.schemas import validate_edit_tree @@ -21,6 +21,9 @@ from ..vocab import Vocab from .. import util +ActivationsT = Dict[str, Union[List[Floats2d], List[Ints1d]]] + + default_model_config = """ [model] @architectures = "spacy.Tagger.v2" @@ -49,6 +52,7 @@ DEFAULT_EDIT_TREE_LEMMATIZER_MODEL = Config().from_str(default_model_config)["mo "overwrite": False, "top_k": 1, "scorer": {"@scorers": "spacy.lemmatizer_scorer.v1"}, + "save_activations": False, }, default_score_weights={"lemma_acc": 1.0}, ) @@ -61,6 +65,7 @@ def make_edit_tree_lemmatizer( overwrite: bool, top_k: int, scorer: Optional[Callable], + save_activations: bool, ): """Construct an EditTreeLemmatizer component.""" return EditTreeLemmatizer( @@ -72,6 +77,7 @@ def make_edit_tree_lemmatizer( overwrite=overwrite, top_k=top_k, scorer=scorer, + save_activations=save_activations, ) @@ -91,6 +97,7 @@ class EditTreeLemmatizer(TrainablePipe): overwrite: bool = False, top_k: int = 1, scorer: Optional[Callable] = lemmatizer_score, + save_activations: bool = False, ): """ Construct an edit tree lemmatizer. @@ -102,6 +109,7 @@ class EditTreeLemmatizer(TrainablePipe): frequency in the training data. overwrite (bool): overwrite existing lemma annotations. top_k (int): try to apply at most the k most probable edit trees. + save_activations (bool): save model activations in Doc when annotating. """ self.vocab = vocab self.model = model @@ -116,6 +124,7 @@ class EditTreeLemmatizer(TrainablePipe): self.cfg: Dict[str, Any] = {"labels": []} self.scorer = scorer + self.save_activations = save_activations def get_loss( self, examples: Iterable[Example], scores: List[Floats2d] @@ -144,21 +153,24 @@ class EditTreeLemmatizer(TrainablePipe): return float(loss), d_scores - def predict(self, docs: Iterable[Doc]) -> List[Ints2d]: + def predict(self, docs: Iterable[Doc]) -> ActivationsT: n_docs = len(list(docs)) if not any(len(doc) for doc in docs): # Handle cases where there are no tokens in any docs. n_labels = len(self.cfg["labels"]) - guesses: List[Ints2d] = [ + guesses: List[Ints1d] = [ + self.model.ops.alloc((0,), dtype="i") for doc in docs + ] + scores: List[Floats2d] = [ self.model.ops.alloc((0, n_labels), dtype="i") for doc in docs ] assert len(guesses) == n_docs - return guesses + return {"probabilities": scores, "tree_ids": guesses} scores = self.model.predict(docs) assert len(scores) == n_docs guesses = self._scores2guesses(docs, scores) assert len(guesses) == n_docs - return guesses + return {"probabilities": scores, "tree_ids": guesses} def _scores2guesses(self, docs, scores): guesses = [] @@ -186,8 +198,13 @@ class EditTreeLemmatizer(TrainablePipe): return guesses - def set_annotations(self, docs: Iterable[Doc], batch_tree_ids): + def set_annotations(self, docs: Iterable[Doc], activations: ActivationsT): + batch_tree_ids = activations["tree_ids"] for i, doc in enumerate(docs): + if self.save_activations: + doc.activations[self.name] = {} + for act_name, acts in activations.items(): + doc.activations[self.name][act_name] = acts[i] doc_tree_ids = batch_tree_ids[i] if hasattr(doc_tree_ids, "get"): doc_tree_ids = doc_tree_ids.get() diff --git a/spacy/pipeline/entity_linker.py b/spacy/pipeline/entity_linker.py index 73a90b268..ac05cb840 100644 --- a/spacy/pipeline/entity_linker.py +++ b/spacy/pipeline/entity_linker.py @@ -1,5 +1,7 @@ -from typing import Optional, Iterable, Callable, Dict, Union, List, Any -from thinc.types import Floats2d +from typing import Optional, Iterable, Callable, Dict, Sequence, Union, List, Any +from typing import cast +from numpy import dtype +from thinc.types import Floats1d, Floats2d, Ints1d, Ragged from pathlib import Path from itertools import islice import srsly @@ -21,6 +23,11 @@ from ..util import SimpleFrozenList, registry from .. import util from ..scorer import Scorer + +ActivationsT = Dict[str, Union[List[Ragged], List[str]]] + +KNOWLEDGE_BASE_IDS = "kb_ids" + # See #9050 BACKWARD_OVERWRITE = True @@ -57,6 +64,7 @@ DEFAULT_NEL_MODEL = Config().from_str(default_model_config)["model"] "scorer": {"@scorers": "spacy.entity_linker_scorer.v1"}, "use_gold_ents": True, "threshold": None, + "save_activations": False, }, default_score_weights={ "nel_micro_f": 1.0, @@ -79,6 +87,7 @@ def make_entity_linker( scorer: Optional[Callable], use_gold_ents: bool, threshold: Optional[float] = None, + save_activations: bool, ): """Construct an EntityLinker component. @@ -97,6 +106,7 @@ def make_entity_linker( component must provide entity annotations. threshold (Optional[float]): Confidence threshold for entity predictions. If confidence is below the threshold, prediction is discarded. If None, predictions are not filtered by any threshold. + save_activations (bool): save model activations in Doc when annotating. """ if not model.attrs.get("include_span_maker", False): @@ -128,6 +138,7 @@ def make_entity_linker( scorer=scorer, use_gold_ents=use_gold_ents, threshold=threshold, + save_activations=save_activations, ) @@ -164,6 +175,7 @@ class EntityLinker(TrainablePipe): scorer: Optional[Callable] = entity_linker_score, use_gold_ents: bool, threshold: Optional[float] = None, + save_activations: bool = False, ) -> None: """Initialize an entity linker. @@ -212,6 +224,7 @@ class EntityLinker(TrainablePipe): self.scorer = scorer self.use_gold_ents = use_gold_ents self.threshold = threshold + self.save_activations = save_activations def set_kb(self, kb_loader: Callable[[Vocab], KnowledgeBase]): """Define the KB of this pipe by providing a function that will @@ -397,7 +410,7 @@ class EntityLinker(TrainablePipe): loss = loss / len(entity_encodings) return float(loss), out - def predict(self, docs: Iterable[Doc]) -> List[str]: + def predict(self, docs: Iterable[Doc]) -> ActivationsT: """Apply the pipeline's model to a batch of docs, without modifying them. Returns the KB IDs for each entity in each doc, including NIL if there is no prediction. @@ -410,13 +423,20 @@ class EntityLinker(TrainablePipe): self.validate_kb() entity_count = 0 final_kb_ids: List[str] = [] - xp = self.model.ops.xp + ops = self.model.ops + xp = ops.xp + docs_ents: List[Ragged] = [] + docs_scores: List[Ragged] = [] if not docs: - return final_kb_ids + return {KNOWLEDGE_BASE_IDS: final_kb_ids, "ents": docs_ents, "scores": docs_scores} if isinstance(docs, Doc): docs = [docs] - for i, doc in enumerate(docs): + for doc in docs: + doc_ents: List[Ints1d] = [] + doc_scores: List[Floats1d] = [] if len(doc) == 0: + docs_scores.append(Ragged(ops.alloc1f(0), ops.alloc1i(0))) + docs_ents.append(Ragged(xp.zeros(0, dtype="uint64"), ops.alloc1i(0))) continue sentences = [s for s in doc.sents] # Looping through each entity (TODO: rewrite) @@ -439,14 +459,32 @@ class EntityLinker(TrainablePipe): if ent.label_ in self.labels_discard: # ignoring this entity - setting to NIL final_kb_ids.append(self.NIL) + self._add_activations( + doc_scores=doc_scores, + doc_ents=doc_ents, + scores=[0.0], + ents=[0], + ) else: candidates = list(self.get_candidates(self.kb, ent)) if not candidates: # no prediction possible for this entity - setting to NIL final_kb_ids.append(self.NIL) + self._add_activations( + doc_scores=doc_scores, + doc_ents=doc_ents, + scores=[0.0], + ents=[0], + ) elif len(candidates) == 1 and self.threshold is None: # shortcut for efficiency reasons: take the 1 candidate final_kb_ids.append(candidates[0].entity_) + self._add_activations( + doc_scores=doc_scores, + doc_ents=doc_ents, + scores=[1.0], + ents=[candidates[0].entity_], + ) else: random.shuffle(candidates) # set all prior probabilities to 0 if incl_prior=False @@ -479,27 +517,48 @@ class EntityLinker(TrainablePipe): if self.threshold is None or scores.max() >= self.threshold else EntityLinker.NIL ) + self._add_activations( + doc_scores=doc_scores, + doc_ents=doc_ents, + scores=scores, + ents=[c.entity for c in candidates], + ) + self._add_doc_activations( + docs_scores=docs_scores, + docs_ents=docs_ents, + doc_scores=doc_scores, + doc_ents=doc_ents, + ) if not (len(final_kb_ids) == entity_count): err = Errors.E147.format( method="predict", msg="result variables not of equal length" ) raise RuntimeError(err) - return final_kb_ids + return {KNOWLEDGE_BASE_IDS: final_kb_ids, "ents": docs_ents, "scores": docs_scores} - def set_annotations(self, docs: Iterable[Doc], kb_ids: List[str]) -> None: + def set_annotations(self, docs: Iterable[Doc], activations: ActivationsT) -> None: """Modify a batch of documents, using pre-computed scores. docs (Iterable[Doc]): The documents to modify. - kb_ids (List[str]): The IDs to set, produced by EntityLinker.predict. + activations (ActivationsT): The activations used for setting annotations, produced + by EntityLinker.predict. DOCS: https://spacy.io/api/entitylinker#set_annotations """ + kb_ids = cast(List[str], activations[KNOWLEDGE_BASE_IDS]) count_ents = len([ent for doc in docs for ent in doc.ents]) if count_ents != len(kb_ids): raise ValueError(Errors.E148.format(ents=count_ents, ids=len(kb_ids))) i = 0 overwrite = self.cfg["overwrite"] - for doc in docs: + for j, doc in enumerate(docs): + if self.save_activations: + doc.activations[self.name] = {} + for act_name, acts in activations.items(): + if act_name != KNOWLEDGE_BASE_IDS: + # We only copy activations that are Ragged. + doc.activations[self.name][act_name] = cast(Ragged, acts[j]) + for ent in doc.ents: kb_id = kb_ids[i] i += 1 @@ -598,3 +657,32 @@ class EntityLinker(TrainablePipe): def add_label(self, label): raise NotImplementedError + + def _add_doc_activations( + self, + *, + docs_scores: List[Ragged], + docs_ents: List[Ragged], + doc_scores: List[Floats1d], + doc_ents: List[Ints1d], + ): + if not self.save_activations: + return + ops = self.model.ops + lengths = ops.asarray1i([s.shape[0] for s in doc_scores]) + docs_scores.append(Ragged(ops.flatten(doc_scores), lengths)) + docs_ents.append(Ragged(ops.flatten(doc_ents), lengths)) + + def _add_activations( + self, + *, + doc_scores: List[Floats1d], + doc_ents: List[Ints1d], + scores: Sequence[float], + ents: Sequence[int], + ): + if not self.save_activations: + return + ops = self.model.ops + doc_scores.append(ops.asarray1f(scores)) + doc_ents.append(ops.asarray1i(ents, dtype="uint64")) diff --git a/spacy/pipeline/morphologizer.pyx b/spacy/pipeline/morphologizer.pyx index eec1e42e1..782a1dabe 100644 --- a/spacy/pipeline/morphologizer.pyx +++ b/spacy/pipeline/morphologizer.pyx @@ -1,7 +1,8 @@ # cython: infer_types=True, profile=True, binding=True -from typing import Optional, Union, Dict, Callable +from typing import Callable, Dict, Iterable, List, Optional, Union import srsly from thinc.api import SequenceCategoricalCrossentropy, Model, Config +from thinc.types import Floats2d, Ints1d from itertools import islice from ..tokens.doc cimport Doc @@ -13,7 +14,7 @@ from ..symbols import POS from ..language import Language from ..errors import Errors from .pipe import deserialize_config -from .tagger import Tagger +from .tagger import ActivationsT, Tagger from .. import util from ..scorer import Scorer from ..training import validate_examples, validate_get_examples @@ -52,7 +53,13 @@ DEFAULT_MORPH_MODEL = Config().from_str(default_model_config)["model"] @Language.factory( "morphologizer", assigns=["token.morph", "token.pos"], - default_config={"model": DEFAULT_MORPH_MODEL, "overwrite": True, "extend": False, "scorer": {"@scorers": "spacy.morphologizer_scorer.v1"}}, + default_config={ + "model": DEFAULT_MORPH_MODEL, + "overwrite": True, + "extend": False, + "scorer": {"@scorers": "spacy.morphologizer_scorer.v1"}, + "save_activations": False, + }, default_score_weights={"pos_acc": 0.5, "morph_acc": 0.5, "morph_per_feat": None}, ) def make_morphologizer( @@ -62,8 +69,10 @@ def make_morphologizer( overwrite: bool, extend: bool, scorer: Optional[Callable], + save_activations: bool, ): - return Morphologizer(nlp.vocab, model, name, overwrite=overwrite, extend=extend, scorer=scorer) + return Morphologizer(nlp.vocab, model, name, overwrite=overwrite, extend=extend, scorer=scorer, + save_activations=save_activations) def morphologizer_score(examples, **kwargs): @@ -95,6 +104,7 @@ class Morphologizer(Tagger): overwrite: bool = BACKWARD_OVERWRITE, extend: bool = BACKWARD_EXTEND, scorer: Optional[Callable] = morphologizer_score, + save_activations: bool = False, ): """Initialize a morphologizer. @@ -105,6 +115,7 @@ class Morphologizer(Tagger): scorer (Optional[Callable]): The scoring method. Defaults to Scorer.score_token_attr for the attributes "pos" and "morph" and Scorer.score_token_attr_per_feat for the attribute "morph". + save_activations (bool): save model activations in Doc when annotating. DOCS: https://spacy.io/api/morphologizer#init """ @@ -124,6 +135,7 @@ class Morphologizer(Tagger): } self.cfg = dict(sorted(cfg.items())) self.scorer = scorer + self.save_activations = save_activations @property def labels(self): @@ -217,14 +229,15 @@ class Morphologizer(Tagger): assert len(label_sample) > 0, Errors.E923.format(name=self.name) self.model.initialize(X=doc_sample, Y=label_sample) - def set_annotations(self, docs, batch_tag_ids): + def set_annotations(self, docs: Iterable[Doc], activations: ActivationsT): """Modify a batch of documents, using pre-computed scores. docs (Iterable[Doc]): The documents to modify. - batch_tag_ids: The IDs to set, produced by Morphologizer.predict. + activations (ActivationsT): The activations used for setting annotations, produced by Morphologizer.predict. DOCS: https://spacy.io/api/morphologizer#set_annotations """ + batch_tag_ids = activations["label_ids"] if isinstance(docs, Doc): docs = [docs] cdef Doc doc @@ -236,6 +249,10 @@ class Morphologizer(Tagger): # to allocate a compatible container out of the iterable. labels = tuple(self.labels) for i, doc in enumerate(docs): + if self.save_activations: + doc.activations[self.name] = {} + for act_name, acts in activations.items(): + doc.activations[self.name][act_name] = acts[i] doc_tag_ids = batch_tag_ids[i] if hasattr(doc_tag_ids, "get"): doc_tag_ids = doc_tag_ids.get() diff --git a/spacy/pipeline/senter.pyx b/spacy/pipeline/senter.pyx index 6808fe70e..93a7ee796 100644 --- a/spacy/pipeline/senter.pyx +++ b/spacy/pipeline/senter.pyx @@ -1,13 +1,14 @@ # cython: infer_types=True, profile=True, binding=True -from typing import Optional, Callable +from typing import Dict, Iterable, Optional, Callable, List, Union from itertools import islice import srsly from thinc.api import Model, SequenceCategoricalCrossentropy, Config +from thinc.types import Floats2d, Ints1d from ..tokens.doc cimport Doc -from .tagger import Tagger +from .tagger import ActivationsT, Tagger from ..language import Language from ..errors import Errors from ..scorer import Scorer @@ -38,11 +39,21 @@ DEFAULT_SENTER_MODEL = Config().from_str(default_model_config)["model"] @Language.factory( "senter", assigns=["token.is_sent_start"], - default_config={"model": DEFAULT_SENTER_MODEL, "overwrite": False, "scorer": {"@scorers": "spacy.senter_scorer.v1"}}, + default_config={ + "model": DEFAULT_SENTER_MODEL, + "overwrite": False, + "scorer": {"@scorers": "spacy.senter_scorer.v1"}, + "save_activations": False, + }, default_score_weights={"sents_f": 1.0, "sents_p": 0.0, "sents_r": 0.0}, ) -def make_senter(nlp: Language, name: str, model: Model, overwrite: bool, scorer: Optional[Callable]): - return SentenceRecognizer(nlp.vocab, model, name, overwrite=overwrite, scorer=scorer) +def make_senter(nlp: Language, + name: str, + model: Model, + overwrite: bool, + scorer: Optional[Callable], + save_activations: bool): + return SentenceRecognizer(nlp.vocab, model, name, overwrite=overwrite, scorer=scorer, save_activations=save_activations) def senter_score(examples, **kwargs): @@ -72,6 +83,7 @@ class SentenceRecognizer(Tagger): *, overwrite=BACKWARD_OVERWRITE, scorer=senter_score, + save_activations: bool = False, ): """Initialize a sentence recognizer. @@ -81,6 +93,7 @@ class SentenceRecognizer(Tagger): losses during training. scorer (Optional[Callable]): The scoring method. Defaults to Scorer.score_spans for the attribute "sents". + save_activations (bool): save model activations in Doc when annotating. DOCS: https://spacy.io/api/sentencerecognizer#init """ @@ -90,6 +103,7 @@ class SentenceRecognizer(Tagger): self._rehearsal_model = None self.cfg = {"overwrite": overwrite} self.scorer = scorer + self.save_activations = save_activations @property def labels(self): @@ -107,19 +121,24 @@ class SentenceRecognizer(Tagger): def label_data(self): return None - def set_annotations(self, docs, batch_tag_ids): + def set_annotations(self, docs: Iterable[Doc], activations: ActivationsT): """Modify a batch of documents, using pre-computed scores. docs (Iterable[Doc]): The documents to modify. - batch_tag_ids: The IDs to set, produced by SentenceRecognizer.predict. + activations (ActivationsT): The activations used for setting annotations, produced by SentenceRecognizer.predict. DOCS: https://spacy.io/api/sentencerecognizer#set_annotations """ + batch_tag_ids = activations["label_ids"] if isinstance(docs, Doc): docs = [docs] cdef Doc doc cdef bint overwrite = self.cfg["overwrite"] for i, doc in enumerate(docs): + if self.save_activations: + doc.activations[self.name] = {} + for act_name, acts in activations.items(): + doc.activations[self.name][act_name] = acts[i] doc_tag_ids = batch_tag_ids[i] if hasattr(doc_tag_ids, "get"): doc_tag_ids = doc_tag_ids.get() diff --git a/spacy/pipeline/spancat.py b/spacy/pipeline/spancat.py index 1b7a9eecb..c517991f5 100644 --- a/spacy/pipeline/spancat.py +++ b/spacy/pipeline/spancat.py @@ -1,4 +1,5 @@ from typing import List, Dict, Callable, Tuple, Optional, Iterable, Any, cast +from typing import Union from thinc.api import Config, Model, get_current_ops, set_dropout_rate, Ops from thinc.api import Optimizer from thinc.types import Ragged, Ints2d, Floats2d, Ints1d @@ -16,6 +17,9 @@ from ..errors import Errors from ..util import registry +ActivationsT = Dict[str, Union[Floats2d, Ragged]] + + spancat_default_config = """ [model] @architectures = "spacy.SpanCategorizer.v1" @@ -106,6 +110,7 @@ def build_ngram_range_suggester(min_size: int, max_size: int) -> Suggester: "model": DEFAULT_SPANCAT_MODEL, "suggester": {"@misc": "spacy.ngram_suggester.v1", "sizes": [1, 2, 3]}, "scorer": {"@scorers": "spacy.spancat_scorer.v1"}, + "save_activations": False, }, default_score_weights={"spans_sc_f": 1.0, "spans_sc_p": 0.0, "spans_sc_r": 0.0}, ) @@ -118,6 +123,7 @@ def make_spancat( scorer: Optional[Callable], threshold: float, max_positive: Optional[int], + save_activations: bool, ) -> "SpanCategorizer": """Create a SpanCategorizer component. The span categorizer consists of two parts: a suggester function that proposes candidate spans, and a labeller @@ -138,6 +144,7 @@ def make_spancat( 0.5. max_positive (Optional[int]): Maximum number of labels to consider positive per span. Defaults to None, indicating no limit. + save_activations (bool): save model activations in Doc when annotating. """ return SpanCategorizer( nlp.vocab, @@ -148,6 +155,7 @@ def make_spancat( max_positive=max_positive, name=name, scorer=scorer, + save_activations=save_activations, ) @@ -186,6 +194,7 @@ class SpanCategorizer(TrainablePipe): threshold: float = 0.5, max_positive: Optional[int] = None, scorer: Optional[Callable] = spancat_score, + save_activations: bool = False, ) -> None: """Initialize the span categorizer. vocab (Vocab): The shared vocabulary. @@ -218,6 +227,7 @@ class SpanCategorizer(TrainablePipe): self.model = model self.name = name self.scorer = scorer + self.save_activations = save_activations @property def key(self) -> str: @@ -260,7 +270,7 @@ class SpanCategorizer(TrainablePipe): """ return list(self.labels) - def predict(self, docs: Iterable[Doc]): + def predict(self, docs: Iterable[Doc]) -> ActivationsT: """Apply the pipeline's model to a batch of docs, without modifying them. docs (Iterable[Doc]): The documents to predict. @@ -270,7 +280,7 @@ class SpanCategorizer(TrainablePipe): """ indices = self.suggester(docs, ops=self.model.ops) scores = self.model.predict((docs, indices)) # type: ignore - return indices, scores + return {"indices": indices, "scores": scores} def set_candidates( self, docs: Iterable[Doc], *, candidates_key: str = "candidates" @@ -290,19 +300,29 @@ class SpanCategorizer(TrainablePipe): for index in candidates.dataXd: doc.spans[candidates_key].append(doc[index[0] : index[1]]) - def set_annotations(self, docs: Iterable[Doc], indices_scores) -> None: + def set_annotations(self, docs: Iterable[Doc], activations: ActivationsT) -> None: """Modify a batch of Doc objects, using pre-computed scores. docs (Iterable[Doc]): The documents to modify. - scores: The scores to set, produced by SpanCategorizer.predict. + activations: ActivationsT: The activations, produced by SpanCategorizer.predict. DOCS: https://spacy.io/api/spancategorizer#set_annotations """ labels = self.labels - indices, scores = indices_scores + + indices = activations["indices"] + assert isinstance(indices, Ragged) + scores = cast(Floats2d, activations["scores"]) + offset = 0 for i, doc in enumerate(docs): indices_i = indices[i].dataXd + if self.save_activations: + doc.activations[self.name] = {} + doc.activations[self.name]["indices"] = indices_i + doc.activations[self.name]["scores"] = scores[ + offset : offset + indices.lengths[i] + ] doc.spans[self.key] = self._make_span_group( doc, indices_i, scores[offset : offset + indices.lengths[i]], labels # type: ignore[arg-type] ) diff --git a/spacy/pipeline/tagger.pyx b/spacy/pipeline/tagger.pyx index d6ecbf084..3b4715ce5 100644 --- a/spacy/pipeline/tagger.pyx +++ b/spacy/pipeline/tagger.pyx @@ -1,9 +1,9 @@ # cython: infer_types=True, profile=True, binding=True -from typing import Callable, Optional +from typing import Callable, Dict, Iterable, List, Optional, Union import numpy import srsly from thinc.api import Model, set_dropout_rate, SequenceCategoricalCrossentropy, Config -from thinc.types import Floats2d +from thinc.types import Floats2d, Ints1d import warnings from itertools import islice @@ -22,6 +22,9 @@ from ..training import validate_examples, validate_get_examples from ..util import registry from .. import util + +ActivationsT = Dict[str, Union[List[Floats2d], List[Ints1d]]] + # See #9050 BACKWARD_OVERWRITE = False @@ -45,7 +48,13 @@ DEFAULT_TAGGER_MODEL = Config().from_str(default_model_config)["model"] @Language.factory( "tagger", assigns=["token.tag"], - default_config={"model": DEFAULT_TAGGER_MODEL, "overwrite": False, "scorer": {"@scorers": "spacy.tagger_scorer.v1"}, "neg_prefix": "!"}, + default_config={ + "model": DEFAULT_TAGGER_MODEL, + "overwrite": False, + "scorer": {"@scorers": "spacy.tagger_scorer.v1"}, + "neg_prefix": "!", + "save_activations": False, + }, default_score_weights={"tag_acc": 1.0}, ) def make_tagger( @@ -55,6 +64,7 @@ def make_tagger( overwrite: bool, scorer: Optional[Callable], neg_prefix: str, + save_activations: bool, ): """Construct a part-of-speech tagger component. @@ -63,7 +73,8 @@ def make_tagger( in size, and be normalized as probabilities (all scores between 0 and 1, with the rows summing to 1). """ - return Tagger(nlp.vocab, model, name, overwrite=overwrite, scorer=scorer, neg_prefix=neg_prefix) + return Tagger(nlp.vocab, model, name, overwrite=overwrite, scorer=scorer, neg_prefix=neg_prefix, + save_activations=save_activations) def tagger_score(examples, **kwargs): @@ -89,6 +100,7 @@ class Tagger(TrainablePipe): overwrite=BACKWARD_OVERWRITE, scorer=tagger_score, neg_prefix="!", + save_activations: bool = False, ): """Initialize a part-of-speech tagger. @@ -98,6 +110,7 @@ class Tagger(TrainablePipe): losses during training. scorer (Optional[Callable]): The scoring method. Defaults to Scorer.score_token_attr for the attribute "tag". + save_activations (bool): save model activations in Doc when annotating. DOCS: https://spacy.io/api/tagger#init """ @@ -108,6 +121,7 @@ class Tagger(TrainablePipe): cfg = {"labels": [], "overwrite": overwrite, "neg_prefix": neg_prefix} self.cfg = dict(sorted(cfg.items())) self.scorer = scorer + self.save_activations = save_activations @property def labels(self): @@ -126,7 +140,7 @@ class Tagger(TrainablePipe): """Data about the labels currently added to the component.""" return tuple(self.cfg["labels"]) - def predict(self, docs): + def predict(self, docs) -> ActivationsT: """Apply the pipeline's model to a batch of docs, without modifying them. docs (Iterable[Doc]): The documents to predict. @@ -139,12 +153,12 @@ class Tagger(TrainablePipe): n_labels = len(self.labels) guesses = [self.model.ops.alloc((0, n_labels)) for doc in docs] assert len(guesses) == len(docs) - return guesses + return {"probabilities": guesses, "label_ids": guesses} scores = self.model.predict(docs) assert len(scores) == len(docs), (len(scores), len(docs)) guesses = self._scores2guesses(scores) assert len(guesses) == len(docs) - return guesses + return {"probabilities": scores, "label_ids": guesses} def _scores2guesses(self, scores): guesses = [] @@ -155,14 +169,15 @@ class Tagger(TrainablePipe): guesses.append(doc_guesses) return guesses - def set_annotations(self, docs, batch_tag_ids): + def set_annotations(self, docs: Iterable[Doc], activations: ActivationsT): """Modify a batch of documents, using pre-computed scores. docs (Iterable[Doc]): The documents to modify. - batch_tag_ids: The IDs to set, produced by Tagger.predict. + activations (ActivationsT): The activations used for setting annotations, produced by Tagger.predict. DOCS: https://spacy.io/api/tagger#set_annotations """ + batch_tag_ids = activations["label_ids"] if isinstance(docs, Doc): docs = [docs] cdef Doc doc @@ -170,6 +185,10 @@ class Tagger(TrainablePipe): cdef bint overwrite = self.cfg["overwrite"] labels = self.labels for i, doc in enumerate(docs): + if self.save_activations: + doc.activations[self.name] = {} + for act_name, acts in activations.items(): + doc.activations[self.name][act_name] = acts[i] doc_tag_ids = batch_tag_ids[i] if hasattr(doc_tag_ids, "get"): doc_tag_ids = doc_tag_ids.get() diff --git a/spacy/pipeline/textcat.py b/spacy/pipeline/textcat.py index c45f819fc..506cdb61c 100644 --- a/spacy/pipeline/textcat.py +++ b/spacy/pipeline/textcat.py @@ -1,4 +1,4 @@ -from typing import Iterable, Tuple, Optional, Dict, List, Callable, Any +from typing import Iterable, Tuple, Optional, Dict, List, Callable, Any, Union from thinc.api import get_array_module, Model, Optimizer, set_dropout_rate, Config from thinc.types import Floats2d import numpy @@ -14,6 +14,9 @@ from ..util import registry from ..vocab import Vocab +ActivationsT = Dict[str, Floats2d] + + single_label_default_config = """ [model] @architectures = "spacy.TextCatEnsemble.v2" @@ -75,6 +78,7 @@ subword_features = true "threshold": 0.5, "model": DEFAULT_SINGLE_TEXTCAT_MODEL, "scorer": {"@scorers": "spacy.textcat_scorer.v1"}, + "save_activations": False, }, default_score_weights={ "cats_score": 1.0, @@ -96,6 +100,7 @@ def make_textcat( model: Model[List[Doc], List[Floats2d]], threshold: float, scorer: Optional[Callable], + save_activations: bool, ) -> "TextCategorizer": """Create a TextCategorizer component. The text categorizer predicts categories over a whole document. It can learn one or more labels, and the labels are considered @@ -105,8 +110,16 @@ def make_textcat( scores for each category. threshold (float): Cutoff to consider a prediction "positive". scorer (Optional[Callable]): The scoring method. + save_activations (bool): save model activations in Doc when annotating. """ - return TextCategorizer(nlp.vocab, model, name, threshold=threshold, scorer=scorer) + return TextCategorizer( + nlp.vocab, + model, + name, + threshold=threshold, + scorer=scorer, + save_activations=save_activations, + ) def textcat_score(examples: Iterable[Example], **kwargs) -> Dict[str, Any]: @@ -137,6 +150,7 @@ class TextCategorizer(TrainablePipe): *, threshold: float, scorer: Optional[Callable] = textcat_score, + save_activations: bool = False, ) -> None: """Initialize a text categorizer for single-label classification. @@ -157,6 +171,7 @@ class TextCategorizer(TrainablePipe): cfg = {"labels": [], "threshold": threshold, "positive_label": None} self.cfg = dict(cfg) self.scorer = scorer + self.save_activations = save_activations @property def support_missing_values(self): @@ -181,7 +196,7 @@ class TextCategorizer(TrainablePipe): """ return self.labels # type: ignore[return-value] - def predict(self, docs: Iterable[Doc]): + def predict(self, docs: Iterable[Doc]) -> ActivationsT: """Apply the pipeline's model to a batch of docs, without modifying them. docs (Iterable[Doc]): The documents to predict. @@ -194,12 +209,12 @@ class TextCategorizer(TrainablePipe): tensors = [doc.tensor for doc in docs] xp = self.model.ops.xp scores = xp.zeros((len(list(docs)), len(self.labels))) - return scores + return {"probabilities": scores} scores = self.model.predict(docs) scores = self.model.ops.asarray(scores) - return scores + return {"probabilities": scores} - def set_annotations(self, docs: Iterable[Doc], scores) -> None: + def set_annotations(self, docs: Iterable[Doc], activations: ActivationsT) -> None: """Modify a batch of Doc objects, using pre-computed scores. docs (Iterable[Doc]): The documents to modify. @@ -207,9 +222,13 @@ class TextCategorizer(TrainablePipe): DOCS: https://spacy.io/api/textcategorizer#set_annotations """ + probs = activations["probabilities"] for i, doc in enumerate(docs): + if self.save_activations: + doc.activations[self.name] = {} + doc.activations[self.name]["probabilities"] = probs[i] for j, label in enumerate(self.labels): - doc.cats[label] = float(scores[i, j]) + doc.cats[label] = float(probs[i, j]) def update( self, diff --git a/spacy/pipeline/textcat_multilabel.py b/spacy/pipeline/textcat_multilabel.py index e33a885f8..3a6dd0b0c 100644 --- a/spacy/pipeline/textcat_multilabel.py +++ b/spacy/pipeline/textcat_multilabel.py @@ -1,4 +1,4 @@ -from typing import Iterable, Optional, Dict, List, Callable, Any +from typing import Iterable, Optional, Dict, List, Callable, Any, Union from thinc.types import Floats2d from thinc.api import Model, Config @@ -75,6 +75,7 @@ subword_features = true "threshold": 0.5, "model": DEFAULT_MULTI_TEXTCAT_MODEL, "scorer": {"@scorers": "spacy.textcat_multilabel_scorer.v1"}, + "save_activations": False, }, default_score_weights={ "cats_score": 1.0, @@ -96,6 +97,7 @@ def make_multilabel_textcat( model: Model[List[Doc], List[Floats2d]], threshold: float, scorer: Optional[Callable], + save_activations: bool, ) -> "TextCategorizer": """Create a TextCategorizer component. The text categorizer predicts categories over a whole document. It can learn one or more labels, and the labels are considered @@ -107,7 +109,12 @@ def make_multilabel_textcat( threshold (float): Cutoff to consider a prediction "positive". """ return MultiLabel_TextCategorizer( - nlp.vocab, model, name, threshold=threshold, scorer=scorer + nlp.vocab, + model, + name, + threshold=threshold, + scorer=scorer, + save_activations=save_activations, ) @@ -139,6 +146,7 @@ class MultiLabel_TextCategorizer(TextCategorizer): *, threshold: float, scorer: Optional[Callable] = textcat_multilabel_score, + save_activations: bool = False, ) -> None: """Initialize a text categorizer for multi-label classification. @@ -147,6 +155,7 @@ class MultiLabel_TextCategorizer(TextCategorizer): name (str): The component instance name, used to add entries to the losses during training. threshold (float): Cutoff to consider a prediction "positive". + save_activations (bool): save model activations in Doc when annotating. DOCS: https://spacy.io/api/textcategorizer#init """ @@ -157,6 +166,7 @@ class MultiLabel_TextCategorizer(TextCategorizer): cfg = {"labels": [], "threshold": threshold} self.cfg = dict(cfg) self.scorer = scorer + self.save_activations = save_activations @property def support_missing_values(self): diff --git a/spacy/pipeline/trainable_pipe.pxd b/spacy/pipeline/trainable_pipe.pxd index 65daa8b22..180f86f45 100644 --- a/spacy/pipeline/trainable_pipe.pxd +++ b/spacy/pipeline/trainable_pipe.pxd @@ -6,3 +6,4 @@ cdef class TrainablePipe(Pipe): cdef public object model cdef public object cfg cdef public object scorer + cdef bint _save_activations diff --git a/spacy/pipeline/trainable_pipe.pyx b/spacy/pipeline/trainable_pipe.pyx index 76b0733cf..c82f2830c 100644 --- a/spacy/pipeline/trainable_pipe.pyx +++ b/spacy/pipeline/trainable_pipe.pyx @@ -2,11 +2,12 @@ from typing import Iterable, Iterator, Optional, Dict, Tuple, Callable import srsly from thinc.api import set_dropout_rate, Model, Optimizer +import warnings from ..tokens.doc cimport Doc from ..training import validate_examples -from ..errors import Errors +from ..errors import Errors, Warnings from .pipe import Pipe, deserialize_config from .. import util from ..vocab import Vocab @@ -342,3 +343,11 @@ cdef class TrainablePipe(Pipe): deserialize["model"] = load_model util.from_disk(path, deserialize, exclude) return self + + @property + def save_activations(self): + return self._save_activations + + @save_activations.setter + def save_activations(self, save_activations: bool): + self._save_activations = save_activations diff --git a/spacy/tests/pipeline/test_edit_tree_lemmatizer.py b/spacy/tests/pipeline/test_edit_tree_lemmatizer.py index cf541e301..ad2e56729 100644 --- a/spacy/tests/pipeline/test_edit_tree_lemmatizer.py +++ b/spacy/tests/pipeline/test_edit_tree_lemmatizer.py @@ -1,3 +1,4 @@ +from typing import cast import pickle import pytest from hypothesis import given @@ -6,6 +7,7 @@ from spacy import util from spacy.lang.en import English from spacy.language import Language from spacy.pipeline._edit_tree_internals.edit_trees import EditTrees +from spacy.pipeline.trainable_pipe import TrainablePipe from spacy.training import Example from spacy.strings import StringStore from spacy.util import make_tempdir @@ -278,3 +280,26 @@ def test_empty_strings(): no_change = trees.add("xyz", "xyz") empty = trees.add("", "") assert no_change == empty + + +def test_save_activations(): + nlp = English() + lemmatizer = cast(TrainablePipe, nlp.add_pipe("trainable_lemmatizer")) + lemmatizer.min_tree_freq = 1 + train_examples = [] + for t in TRAIN_DATA: + train_examples.append(Example.from_dict(nlp.make_doc(t[0]), t[1])) + nlp.initialize(get_examples=lambda: train_examples) + nO = lemmatizer.model.get_dim("nO") + + doc = nlp("This is a test.") + assert "trainable_lemmatizer" not in doc.activations + + lemmatizer.save_activations = True + doc = nlp("This is a test.") + assert list(doc.activations["trainable_lemmatizer"].keys()) == [ + "probabilities", + "tree_ids", + ] + assert doc.activations["trainable_lemmatizer"]["probabilities"].shape == (5, nO) + assert doc.activations["trainable_lemmatizer"]["tree_ids"].shape == (5,) diff --git a/spacy/tests/pipeline/test_entity_linker.py b/spacy/tests/pipeline/test_entity_linker.py index 82bc976bb..75d1feea5 100644 --- a/spacy/tests/pipeline/test_entity_linker.py +++ b/spacy/tests/pipeline/test_entity_linker.py @@ -1,7 +1,8 @@ -from typing import Callable, Iterable, Dict, Any +from typing import Callable, Iterable, Dict, Any, cast import pytest from numpy.testing import assert_equal +from thinc.types import Ragged from spacy import registry, util from spacy.attrs import ENT_KB_ID @@ -9,7 +10,7 @@ from spacy.compat import pickle from spacy.kb import Candidate, KnowledgeBase, get_candidates from spacy.lang.en import English from spacy.ml import load_kb -from spacy.pipeline import EntityLinker +from spacy.pipeline import EntityLinker, TrainablePipe from spacy.pipeline.legacy import EntityLinker_v1 from spacy.pipeline.tok2vec import DEFAULT_TOK2VEC_MODEL from spacy.scorer import Scorer @@ -1176,3 +1177,66 @@ def test_threshold(meet_threshold: bool, config: Dict[str, Any]): assert len(doc.ents) == 1 assert doc.ents[0].kb_id_ == entity_id if meet_threshold else EntityLinker.NIL + + +def test_save_activations(): + nlp = English() + vector_length = 3 + assert "Q2146908" not in nlp.vocab.strings + + # Convert the texts to docs to make sure we have doc.ents set for the training examples + train_examples = [] + for text, annotation in TRAIN_DATA: + doc = nlp(text) + train_examples.append(Example.from_dict(doc, annotation)) + + def create_kb(vocab): + # create artificial KB - assign same prior weight to the two russ cochran's + # Q2146908 (Russ Cochran): American golfer + # Q7381115 (Russ Cochran): publisher + mykb = KnowledgeBase(vocab, entity_vector_length=vector_length) + mykb.add_entity(entity="Q2146908", freq=12, entity_vector=[6, -4, 3]) + mykb.add_entity(entity="Q7381115", freq=12, entity_vector=[9, 1, -7]) + mykb.add_alias( + alias="Russ Cochran", + entities=["Q2146908", "Q7381115"], + probabilities=[0.5, 0.5], + ) + return mykb + + # Create the Entity Linker component and add it to the pipeline + entity_linker = cast(TrainablePipe, nlp.add_pipe("entity_linker", last=True)) + assert isinstance(entity_linker, EntityLinker) + entity_linker.set_kb(create_kb) + assert "Q2146908" in entity_linker.vocab.strings + assert "Q2146908" in entity_linker.kb.vocab.strings + + # initialize the NEL pipe + nlp.initialize(get_examples=lambda: train_examples) + + nO = entity_linker.model.get_dim("nO") + + nlp.add_pipe("sentencizer", first=True) + patterns = [ + {"label": "PERSON", "pattern": [{"LOWER": "russ"}, {"LOWER": "cochran"}]}, + {"label": "ORG", "pattern": [{"LOWER": "ec"}, {"LOWER": "comics"}]}, + ] + ruler = nlp.add_pipe("entity_ruler", before="entity_linker") + ruler.add_patterns(patterns) + + doc = nlp("Russ Cochran was a publisher") + assert "entity_linker" not in doc.activations + + entity_linker.save_activations = True + doc = nlp("Russ Cochran was a publisher") + assert set(doc.activations["entity_linker"].keys()) == {"ents", "scores"} + ents = doc.activations["entity_linker"]["ents"] + assert isinstance(ents, Ragged) + assert ents.data.shape == (2, 1) + assert ents.data.dtype == "uint64" + assert ents.lengths.shape == (1,) + scores = doc.activations["entity_linker"]["scores"] + assert isinstance(scores, Ragged) + assert scores.data.shape == (2, 1) + assert scores.data.dtype == "float32" + assert scores.lengths.shape == (1,) diff --git a/spacy/tests/pipeline/test_morphologizer.py b/spacy/tests/pipeline/test_morphologizer.py index 33696bfd8..70fc77304 100644 --- a/spacy/tests/pipeline/test_morphologizer.py +++ b/spacy/tests/pipeline/test_morphologizer.py @@ -1,3 +1,4 @@ +from typing import cast import pytest from numpy.testing import assert_equal @@ -7,6 +8,7 @@ from spacy.lang.en import English from spacy.language import Language from spacy.tests.util import make_tempdir from spacy.morphology import Morphology +from spacy.pipeline import TrainablePipe from spacy.attrs import MORPH from spacy.tokens import Doc @@ -197,3 +199,25 @@ def test_overfitting_IO(): gold_pos_tags = ["NOUN", "NOUN", "NOUN", "NOUN"] assert [str(t.morph) for t in doc] == gold_morphs assert [t.pos_ for t in doc] == gold_pos_tags + + +def test_save_activations(): + nlp = English() + morphologizer = cast(TrainablePipe, nlp.add_pipe("morphologizer")) + train_examples = [] + for inst in TRAIN_DATA: + train_examples.append(Example.from_dict(nlp.make_doc(inst[0]), inst[1])) + nlp.initialize(get_examples=lambda: train_examples) + + doc = nlp("This is a test.") + assert "morphologizer" not in doc.activations + + morphologizer.save_activations = True + doc = nlp("This is a test.") + assert "morphologizer" in doc.activations + assert set(doc.activations["morphologizer"].keys()) == { + "label_ids", + "probabilities", + } + assert doc.activations["morphologizer"]["probabilities"].shape == (5, 6) + assert doc.activations["morphologizer"]["label_ids"].shape == (5,) diff --git a/spacy/tests/pipeline/test_senter.py b/spacy/tests/pipeline/test_senter.py index 047f59bef..3deac9e9a 100644 --- a/spacy/tests/pipeline/test_senter.py +++ b/spacy/tests/pipeline/test_senter.py @@ -1,3 +1,4 @@ +from typing import cast import pytest from numpy.testing import assert_equal from spacy.attrs import SENT_START @@ -6,6 +7,7 @@ from spacy import util from spacy.training import Example from spacy.lang.en import English from spacy.language import Language +from spacy.pipeline import TrainablePipe from spacy.tests.util import make_tempdir @@ -101,3 +103,26 @@ def test_overfitting_IO(): # test internal pipe labels vs. Language.pipe_labels with hidden labels assert nlp.get_pipe("senter").labels == ("I", "S") assert "senter" not in nlp.pipe_labels + + +def test_save_activations(): + # Test if activations are correctly added to Doc when requested. + nlp = English() + senter = cast(TrainablePipe, nlp.add_pipe("senter")) + + train_examples = [] + for t in TRAIN_DATA: + train_examples.append(Example.from_dict(nlp.make_doc(t[0]), t[1])) + + nlp.initialize(get_examples=lambda: train_examples) + nO = senter.model.get_dim("nO") + + doc = nlp("This is a test.") + assert "senter" not in doc.activations + + senter.save_activations = True + doc = nlp("This is a test.") + assert "senter" in doc.activations + assert set(doc.activations["senter"].keys()) == {"label_ids", "probabilities"} + assert doc.activations["senter"]["probabilities"].shape == (5, nO) + assert doc.activations["senter"]["label_ids"].shape == (5,) diff --git a/spacy/tests/pipeline/test_spancat.py b/spacy/tests/pipeline/test_spancat.py index 95e9aeb57..4fb26c7e7 100644 --- a/spacy/tests/pipeline/test_spancat.py +++ b/spacy/tests/pipeline/test_spancat.py @@ -419,3 +419,23 @@ def test_set_candidates(): assert len(docs[0].spans["candidates"]) == 9 assert docs[0].spans["candidates"][0].text == "Just" assert docs[0].spans["candidates"][4].text == "Just a" + + +def test_save_activations(): + # Test if activations are correctly added to Doc when requested. + nlp = English() + spancat = nlp.add_pipe("spancat", config={"spans_key": SPAN_KEY}) + train_examples = make_examples(nlp) + nlp.initialize(get_examples=lambda: train_examples) + nO = spancat.model.get_dim("nO") + assert nO == 2 + assert set(spancat.labels) == {"LOC", "PERSON"} + + doc = nlp("This is a test.") + assert "spancat" not in doc.activations + + spancat.save_activations = True + doc = nlp("This is a test.") + assert set(doc.activations["spancat"].keys()) == {"indices", "scores"} + assert doc.activations["spancat"]["indices"].shape == (12, 2) + assert doc.activations["spancat"]["scores"].shape == (12, nO) diff --git a/spacy/tests/pipeline/test_tagger.py b/spacy/tests/pipeline/test_tagger.py index 96e75851e..a0c71198e 100644 --- a/spacy/tests/pipeline/test_tagger.py +++ b/spacy/tests/pipeline/test_tagger.py @@ -1,3 +1,4 @@ +from typing import cast import pytest from numpy.testing import assert_equal from spacy.attrs import TAG @@ -6,6 +7,7 @@ from spacy import util from spacy.training import Example from spacy.lang.en import English from spacy.language import Language +from spacy.pipeline import TrainablePipe from thinc.api import compounding from ..util import make_tempdir @@ -211,6 +213,26 @@ def test_overfitting_IO(): assert doc3[0].tag_ != "N" +def test_save_activations(): + # Test if activations are correctly added to Doc when requested. + nlp = English() + tagger = cast(TrainablePipe, nlp.add_pipe("tagger")) + train_examples = [] + for t in TRAIN_DATA: + train_examples.append(Example.from_dict(nlp.make_doc(t[0]), t[1])) + nlp.initialize(get_examples=lambda: train_examples) + + doc = nlp("This is a test.") + assert "tagger" not in doc.activations + + tagger.save_activations = True + doc = nlp("This is a test.") + assert "tagger" in doc.activations + assert set(doc.activations["tagger"].keys()) == {"label_ids", "probabilities"} + assert doc.activations["tagger"]["probabilities"].shape == (5, len(TAGS)) + assert doc.activations["tagger"]["label_ids"].shape == (5,) + + def test_tagger_requires_labels(): nlp = English() nlp.add_pipe("tagger") diff --git a/spacy/tests/pipeline/test_textcat.py b/spacy/tests/pipeline/test_textcat.py index 0bb036a33..c1f61a3c0 100644 --- a/spacy/tests/pipeline/test_textcat.py +++ b/spacy/tests/pipeline/test_textcat.py @@ -1,3 +1,4 @@ +from typing import cast import random import numpy.random @@ -11,7 +12,7 @@ from spacy import util from spacy.cli.evaluate import print_prf_per_type, print_textcats_auc_per_cat from spacy.lang.en import English from spacy.language import Language -from spacy.pipeline import TextCategorizer +from spacy.pipeline import TextCategorizer, TrainablePipe from spacy.pipeline.textcat import single_label_bow_config from spacy.pipeline.textcat import single_label_cnn_config from spacy.pipeline.textcat import single_label_default_config @@ -285,7 +286,7 @@ def test_issue9904(): nlp.initialize(get_examples) examples = get_examples() - scores = textcat.predict([eg.predicted for eg in examples]) + scores = textcat.predict([eg.predicted for eg in examples])["probabilities"] loss = textcat.get_loss(examples, scores)[0] loss_double_bs = textcat.get_loss(examples * 2, scores.repeat(2, axis=0))[0] @@ -871,3 +872,41 @@ def test_textcat_multi_threshold(): scores = nlp.evaluate(train_examples, scorer_cfg={"threshold": 0}) assert scores["cats_f_per_type"]["POSITIVE"]["r"] == 1.0 + + +def test_save_activations(): + nlp = English() + textcat = cast(TrainablePipe, nlp.add_pipe("textcat")) + + train_examples = [] + for text, annotations in TRAIN_DATA_SINGLE_LABEL: + train_examples.append(Example.from_dict(nlp.make_doc(text), annotations)) + nlp.initialize(get_examples=lambda: train_examples) + nO = textcat.model.get_dim("nO") + + doc = nlp("This is a test.") + assert "textcat" not in doc.activations + + textcat.save_activations = True + doc = nlp("This is a test.") + assert list(doc.activations["textcat"].keys()) == ["probabilities"] + assert doc.activations["textcat"]["probabilities"].shape == (nO,) + + +def test_save_activations_multi(): + nlp = English() + textcat = cast(TrainablePipe, nlp.add_pipe("textcat_multilabel")) + + train_examples = [] + for text, annotations in TRAIN_DATA_MULTI_LABEL: + train_examples.append(Example.from_dict(nlp.make_doc(text), annotations)) + nlp.initialize(get_examples=lambda: train_examples) + nO = textcat.model.get_dim("nO") + + doc = nlp("This is a test.") + assert "textcat_multilabel" not in doc.activations + + textcat.save_activations = True + doc = nlp("This is a test.") + assert list(doc.activations["textcat_multilabel"].keys()) == ["probabilities"] + assert doc.activations["textcat_multilabel"]["probabilities"].shape == (nO,) diff --git a/spacy/tokens/doc.pxd b/spacy/tokens/doc.pxd index 57d087958..83a940cbb 100644 --- a/spacy/tokens/doc.pxd +++ b/spacy/tokens/doc.pxd @@ -50,6 +50,8 @@ cdef class Doc: cdef public float sentiment + cdef public dict activations + cdef public dict user_hooks cdef public dict user_token_hooks cdef public dict user_span_hooks diff --git a/spacy/tokens/doc.pyi b/spacy/tokens/doc.pyi index ae1324a8a..763c1fd2f 100644 --- a/spacy/tokens/doc.pyi +++ b/spacy/tokens/doc.pyi @@ -1,7 +1,7 @@ from typing import Callable, Protocol, Iterable, Iterator, Optional from typing import Union, Tuple, List, Dict, Any, overload from cymem.cymem import Pool -from thinc.types import Floats1d, Floats2d, Ints2d +from thinc.types import ArrayXd, Floats1d, Floats2d, Ints2d, Ragged from .span import Span from .token import Token from .span_groups import SpanGroups @@ -22,6 +22,7 @@ class Doc: max_length: int length: int sentiment: float + activations: Dict[str, Dict[str, Union[ArrayXd, Ragged]]] cats: Dict[str, float] user_hooks: Dict[str, Callable[..., Any]] user_token_hooks: Dict[str, Callable[..., Any]] diff --git a/spacy/tokens/doc.pyx b/spacy/tokens/doc.pyx index 85d76efb3..6969515c3 100644 --- a/spacy/tokens/doc.pyx +++ b/spacy/tokens/doc.pyx @@ -245,6 +245,7 @@ cdef class Doc: self.length = 0 self.sentiment = 0.0 self.cats = {} + self.activations = {} self.user_hooks = {} self.user_token_hooks = {} self.user_span_hooks = {} diff --git a/website/docs/api/doc.md b/website/docs/api/doc.md index f97f4ad83..136e7785d 100644 --- a/website/docs/api/doc.md +++ b/website/docs/api/doc.md @@ -751,22 +751,23 @@ The L2 norm of the document's vector representation. ## Attributes {#attributes} -| Name | Description | -| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | -| `text` | A string representation of the document text. ~~str~~ | -| `text_with_ws` | An alias of `Doc.text`, provided for duck-type compatibility with `Span` and `Token`. ~~str~~ | -| `mem` | The document's local memory heap, for all C data it owns. ~~cymem.Pool~~ | -| `vocab` | The store of lexical types. ~~Vocab~~ | -| `tensor` 2 | Container for dense vector representations. ~~numpy.ndarray~~ | -| `user_data` | A generic storage area, for user custom data. ~~Dict[str, Any]~~ | -| `lang` 2.1 | Language of the document's vocabulary. ~~int~~ | -| `lang_` 2.1 | Language of the document's vocabulary. ~~str~~ | -| `sentiment` | The document's positivity/negativity score, if available. ~~float~~ | -| `user_hooks` | A dictionary that allows customization of the `Doc`'s properties. ~~Dict[str, Callable]~~ | -| `user_token_hooks` | A dictionary that allows customization of properties of `Token` children. ~~Dict[str, Callable]~~ | -| `user_span_hooks` | A dictionary that allows customization of properties of `Span` children. ~~Dict[str, Callable]~~ | -| `has_unknown_spaces` | Whether the document was constructed without known spacing between tokens (typically when created from gold tokenization). ~~bool~~ | -| `_` | User space for adding custom [attribute extensions](/usage/processing-pipelines#custom-components-attributes). ~~Underscore~~ | +| Name | Description | +| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `text` | A string representation of the document text. ~~str~~ | +| `text_with_ws` | An alias of `Doc.text`, provided for duck-type compatibility with `Span` and `Token`. ~~str~~ | +| `mem` | The document's local memory heap, for all C data it owns. ~~cymem.Pool~~ | +| `vocab` | The store of lexical types. ~~Vocab~~ | +| `tensor` 2 | Container for dense vector representations. ~~numpy.ndarray~~ | +| `user_data` | A generic storage area, for user custom data. ~~Dict[str, Any]~~ | +| `lang` 2.1 | Language of the document's vocabulary. ~~int~~ | +| `lang_` 2.1 | Language of the document's vocabulary. ~~str~~ | +| `sentiment` | The document's positivity/negativity score, if available. ~~float~~ | +| `user_hooks` | A dictionary that allows customization of the `Doc`'s properties. ~~Dict[str, Callable]~~ | +| `user_token_hooks` | A dictionary that allows customization of properties of `Token` children. ~~Dict[str, Callable]~~ | +| `user_span_hooks` | A dictionary that allows customization of properties of `Span` children. ~~Dict[str, Callable]~~ | +| `has_unknown_spaces` | Whether the document was constructed without known spacing between tokens (typically when created from gold tokenization). ~~bool~~ | +| `_` | User space for adding custom [attribute extensions](/usage/processing-pipelines#custom-components-attributes). ~~Underscore~~ | +| `activations` 4.0 | A dictionary of activations per trainable pipe (available when the `save_activations` option of a pipe is enabled). ~~Dict[str, Option[Any]]~~ | ## Serialization fields {#serialization-fields} diff --git a/website/docs/api/edittreelemmatizer.md b/website/docs/api/edittreelemmatizer.md index 63e4bf910..8bee74316 100644 --- a/website/docs/api/edittreelemmatizer.md +++ b/website/docs/api/edittreelemmatizer.md @@ -44,14 +44,15 @@ architectures and their arguments and hyperparameters. > nlp.add_pipe("trainable_lemmatizer", config=config, name="lemmatizer") > ``` -| Setting | Description | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `model` | A model instance that predicts the edit tree probabilities. The output vectors should match the number of edit trees in size, and be normalized as probabilities (all scores between 0 and 1, with the rows summing to `1`). Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | -| `backoff` | ~~Token~~ attribute to use when no applicable edit tree is found. Defaults to `orth`. ~~str~~ | -| `min_tree_freq` | Minimum frequency of an edit tree in the training set to be used. Defaults to `3`. ~~int~~ | -| `overwrite` | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ | -| `top_k` | The number of most probable edit trees to try before resorting to `backoff`. Defaults to `1`. ~~int~~ | -| `scorer` | The scoring method. Defaults to [`Scorer.score_token_attr`](/api/scorer#score_token_attr) for the attribute `"lemma"`. ~~Optional[Callable]~~ | +| Setting | Description | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `model` | A model instance that predicts the edit tree probabilities. The output vectors should match the number of edit trees in size, and be normalized as probabilities (all scores between 0 and 1, with the rows summing to `1`). Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | +| `backoff` | ~~Token~~ attribute to use when no applicable edit tree is found. Defaults to `orth`. ~~str~~ | +| `min_tree_freq` | Minimum frequency of an edit tree in the training set to be used. Defaults to `3`. ~~int~~ | +| `overwrite` | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ | +| `top_k` | The number of most probable edit trees to try before resorting to `backoff`. Defaults to `1`. ~~int~~ | +| `scorer` | The scoring method. Defaults to [`Scorer.score_token_attr`](/api/scorer#score_token_attr) for the attribute `"lemma"`. ~~Optional[Callable]~~ | +| `save_activations` 4.0 | Save activations in `Doc` when annotating. Saved activations are `"probabilities"` and `"tree_ids"`. ~~Union[bool, list[str]]~~ | ```python %%GITHUB_SPACY/spacy/pipeline/edit_tree_lemmatizer.py diff --git a/website/docs/api/entitylinker.md b/website/docs/api/entitylinker.md index 43e08a39c..07dd02634 100644 --- a/website/docs/api/entitylinker.md +++ b/website/docs/api/entitylinker.md @@ -52,19 +52,20 @@ architectures and their arguments and hyperparameters. > nlp.add_pipe("entity_linker", config=config) > ``` -| Setting | Description | -| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `labels_discard` | NER labels that will automatically get a "NIL" prediction. Defaults to `[]`. ~~Iterable[str]~~ | -| `n_sents` | The number of neighbouring sentences to take into account. Defaults to 0. ~~int~~ | -| `incl_prior` | Whether or not to include prior probabilities from the KB in the model. Defaults to `True`. ~~bool~~ | -| `incl_context` | Whether or not to include the local context in the model. Defaults to `True`. ~~bool~~ | -| `model` | The [`Model`](https://thinc.ai/docs/api-model) powering the pipeline component. Defaults to [EntityLinker](/api/architectures#EntityLinker). ~~Model~~ | -| `entity_vector_length` | Size of encoding vectors in the KB. Defaults to `64`. ~~int~~ | -| `use_gold_ents` | Whether to copy entities from the gold docs or not. Defaults to `True`. If `False`, entities must be set in the training data or by an annotating component in the pipeline. ~~int~~ | -| `get_candidates` | Function that generates plausible candidates for a given `Span` object. Defaults to [CandidateGenerator](/api/architectures#CandidateGenerator), a function looking up exact, case-dependent aliases in the KB. ~~Callable[[KnowledgeBase, Span], Iterable[Candidate]]~~ | -| `overwrite` 3.2 | Whether existing annotation is overwritten. Defaults to `True`. ~~bool~~ | -| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_links`](/api/scorer#score_links). ~~Optional[Callable]~~ | -| `threshold` 3.4 | Confidence threshold for entity predictions. The default of `None` implies that all predictions are accepted, otherwise those with a score beneath the treshold are discarded. If there are no predictions with scores above the threshold, the linked entity is `NIL`. ~~Optional[float]~~ | +| Setting | Description | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `labels_discard` | NER labels that will automatically get a "NIL" prediction. Defaults to `[]`. ~~Iterable[str]~~ | +| `n_sents` | The number of neighbouring sentences to take into account. Defaults to 0. ~~int~~ | +| `incl_prior` | Whether or not to include prior probabilities from the KB in the model. Defaults to `True`. ~~bool~~ | +| `incl_context` | Whether or not to include the local context in the model. Defaults to `True`. ~~bool~~ | +| `model` | The [`Model`](https://thinc.ai/docs/api-model) powering the pipeline component. Defaults to [EntityLinker](/api/architectures#EntityLinker). ~~Model~~ | +| `entity_vector_length` | Size of encoding vectors in the KB. Defaults to `64`. ~~int~~ | +| `use_gold_ents` | Whether to copy entities from the gold docs or not. Defaults to `True`. If `False`, entities must be set in the training data or by an annotating component in the pipeline. ~~int~~ | +| `get_candidates` | Function that generates plausible candidates for a given `Span` object. Defaults to [CandidateGenerator](/api/architectures#CandidateGenerator), a function looking up exact, case-dependent aliases in the KB. ~~Callable[[KnowledgeBase, Span], Iterable[Candidate]]~~ | +| `overwrite` 3.2 | Whether existing annotation is overwritten. Defaults to `True`. ~~bool~~ | +| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_links`](/api/scorer#score_links). ~~Optional[Callable]~~ | +| `save_activations` 4.0 | Save activations in `Doc` when annotating. Saved activations are `"ents"` and `"scores"`. ~~Union[bool, list[str]]~~ | +| `threshold` 3.4 | Confidence threshold for entity predictions. The default of `None` implies that all predictions are accepted, otherwise those with a score beneath the treshold are discarded. If there are no predictions with scores above the threshold, the linked entity is `NIL`. ~~Optional[float]~~ | ```python %%GITHUB_SPACY/spacy/pipeline/entity_linker.py diff --git a/website/docs/api/morphologizer.md b/website/docs/api/morphologizer.md index fda6d1fa6..97444b157 100644 --- a/website/docs/api/morphologizer.md +++ b/website/docs/api/morphologizer.md @@ -42,12 +42,13 @@ architectures and their arguments and hyperparameters. > nlp.add_pipe("morphologizer", config=config) > ``` -| Setting | Description | -| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `model` | The model to use. Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | -| `overwrite` 3.2 | Whether the values of existing features are overwritten. Defaults to `True`. ~~bool~~ | -| `extend` 3.2 | Whether existing feature types (whose values may or may not be overwritten depending on `overwrite`) are preserved. Defaults to `False`. ~~bool~~ | -| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_token_attr`](/api/scorer#score_token_attr) for the attributes `"pos"` and `"morph"` and [`Scorer.score_token_attr_per_feat`](/api/scorer#score_token_attr_per_feat) for the attribute `"morph"`. ~~Optional[Callable]~~ | +| Setting | Description | +| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `model` | The model to use. Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | +| `overwrite` 3.2 | Whether the values of existing features are overwritten. Defaults to `True`. ~~bool~~ | +| `extend` 3.2 | Whether existing feature types (whose values may or may not be overwritten depending on `overwrite`) are preserved. Defaults to `False`. ~~bool~~ | +| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_token_attr`](/api/scorer#score_token_attr) for the attributes `"pos"` and `"morph"` and [`Scorer.score_token_attr_per_feat`](/api/scorer#score_token_attr_per_feat) for the attribute `"morph"`. ~~Optional[Callable]~~ | +| `save_activations` 4.0 | Save activations in `Doc` when annotating. Saved activations are `"probabilities"` and `"label_ids"`. ~~Union[bool, list[str]]~~ | ```python %%GITHUB_SPACY/spacy/pipeline/morphologizer.pyx @@ -399,8 +400,8 @@ coarse-grained POS as the feature `POS`. > assert "Mood=Ind|POS=VERB|Tense=Past|VerbForm=Fin" in morphologizer.labels > ``` -| Name | Description | -| ----------- | ------------------------------------------------------ | +| Name | Description | +| ----------- | --------------------------------------------------------- | | **RETURNS** | The labels added to the component. ~~Iterable[str, ...]~~ | ## Morphologizer.label_data {#label_data tag="property" new="3"} diff --git a/website/docs/api/sentencerecognizer.md b/website/docs/api/sentencerecognizer.md index 2f50350ae..03744e1b5 100644 --- a/website/docs/api/sentencerecognizer.md +++ b/website/docs/api/sentencerecognizer.md @@ -39,11 +39,12 @@ architectures and their arguments and hyperparameters. > nlp.add_pipe("senter", config=config) > ``` -| Setting | Description | -| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `model` | The [`Model`](https://thinc.ai/docs/api-model) powering the pipeline component. Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | -| `overwrite` 3.2 | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ | -| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_spans`](/api/scorer#score_spans) for the attribute `"sents"`. ~~Optional[Callable]~~ | +| Setting | Description | +| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `model` | The [`Model`](https://thinc.ai/docs/api-model) powering the pipeline component. Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | +| `overwrite` 3.2 | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ | +| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_spans`](/api/scorer#score_spans) for the attribute `"sents"`. ~~Optional[Callable]~~ | +| `save_activations` 4.0 | Save activations in `Doc` when annotating. Saved activations are `"probabilities"` and `"label_ids"`. ~~Union[bool, list[str]]~~ | ```python %%GITHUB_SPACY/spacy/pipeline/senter.pyx diff --git a/website/docs/api/spancategorizer.md b/website/docs/api/spancategorizer.md index 58a06bcf5..e07ad3577 100644 --- a/website/docs/api/spancategorizer.md +++ b/website/docs/api/spancategorizer.md @@ -52,14 +52,15 @@ architectures and their arguments and hyperparameters. > nlp.add_pipe("spancat", config=config) > ``` -| Setting | Description | -| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `suggester` | A function that [suggests spans](#suggesters). Spans are returned as a ragged array with two integer columns, for the start and end positions. Defaults to [`ngram_suggester`](#ngram_suggester). ~~Callable[[Iterable[Doc], Optional[Ops]], Ragged]~~ | -| `model` | A model instance that is given a a list of documents and `(start, end)` indices representing candidate span offsets. The model predicts a probability for each category for each span. Defaults to [SpanCategorizer](/api/architectures#SpanCategorizer). ~~Model[Tuple[List[Doc], Ragged], Floats2d]~~ | -| `spans_key` | Key of the [`Doc.spans`](/api/doc#spans) dict to save the spans under. During initialization and training, the component will look for spans on the reference document under the same key. Defaults to `"sc"`. ~~str~~ | -| `threshold` | Minimum probability to consider a prediction positive. Spans with a positive prediction will be saved on the Doc. Defaults to `0.5`. ~~float~~ | -| `max_positive` | Maximum number of labels to consider positive per span. Defaults to `None`, indicating no limit. ~~Optional[int]~~ | -| `scorer` | The scoring method. Defaults to [`Scorer.score_spans`](/api/scorer#score_spans) for `Doc.spans[spans_key]` with overlapping spans allowed. ~~Optional[Callable]~~ | +| Setting | Description | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `suggester` | A function that [suggests spans](#suggesters). Spans are returned as a ragged array with two integer columns, for the start and end positions. Defaults to [`ngram_suggester`](#ngram_suggester). ~~Callable[[Iterable[Doc], Optional[Ops]], Ragged]~~ | +| `model` | A model instance that is given a a list of documents and `(start, end)` indices representing candidate span offsets. The model predicts a probability for each category for each span. Defaults to [SpanCategorizer](/api/architectures#SpanCategorizer). ~~Model[Tuple[List[Doc], Ragged], Floats2d]~~ | +| `spans_key` | Key of the [`Doc.spans`](/api/doc#spans) dict to save the spans under. During initialization and training, the component will look for spans on the reference document under the same key. Defaults to `"sc"`. ~~str~~ | +| `threshold` | Minimum probability to consider a prediction positive. Spans with a positive prediction will be saved on the Doc. Defaults to `0.5`. ~~float~~ | +| `max_positive` | Maximum number of labels to consider positive per span. Defaults to `None`, indicating no limit. ~~Optional[int]~~ | +| `scorer` | The scoring method. Defaults to [`Scorer.score_spans`](/api/scorer#score_spans) for `Doc.spans[spans_key]` with overlapping spans allowed. ~~Optional[Callable]~~ | +| `save_activations` 4.0 | Save activations in `Doc` when annotating. Saved activations are `"indices"` and `"scores"`. ~~Union[bool, list[str]]~~ | ```python %%GITHUB_SPACY/spacy/pipeline/spancat.py diff --git a/website/docs/api/tagger.md b/website/docs/api/tagger.md index 90a49b197..0d77d9bf4 100644 --- a/website/docs/api/tagger.md +++ b/website/docs/api/tagger.md @@ -40,12 +40,13 @@ architectures and their arguments and hyperparameters. > nlp.add_pipe("tagger", config=config) > ``` -| Setting | Description | -| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `model` | A model instance that predicts the tag probabilities. The output vectors should match the number of tags in size, and be normalized as probabilities (all scores between 0 and 1, with the rows summing to `1`). Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | -| `overwrite` 3.2 | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ | -| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_token_attr`](/api/scorer#score_token_attr) for the attribute `"tag"`. ~~Optional[Callable]~~ | -| `neg_prefix` 3.2.1 | The prefix used to specify incorrect tags while training. The tagger will learn not to predict exactly this tag. Defaults to `!`. ~~str~~ | +| Setting | Description | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `model` | A model instance that predicts the tag probabilities. The output vectors should match the number of tags in size, and be normalized as probabilities (all scores between 0 and 1, with the rows summing to `1`). Defaults to [Tagger](/api/architectures#Tagger). ~~Model[List[Doc], List[Floats2d]]~~ | +| `overwrite` 3.2 | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ | +| `scorer` 3.2 | The scoring method. Defaults to [`Scorer.score_token_attr`](/api/scorer#score_token_attr) for the attribute `"tag"`. ~~Optional[Callable]~~ | +| `neg_prefix` 3.2.1 | The prefix used to specify incorrect tags while training. The tagger will learn not to predict exactly this tag. Defaults to `!`. ~~str~~ | +| `save_activations` 4.0 | Save activations in `Doc` when annotating. Saved activations are `"probabilities"` and `"label_ids"`. ~~Union[bool, list[str]]~~ | ```python %%GITHUB_SPACY/spacy/pipeline/tagger.pyx diff --git a/website/docs/api/textcategorizer.md b/website/docs/api/textcategorizer.md index 042b4ab76..d8a609693 100644 --- a/website/docs/api/textcategorizer.md +++ b/website/docs/api/textcategorizer.md @@ -117,14 +117,15 @@ Create a new pipeline instance. In your application, you would normally use a shortcut for this and instantiate the component using its string name and [`nlp.add_pipe`](/api/language#create_pipe). -| Name | Description | -| -------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `vocab` | The shared vocabulary. ~~Vocab~~ | -| `model` | The Thinc [`Model`](https://thinc.ai/docs/api-model) powering the pipeline component. ~~Model[List[Doc], List[Floats2d]]~~ | -| `name` | String name of the component instance. Used to add entries to the `losses` during training. ~~str~~ | -| _keyword-only_ | | -| `threshold` | Cutoff to consider a prediction "positive", relevant when printing accuracy results. ~~float~~ | -| `scorer` | The scoring method. Defaults to [`Scorer.score_cats`](/api/scorer#score_cats) for the attribute `"cats"`. ~~Optional[Callable]~~ | +| Name | Description | +| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `vocab` | The shared vocabulary. ~~Vocab~~ | +| `model` | The Thinc [`Model`](https://thinc.ai/docs/api-model) powering the pipeline component. ~~Model[List[Doc], List[Floats2d]]~~ | +| `name` | String name of the component instance. Used to add entries to the `losses` during training. ~~str~~ | +| _keyword-only_ | | +| `threshold` | Cutoff to consider a prediction "positive", relevant when printing accuracy results. ~~float~~ | +| `scorer` | The scoring method. Defaults to [`Scorer.score_cats`](/api/scorer#score_cats) for the attribute `"cats"`. ~~Optional[Callable]~~ | +| `save_activations` 4.0 | Save activations in `Doc` when annotating. The supported activations is `"probabilities"`. ~~Union[bool, list[str]]~~ | ## TextCategorizer.\_\_call\_\_ {#call tag="method"} From 5157e4e8235786438c6c463fa7003de17c43b649 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Thu, 15 Sep 2022 17:06:58 +0200 Subject: [PATCH 016/123] disable mypy run for Python 3.10 (#11508) (#11512) --- .github/azure-steps.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/azure-steps.yml b/.github/azure-steps.yml index 18224ba8c..c7722391f 100644 --- a/.github/azure-steps.yml +++ b/.github/azure-steps.yml @@ -27,6 +27,7 @@ steps: - script: python -m mypy spacy displayName: 'Run mypy' + condition: ne(variables['python_version'], '3.10') - task: DeleteFiles@1 inputs: From d4922f25fc182a51d71375a979f99cf27b08ecd9 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Mon, 3 Oct 2022 14:41:15 +0200 Subject: [PATCH 017/123] fix test for EL activations with refactored KB --- spacy/tests/pipeline/test_entity_linker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spacy/tests/pipeline/test_entity_linker.py b/spacy/tests/pipeline/test_entity_linker.py index c03c7008a..a6baa1ff4 100644 --- a/spacy/tests/pipeline/test_entity_linker.py +++ b/spacy/tests/pipeline/test_entity_linker.py @@ -1214,7 +1214,7 @@ def test_save_activations(): # create artificial KB - assign same prior weight to the two russ cochran's # Q2146908 (Russ Cochran): American golfer # Q7381115 (Russ Cochran): publisher - mykb = KnowledgeBase(vocab, entity_vector_length=vector_length) + mykb = InMemoryLookupKB(vocab, entity_vector_length=vector_length) mykb.add_entity(entity="Q2146908", freq=12, entity_vector=[6, -4, 3]) mykb.add_entity(entity="Q7381115", freq=12, entity_vector=[9, 1, -7]) mykb.add_alias( From 446a3ecf34f3b0c139a326d7471b9b1b5346bcb0 Mon Sep 17 00:00:00 2001 From: Madeesh Kannan Date: Thu, 6 Oct 2022 10:51:06 +0200 Subject: [PATCH 018/123] `StringStore` refactoring (#11344) * `strings`: Remove unused `hash32_utf8` function * `strings`: Make `hash_utf8` and `decode_Utf8Str` private * `strings`: Reorganize private functions * 'strings': Raise error when non-string/-int types are passed to functions that don't accept them * `strings`: Add `items()` method, add type hints, remove unused methods, restrict inputs to specific types, reorganize methods * `Morphology`: Use `StringStore.items()` to enumerate features when pickling * `test_stringstore`: Update pre-Python 3 tests * Update `StringStore` docs * Fix `get_string_id` imports * Replace redundant test with tests for type checking * Rename `_retrieve_interned_str`, remove `.get` default arg * Add `get_string_id` to `strings.pyi` Remove `mypy` ignore directives from imports of the above * `strings.pyi`: Replace functions that consume `Union`-typed params with overloads * `strings.pyi`: Revert some function signatures * Update `SYMBOLS_BY_INT` lookups and error codes post-merge * Revert clobbered change introduced in a previous merge * Remove unnecessary type hint * Invert tuple order in `StringStore.items()` * Add test for `StringStore.items()` * Revert "`Morphology`: Use `StringStore.items()` to enumerate features when pickling" This reverts commit 1af9510ceb6b08cfdcfbf26df6896f26709fac0d. * Rename `keys` and `key_map` * Add `keys()` and `values()` * Add comment about the inverted key-value semantics in the API * Fix type hints * Implement `keys()`, `values()`, `items()` without generators * Fix type hints, remove unnecessary boxing * Update docs * Simplify `keys/values/items()` impl * `mypy` fix * Fix error message, doc fixes --- spacy/errors.py | 4 +- spacy/matcher/matcher.pyx | 2 +- spacy/strings.pxd | 21 +- spacy/strings.pyi | 23 +- spacy/strings.pyx | 426 +++++++++--------- spacy/tests/vocab_vectors/test_stringstore.py | 41 +- spacy/tokens/graph.pyx | 2 +- spacy/tokens/retokenizer.pyx | 2 +- website/docs/api/stringstore.md | 82 +++- 9 files changed, 339 insertions(+), 264 deletions(-) diff --git a/spacy/errors.py b/spacy/errors.py index 5fb59e2c5..856660106 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -252,7 +252,7 @@ class Errors(metaclass=ErrorsWithCodes): E012 = ("Cannot add pattern for zero tokens to matcher.\nKey: {key}") E016 = ("MultitaskObjective target should be function or one of: dep, " "tag, ent, dep_tag_offset, ent_tag.") - E017 = ("Can only add unicode or bytes. Got type: {value_type}") + E017 = ("Can only add 'str' inputs to StringStore. Got type: {value_type}") E018 = ("Can't retrieve string for hash '{hash_value}'. This usually " "refers to an issue with the `Vocab` or `StringStore`.") E019 = ("Can't create transition with unknown action ID: {action}. Action " @@ -955,6 +955,8 @@ class Errors(metaclass=ErrorsWithCodes): # v4 error strings E4000 = ("Expected a Doc as input, but got: '{type}'") + E4001 = ("Expected input to be one of the following types: ({expected_types}), " + "but got '{received_type}'") # Deprecated model shortcuts, only used in errors and warnings diff --git a/spacy/matcher/matcher.pyx b/spacy/matcher/matcher.pyx index 865e7594e..8bd05f25f 100644 --- a/spacy/matcher/matcher.pyx +++ b/spacy/matcher/matcher.pyx @@ -22,7 +22,7 @@ from ..attrs cimport ID, attr_id_t, NULL_ATTR, ORTH, POS, TAG, DEP, LEMMA, MORPH from ..schemas import validate_token_pattern from ..errors import Errors, MatchPatternError, Warnings -from ..strings import get_string_id +from ..strings cimport get_string_id from ..attrs import IDS diff --git a/spacy/strings.pxd b/spacy/strings.pxd index 5f03a9a28..0c1a30fe3 100644 --- a/spacy/strings.pxd +++ b/spacy/strings.pxd @@ -1,4 +1,4 @@ -from libc.stdint cimport int64_t +from libc.stdint cimport int64_t, uint32_t from libcpp.vector cimport vector from libcpp.set cimport set from cymem.cymem cimport Pool @@ -7,13 +7,6 @@ from murmurhash.mrmr cimport hash64 from .typedefs cimport attr_t, hash_t - -cpdef hash_t hash_string(str string) except 0 -cdef hash_t hash_utf8(char* utf8_string, int length) nogil - -cdef str decode_Utf8Str(const Utf8Str* string) - - ctypedef union Utf8Str: unsigned char[8] s unsigned char* p @@ -21,9 +14,13 @@ ctypedef union Utf8Str: cdef class StringStore: cdef Pool mem + cdef vector[hash_t] _keys + cdef PreshMap _map - cdef vector[hash_t] keys - cdef public PreshMap _map + cdef hash_t _intern_str(self, str string) + cdef Utf8Str* _allocate_str_repr(self, const unsigned char* chars, uint32_t length) except * + cdef str _decode_str_repr(self, const Utf8Str* string) - cdef const Utf8Str* intern_unicode(self, str py_string) - cdef const Utf8Str* _intern_utf8(self, char* utf8_string, int length, hash_t* precalculated_hash) + +cpdef hash_t hash_string(object string) except -1 +cpdef hash_t get_string_id(object string_or_hash) except -1 diff --git a/spacy/strings.pyi b/spacy/strings.pyi index b29389b9a..d9509ff57 100644 --- a/spacy/strings.pyi +++ b/spacy/strings.pyi @@ -1,21 +1,20 @@ -from typing import Optional, Iterable, Iterator, Union, Any, overload +from typing import List, Optional, Iterable, Iterator, Union, Any, Tuple, overload from pathlib import Path -def get_string_id(key: Union[str, int]) -> int: ... - class StringStore: - def __init__( - self, strings: Optional[Iterable[str]] = ..., freeze: bool = ... - ) -> None: ... + def __init__(self, strings: Optional[Iterable[str]]) -> None: ... @overload - def __getitem__(self, string_or_id: Union[bytes, str]) -> int: ... + def __getitem__(self, string_or_hash: str) -> int: ... @overload - def __getitem__(self, string_or_id: int) -> str: ... - def as_int(self, key: Union[bytes, str, int]) -> int: ... - def as_string(self, key: Union[bytes, str, int]) -> str: ... + def __getitem__(self, string_or_hash: int) -> str: ... + def as_int(self, string_or_hash: Union[str, int]) -> int: ... + def as_string(self, string_or_hash: Union[str, int]) -> str: ... def add(self, string: str) -> int: ... + def items(self) -> List[Tuple[str, int]]: ... + def keys(self) -> List[str]: ... + def values(self) -> List[int]: ... def __len__(self) -> int: ... - def __contains__(self, string: str) -> bool: ... + def __contains__(self, string_or_hash: Union[str, int]) -> bool: ... def __iter__(self) -> Iterator[str]: ... def __reduce__(self) -> Any: ... def to_disk(self, path: Union[str, Path]) -> None: ... @@ -23,3 +22,5 @@ class StringStore: def to_bytes(self, **kwargs: Any) -> bytes: ... def from_bytes(self, bytes_data: bytes, **kwargs: Any) -> StringStore: ... def _reset_and_load(self, strings: Iterable[str]) -> None: ... + +def get_string_id(string_or_hash: Union[str, int]) -> int: ... diff --git a/spacy/strings.pyx b/spacy/strings.pyx index e86682733..5a037eb9a 100644 --- a/spacy/strings.pyx +++ b/spacy/strings.pyx @@ -1,9 +1,10 @@ # cython: infer_types=True +from typing import Optional, Union, Iterable, Tuple, Callable, Any, List, Iterator cimport cython from libc.string cimport memcpy from libcpp.set cimport set from libc.stdint cimport uint32_t -from murmurhash.mrmr cimport hash64, hash32 +from murmurhash.mrmr cimport hash64 import srsly @@ -14,105 +15,13 @@ from .symbols import NAMES as SYMBOLS_BY_INT from .errors import Errors from . import util -# Not particularly elegant, but this is faster than `isinstance(key, numbers.Integral)` -cdef inline bint _try_coerce_to_hash(object key, hash_t* out_hash): - try: - out_hash[0] = key - return True - except: - return False - -def get_string_id(key): - """Get a string ID, handling the reserved symbols correctly. If the key is - already an ID, return it. - - This function optimises for convenience over performance, so shouldn't be - used in tight loops. - """ - cdef hash_t str_hash - if isinstance(key, str): - if len(key) == 0: - return 0 - - symbol = SYMBOLS_BY_STR.get(key, None) - if symbol is not None: - return symbol - else: - chars = key.encode("utf8") - return hash_utf8(chars, len(chars)) - elif _try_coerce_to_hash(key, &str_hash): - # Coerce the integral key to the expected primitive hash type. - # This ensures that custom/overloaded "primitive" data types - # such as those implemented by numpy are not inadvertently used - # downsteam (as these are internally implemented as custom PyObjects - # whose comparison operators can incur a significant overhead). - return str_hash - else: - # TODO: Raise an error instead - return key - - -cpdef hash_t hash_string(str string) except 0: - chars = string.encode("utf8") - return hash_utf8(chars, len(chars)) - - -cdef hash_t hash_utf8(char* utf8_string, int length) nogil: - return hash64(utf8_string, length, 1) - - -cdef uint32_t hash32_utf8(char* utf8_string, int length) nogil: - return hash32(utf8_string, length, 1) - - -cdef str decode_Utf8Str(const Utf8Str* string): - cdef int i, length - if string.s[0] < sizeof(string.s) and string.s[0] != 0: - return string.s[1:string.s[0]+1].decode("utf8") - elif string.p[0] < 255: - return string.p[1:string.p[0]+1].decode("utf8") - else: - i = 0 - length = 0 - while string.p[i] == 255: - i += 1 - length += 255 - length += string.p[i] - i += 1 - return string.p[i:length + i].decode("utf8") - - -cdef Utf8Str* _allocate(Pool mem, const unsigned char* chars, uint32_t length) except *: - cdef int n_length_bytes - cdef int i - cdef Utf8Str* string = mem.alloc(1, sizeof(Utf8Str)) - cdef uint32_t ulength = length - if length < sizeof(string.s): - string.s[0] = length - memcpy(&string.s[1], chars, length) - return string - elif length < 255: - string.p = mem.alloc(length + 1, sizeof(unsigned char)) - string.p[0] = length - memcpy(&string.p[1], chars, length) - return string - else: - i = 0 - n_length_bytes = (length // 255) + 1 - string.p = mem.alloc(length + n_length_bytes, sizeof(unsigned char)) - for i in range(n_length_bytes-1): - string.p[i] = 255 - string.p[n_length_bytes-1] = length % 255 - memcpy(&string.p[n_length_bytes], chars, length) - return string - cdef class StringStore: - """Look up strings by 64-bit hashes. + """Look up strings by 64-bit hashes. Implicitly handles reserved symbols. DOCS: https://spacy.io/api/stringstore """ - def __init__(self, strings=None, freeze=False): + def __init__(self, strings: Optional[Iterable[str]] = None): """Create the StringStore. strings (iterable): A sequence of unicode strings to add to the store. @@ -123,128 +32,127 @@ cdef class StringStore: for string in strings: self.add(string) - def __getitem__(self, object string_or_id): - """Retrieve a string from a given hash, or vice versa. + def __getitem__(self, string_or_hash: Union[str, int]) -> Union[str, int]: + """Retrieve a string from a given hash. If a string + is passed as the input, add it to the store and return + its hash. - string_or_id (bytes, str or uint64): The value to encode. - Returns (str / uint64): The value to be retrieved. + string_or_hash (int / str): The hash value to lookup or the string to store. + RETURNS (str / int): The stored string or the hash of the newly added string. """ - cdef hash_t str_hash - cdef Utf8Str* utf8str = NULL - - if isinstance(string_or_id, str): - if len(string_or_id) == 0: - return 0 - - # Return early if the string is found in the symbols LUT. - symbol = SYMBOLS_BY_STR.get(string_or_id, None) - if symbol is not None: - return symbol - else: - return hash_string(string_or_id) - elif isinstance(string_or_id, bytes): - return hash_utf8(string_or_id, len(string_or_id)) - elif _try_coerce_to_hash(string_or_id, &str_hash): - if str_hash == 0: - return "" - elif str_hash in SYMBOLS_BY_INT: - return SYMBOLS_BY_INT[str_hash] - else: - utf8str = self._map.get(str_hash) + if isinstance(string_or_hash, str): + return self.add(string_or_hash) else: - # TODO: Raise an error instead - utf8str = self._map.get(string_or_id) + return self._get_interned_str(string_or_hash) - if utf8str is NULL: - raise KeyError(Errors.E018.format(hash_value=string_or_id)) - else: - return decode_Utf8Str(utf8str) + def __contains__(self, string_or_hash: Union[str, int]) -> bool: + """Check whether a string or a hash is in the store. - def as_int(self, key): - """If key is an int, return it; otherwise, get the int value.""" - if not isinstance(key, str): - return key - else: - return self[key] - - def as_string(self, key): - """If key is a string, return it; otherwise, get the string value.""" - if isinstance(key, str): - return key - else: - return self[key] - - def add(self, string): - """Add a string to the StringStore. - - string (str): The string to add. - RETURNS (uint64): The string's hash value. - """ - cdef hash_t str_hash - if isinstance(string, str): - if string in SYMBOLS_BY_STR: - return SYMBOLS_BY_STR[string] - - string = string.encode("utf8") - str_hash = hash_utf8(string, len(string)) - self._intern_utf8(string, len(string), &str_hash) - elif isinstance(string, bytes): - if string in SYMBOLS_BY_STR: - return SYMBOLS_BY_STR[string] - str_hash = hash_utf8(string, len(string)) - self._intern_utf8(string, len(string), &str_hash) - else: - raise TypeError(Errors.E017.format(value_type=type(string))) - return str_hash - - def __len__(self): - """The number of strings in the store. - - RETURNS (int): The number of strings in the store. - """ - return self.keys.size() - - def __contains__(self, string_or_id not None): - """Check whether a string or ID is in the store. - - string_or_id (str or int): The string to check. + string (str / int): The string/hash to check. RETURNS (bool): Whether the store contains the string. """ - cdef hash_t str_hash - if isinstance(string_or_id, str): - if len(string_or_id) == 0: - return True - elif string_or_id in SYMBOLS_BY_STR: - return True - str_hash = hash_string(string_or_id) - elif _try_coerce_to_hash(string_or_id, &str_hash): - pass - else: - # TODO: Raise an error instead - return self._map.get(string_or_id) is not NULL - + cdef hash_t str_hash = get_string_id(string_or_hash) if str_hash in SYMBOLS_BY_INT: return True else: return self._map.get(str_hash) is not NULL - def __iter__(self): - """Iterate over the strings in the store, in order. + def __iter__(self) -> Iterator[str]: + """Iterate over the strings in the store in insertion order. - YIELDS (str): A string in the store. + RETURNS: An iterable collection of strings. """ - cdef int i - cdef hash_t key - for i in range(self.keys.size()): - key = self.keys[i] - utf8str = self._map.get(key) - yield decode_Utf8Str(utf8str) - # TODO: Iterate OOV here? + return iter(self.keys()) def __reduce__(self): strings = list(self) return (StringStore, (strings,), None, None, None) + def __len__(self) -> int: + """The number of strings in the store. + + RETURNS (int): The number of strings in the store. + """ + return self._keys.size() + + def add(self, string: str) -> int: + """Add a string to the StringStore. + + string (str): The string to add. + RETURNS (uint64): The string's hash value. + """ + if not isinstance(string, str): + raise TypeError(Errors.E017.format(value_type=type(string))) + + if string in SYMBOLS_BY_STR: + return SYMBOLS_BY_STR[string] + else: + return self._intern_str(string) + + def as_int(self, string_or_hash: Union[str, int]) -> str: + """If a hash value is passed as the input, return it as-is. If the input + is a string, return its corresponding hash. + + string_or_hash (str / int): The string to hash or a hash value. + RETURNS (int): The hash of the string or the input hash value. + """ + if isinstance(string_or_hash, int): + return string_or_hash + else: + return get_string_id(string_or_hash) + + def as_string(self, string_or_hash: Union[str, int]) -> str: + """If a string is passed as the input, return it as-is. If the input + is a hash value, return its corresponding string. + + string_or_hash (str / int): The hash value to lookup or a string. + RETURNS (str): The stored string or the input string. + """ + if isinstance(string_or_hash, str): + return string_or_hash + else: + return self._get_interned_str(string_or_hash) + + def items(self) -> List[Tuple[str, int]]: + """Iterate over the stored strings and their hashes in insertion order. + + RETURNS: A list of string-hash pairs. + """ + # Even though we internally store the hashes as keys and the strings as + # values, we invert the order in the public API to keep it consistent with + # the implementation of the `__iter__` method (where we wish to iterate over + # the strings in the store). + cdef int i + pairs = [None] * self._keys.size() + for i in range(self._keys.size()): + str_hash = self._keys[i] + utf8str = self._map.get(str_hash) + pairs[i] = (self._decode_str_repr(utf8str), str_hash) + return pairs + + def keys(self) -> List[str]: + """Iterate over the stored strings in insertion order. + + RETURNS: A list of strings. + """ + cdef int i + strings = [None] * self._keys.size() + for i in range(self._keys.size()): + utf8str = self._map.get(self._keys[i]) + strings[i] = self._decode_str_repr(utf8str) + return strings + + def values(self) -> List[int]: + """Iterate over the stored strings hashes in insertion order. + + RETURNS: A list of string hashs. + """ + cdef int i + hashes = [None] * self._keys.size() + for i in range(self._keys.size()): + hashes[i] = self._keys[i] + return hashes + def to_disk(self, path): """Save the current state to a directory. @@ -294,24 +202,122 @@ cdef class StringStore: def _reset_and_load(self, strings): self.mem = Pool() self._map = PreshMap() - self.keys.clear() + self._keys.clear() for string in strings: self.add(string) - cdef const Utf8Str* intern_unicode(self, str py_string): - # 0 means missing, but we don't bother offsetting the index. - cdef bytes byte_string = py_string.encode("utf8") - return self._intern_utf8(byte_string, len(byte_string), NULL) + def _get_interned_str(self, hash_value: int) -> str: + cdef hash_t str_hash + if not _try_coerce_to_hash(hash_value, &str_hash): + raise TypeError(Errors.E4001.format(expected_types="'int'", received_type=type(hash_value))) - @cython.final - cdef const Utf8Str* _intern_utf8(self, char* utf8_string, int length, hash_t* precalculated_hash): + # Handle reserved symbols and empty strings correctly. + if str_hash == 0: + return "" + + symbol = SYMBOLS_BY_INT.get(str_hash) + if symbol is not None: + return symbol + + utf8str = self._map.get(str_hash) + if utf8str is NULL: + raise KeyError(Errors.E018.format(hash_value=str_hash)) + else: + return self._decode_str_repr(utf8str) + + cdef hash_t _intern_str(self, str string): # TODO: This function's API/behaviour is an unholy mess... # 0 means missing, but we don't bother offsetting the index. - cdef hash_t key = precalculated_hash[0] if precalculated_hash is not NULL else hash_utf8(utf8_string, length) + chars = string.encode('utf-8') + cdef hash_t key = hash64(chars, len(chars), 1) cdef Utf8Str* value = self._map.get(key) if value is not NULL: - return value - value = _allocate(self.mem, utf8_string, length) + return key + + value = self._allocate_str_repr(chars, len(chars)) self._map.set(key, value) - self.keys.push_back(key) - return value + self._keys.push_back(key) + return key + + cdef Utf8Str* _allocate_str_repr(self, const unsigned char* chars, uint32_t length) except *: + cdef int n_length_bytes + cdef int i + cdef Utf8Str* string = self.mem.alloc(1, sizeof(Utf8Str)) + cdef uint32_t ulength = length + if length < sizeof(string.s): + string.s[0] = length + memcpy(&string.s[1], chars, length) + return string + elif length < 255: + string.p = self.mem.alloc(length + 1, sizeof(unsigned char)) + string.p[0] = length + memcpy(&string.p[1], chars, length) + return string + else: + i = 0 + n_length_bytes = (length // 255) + 1 + string.p = self.mem.alloc(length + n_length_bytes, sizeof(unsigned char)) + for i in range(n_length_bytes-1): + string.p[i] = 255 + string.p[n_length_bytes-1] = length % 255 + memcpy(&string.p[n_length_bytes], chars, length) + return string + + cdef str _decode_str_repr(self, const Utf8Str* string): + cdef int i, length + if string.s[0] < sizeof(string.s) and string.s[0] != 0: + return string.s[1:string.s[0]+1].decode('utf-8') + elif string.p[0] < 255: + return string.p[1:string.p[0]+1].decode('utf-8') + else: + i = 0 + length = 0 + while string.p[i] == 255: + i += 1 + length += 255 + length += string.p[i] + i += 1 + return string.p[i:length + i].decode('utf-8') + + +cpdef hash_t hash_string(object string) except -1: + if not isinstance(string, str): + raise TypeError(Errors.E4001.format(expected_types="'str'", received_type=type(string))) + + # Handle reserved symbols and empty strings correctly. + if len(string) == 0: + return 0 + + symbol = SYMBOLS_BY_STR.get(string) + if symbol is not None: + return symbol + + chars = string.encode('utf-8') + return hash64(chars, len(chars), 1) + + +cpdef hash_t get_string_id(object string_or_hash) except -1: + cdef hash_t str_hash + + try: + return hash_string(string_or_hash) + except: + if _try_coerce_to_hash(string_or_hash, &str_hash): + # Coerce the integral key to the expected primitive hash type. + # This ensures that custom/overloaded "primitive" data types + # such as those implemented by numpy are not inadvertently used + # downsteam (as these are internally implemented as custom PyObjects + # whose comparison operators can incur a significant overhead). + return str_hash + else: + raise TypeError(Errors.E4001.format(expected_types="'str','int'", received_type=type(string_or_hash))) + + +# Not particularly elegant, but this is faster than `isinstance(key, numbers.Integral)` +cdef inline bint _try_coerce_to_hash(object key, hash_t* out_hash): + try: + out_hash[0] = key + return True + except: + return False + diff --git a/spacy/tests/vocab_vectors/test_stringstore.py b/spacy/tests/vocab_vectors/test_stringstore.py index a0f8016af..f86c0f10d 100644 --- a/spacy/tests/vocab_vectors/test_stringstore.py +++ b/spacy/tests/vocab_vectors/test_stringstore.py @@ -24,6 +24,14 @@ def test_stringstore_from_api_docs(stringstore): stringstore.add("orange") all_strings = [s for s in stringstore] assert all_strings == ["apple", "orange"] + assert all_strings == list(stringstore.keys()) + all_strings_and_hashes = list(stringstore.items()) + assert all_strings_and_hashes == [ + ("apple", 8566208034543834098), + ("orange", 2208928596161743350), + ] + all_hashes = list(stringstore.values()) + assert all_hashes == [8566208034543834098, 2208928596161743350] banana_hash = stringstore.add("banana") assert len(stringstore) == 3 assert banana_hash == 2525716904149915114 @@ -31,12 +39,25 @@ def test_stringstore_from_api_docs(stringstore): assert stringstore["banana"] == banana_hash -@pytest.mark.parametrize("text1,text2,text3", [(b"Hello", b"goodbye", b"hello")]) -def test_stringstore_save_bytes(stringstore, text1, text2, text3): - key = stringstore.add(text1) - assert stringstore[text1] == key - assert stringstore[text2] != key - assert stringstore[text3] != key +@pytest.mark.parametrize( + "val_bytes,val_float,val_list,val_text,val_hash", + [(b"Hello", 1.1, ["abc"], "apple", 8566208034543834098)], +) +def test_stringstore_type_checking( + stringstore, val_bytes, val_float, val_list, val_text, val_hash +): + with pytest.raises(TypeError): + assert stringstore[val_bytes] + + with pytest.raises(TypeError): + stringstore.add(val_float) + + with pytest.raises(TypeError): + assert val_list not in stringstore + + key = stringstore.add(val_text) + assert val_hash == key + assert stringstore[val_hash] == val_text @pytest.mark.parametrize("text1,text2,text3", [("Hello", "goodbye", "hello")]) @@ -47,19 +68,19 @@ def test_stringstore_save_unicode(stringstore, text1, text2, text3): assert stringstore[text3] != key -@pytest.mark.parametrize("text", [b"A"]) +@pytest.mark.parametrize("text", ["A"]) def test_stringstore_retrieve_id(stringstore, text): key = stringstore.add(text) assert len(stringstore) == 1 - assert stringstore[key] == text.decode("utf8") + assert stringstore[key] == text with pytest.raises(KeyError): stringstore[20000] -@pytest.mark.parametrize("text1,text2", [(b"0123456789", b"A")]) +@pytest.mark.parametrize("text1,text2", [("0123456789", "A")]) def test_stringstore_med_string(stringstore, text1, text2): store = stringstore.add(text1) - assert stringstore[store] == text1.decode("utf8") + assert stringstore[store] == text1 stringstore.add(text2) assert stringstore[text1] == store diff --git a/spacy/tokens/graph.pyx b/spacy/tokens/graph.pyx index adc4d23c8..0ae0d94c7 100644 --- a/spacy/tokens/graph.pyx +++ b/spacy/tokens/graph.pyx @@ -12,7 +12,7 @@ from murmurhash.mrmr cimport hash64 from .. import Errors from ..typedefs cimport hash_t -from ..strings import get_string_id +from ..strings cimport get_string_id from ..structs cimport EdgeC, GraphC from .token import Token diff --git a/spacy/tokens/retokenizer.pyx b/spacy/tokens/retokenizer.pyx index 43e6d4aa7..29143bed3 100644 --- a/spacy/tokens/retokenizer.pyx +++ b/spacy/tokens/retokenizer.pyx @@ -18,7 +18,7 @@ from .underscore import is_writable_attr from ..attrs import intify_attrs from ..util import SimpleFrozenDict from ..errors import Errors -from ..strings import get_string_id +from ..strings cimport get_string_id cdef class Retokenizer: diff --git a/website/docs/api/stringstore.md b/website/docs/api/stringstore.md index cd414b1f0..b509659ef 100644 --- a/website/docs/api/stringstore.md +++ b/website/docs/api/stringstore.md @@ -40,7 +40,8 @@ Get the number of strings in the store. ## StringStore.\_\_getitem\_\_ {#getitem tag="method"} -Retrieve a string from a given hash, or vice versa. +Retrieve a string from a given hash. If a string is passed as the input, add it +to the store and return its hash. > #### Example > @@ -51,14 +52,14 @@ Retrieve a string from a given hash, or vice versa. > assert stringstore[apple_hash] == "apple" > ``` -| Name | Description | -| -------------- | ----------------------------------------------- | -| `string_or_id` | The value to encode. ~~Union[bytes, str, int]~~ | -| **RETURNS** | The value to be retrieved. ~~Union[str, int]~~ | +| Name | Description | +| ---------------- | ---------------------------------------------------------------------------- | +| `string_or_hash` | The hash value to lookup or the string to store. ~~Union[str, int]~~ | +| **RETURNS** | The stored string or the hash of the newly added string. ~~Union[str, int]~~ | ## StringStore.\_\_contains\_\_ {#contains tag="method"} -Check whether a string is in the store. +Check whether a string or a hash is in the store. > #### Example > @@ -68,15 +69,14 @@ Check whether a string is in the store. > assert not "cherry" in stringstore > ``` -| Name | Description | -| ----------- | ----------------------------------------------- | -| `string` | The string to check. ~~str~~ | -| **RETURNS** | Whether the store contains the string. ~~bool~~ | +| Name | Description | +| ---------------- | ------------------------------------------------------- | +| `string_or_hash` | The string or hash to check. ~~Union[str, int]~~ | +| **RETURNS** | Whether the store contains the string or hash. ~~bool~~ | ## StringStore.\_\_iter\_\_ {#iter tag="method"} -Iterate over the strings in the store, in order. Note that a newly initialized -store will always include an empty string `""` at position `0`. +Iterate over the stored strings in insertion order. > #### Example > @@ -86,11 +86,59 @@ store will always include an empty string `""` at position `0`. > assert all_strings == ["apple", "orange"] > ``` -| Name | Description | -| ---------- | ------------------------------ | -| **YIELDS** | A string in the store. ~~str~~ | +| Name | Description | +| ----------- | ------------------------------ | +| **RETURNS** | A string in the store. ~~str~~ | -## StringStore.add {#add tag="method" new="2"} +## StringStore.items {#iter tag="method" new="4"} + +Iterate over the stored string-hash pairs in insertion order. + +> #### Example +> +> ```python +> stringstore = StringStore(["apple", "orange"]) +> all_strings_and_hashes = stringstore.items() +> assert all_strings_and_hashes == [("apple", 8566208034543834098), ("orange", 2208928596161743350)] +> ``` + +| Name | Description | +| ----------- | ------------------------------------------------------ | +| **RETURNS** | A list of string-hash pairs. ~~List[Tuple[str, int]]~~ | + +## StringStore.keys {#iter tag="method" new="4"} + +Iterate over the stored strings in insertion order. + +> #### Example +> +> ```python +> stringstore = StringStore(["apple", "orange"]) +> all_strings = stringstore.keys() +> assert all_strings == ["apple", "orange"] +> ``` + +| Name | Description | +| ----------- | -------------------------------- | +| **RETURNS** | A list of strings. ~~List[str]~~ | + +## StringStore.values {#iter tag="method" new="4"} + +Iterate over the stored string hashes in insertion order. + +> #### Example +> +> ```python +> stringstore = StringStore(["apple", "orange"]) +> all_hashes = stringstore.values() +> assert all_hashes == [8566208034543834098, 2208928596161743350] +> ``` + +| Name | Description | +| ----------- | -------------------------------------- | +| **RETURNS** | A list of string hashes. ~~List[int]~~ | + +## StringStore.add {#add tag="method"} Add a string to the `StringStore`. @@ -110,7 +158,7 @@ Add a string to the `StringStore`. | `string` | The string to add. ~~str~~ | | **RETURNS** | The string's hash value. ~~int~~ | -## StringStore.to_disk {#to_disk tag="method" new="2"} +## StringStore.to_disk {#to_disk tag="method"} Save the current state to a directory. From 0e2b7fb28be1eb7a2950ae341b7956c4b0ab7af8 Mon Sep 17 00:00:00 2001 From: Paul O'Leary McCann Date: Fri, 21 Oct 2022 18:01:18 +0900 Subject: [PATCH 019/123] Remove thinc util reimports (#11665) * Remove imports marked as v2 leftovers There are a few functions that were in `spacy.util` in v2, but were moved to Thinc. In v3 these were imported in `spacy.util` so that code could be used unchanged, but the comment over them indicates they should always be imported from Thinc. This commit removes those imports. It doesn't look like any DeprecationWarning was ever thrown for using these, but it is probably fine to remove them anyway with a major version. It is not clear that they were widely used. * Import fix_random_seed correctly This seems to be the only place in spaCy that was using the old import. --- spacy/tests/pipeline/test_spancat.py | 4 ++-- spacy/util.py | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/spacy/tests/pipeline/test_spancat.py b/spacy/tests/pipeline/test_spancat.py index 4fb26c7e7..d7da6eb23 100644 --- a/spacy/tests/pipeline/test_spancat.py +++ b/spacy/tests/pipeline/test_spancat.py @@ -1,7 +1,7 @@ import pytest import numpy from numpy.testing import assert_array_equal, assert_almost_equal -from thinc.api import get_current_ops, Ragged +from thinc.api import get_current_ops, Ragged, fix_random_seed from spacy import util from spacy.lang.en import English @@ -9,7 +9,7 @@ from spacy.language import Language from spacy.tokens import SpanGroup from spacy.tokens.span_groups import SpanGroups from spacy.training import Example -from spacy.util import fix_random_seed, registry, make_tempdir +from spacy.util import registry, make_tempdir OPS = get_current_ops() diff --git a/spacy/util.py b/spacy/util.py index 3034808ba..809bc1814 100644 --- a/spacy/util.py +++ b/spacy/util.py @@ -37,12 +37,6 @@ try: except ImportError: cupy = None -# These are functions that were previously (v2.x) available from spacy.util -# and have since moved to Thinc. We're importing them here so people's code -# doesn't break, but they should always be imported from Thinc from now on, -# not from spacy.util. -from thinc.api import fix_random_seed, compounding, decaying # noqa: F401 - from .symbols import ORTH from .compat import cupy, CudaStream, is_windows, importlib_metadata From cae4589f5a229ab4688338474d93d33512226fd8 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Mon, 24 Oct 2022 09:11:35 +0200 Subject: [PATCH 020/123] Replace EntityRuler with SpanRuler implementation (#11320) * Replace EntityRuler with SpanRuler implementation Remove `EntityRuler` and rename the `SpanRuler`-based `future_entity_ruler` to `entity_ruler`. Main changes: * It is no longer possible to load patterns on init as with `EntityRuler(patterns=)`. * The older serialization formats (`patterns.jsonl`) are no longer supported and the related tests are removed. * The config settings are only stored in the config, not in the serialized component (in particular the `phrase_matcher_attr` and overwrite settings). * Add migration guide to EntityRuler API docs * docs update * Minor edit Co-authored-by: svlandeg --- spacy/errors.py | 8 +- spacy/pipeline/__init__.py | 2 - spacy/pipeline/entity_ruler.py | 525 ------------------ spacy/pipeline/span_ruler.py | 17 +- spacy/tests/matcher/test_phrase_matcher.py | 9 +- spacy/tests/pipeline/test_entity_ruler.py | 255 +++------ .../serialize/test_serialize_pipeline.py | 57 +- website/docs/api/entityruler.md | 313 ++--------- website/docs/api/spanruler.md | 11 + website/docs/usage/101/_architecture.md | 40 +- website/docs/usage/101/_pipelines.md | 6 +- website/docs/usage/processing-pipelines.md | 5 +- website/docs/usage/rule-based-matching.md | 45 +- website/docs/usage/saving-loading.md | 10 +- website/docs/usage/training.md | 2 +- 15 files changed, 233 insertions(+), 1072 deletions(-) delete mode 100644 spacy/pipeline/entity_ruler.py diff --git a/spacy/errors.py b/spacy/errors.py index 856660106..820f7352e 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -460,13 +460,13 @@ class Errors(metaclass=ErrorsWithCodes): "same, but found '{nlp}' and '{vocab}' respectively.") E152 = ("The attribute {attr} is not supported for token patterns. " "Please use the option `validate=True` with the Matcher, PhraseMatcher, " - "EntityRuler or AttributeRuler for more details.") + "SpanRuler or AttributeRuler for more details.") E153 = ("The value type {vtype} is not supported for token patterns. " "Please use the option validate=True with Matcher, PhraseMatcher, " - "EntityRuler or AttributeRuler for more details.") + "SpanRuler or AttributeRuler for more details.") E154 = ("One of the attributes or values is not supported for token " "patterns. Please use the option `validate=True` with the Matcher, " - "PhraseMatcher, or EntityRuler for more details.") + "PhraseMatcher, or SpanRuler for more details.") E155 = ("The pipeline needs to include a {pipe} in order to use " "Matcher or PhraseMatcher with the attribute {attr}. " "Try using `nlp()` instead of `nlp.make_doc()` or `list(nlp.pipe())` " @@ -917,8 +917,6 @@ class Errors(metaclass=ErrorsWithCodes): E1021 = ("`pos` value \"{pp}\" is not a valid Universal Dependencies tag. " "Non-UD tags should use the `tag` property.") E1022 = ("Words must be of type str or int, but input is of type '{wtype}'") - E1023 = ("Couldn't read EntityRuler from the {path}. This file doesn't " - "exist.") E1024 = ("A pattern with {attr_type} '{label}' is not present in " "'{component}' patterns.") E1025 = ("Cannot intify the value '{value}' as an IOB string. The only " diff --git a/spacy/pipeline/__init__.py b/spacy/pipeline/__init__.py index 4744a989b..14dfed949 100644 --- a/spacy/pipeline/__init__.py +++ b/spacy/pipeline/__init__.py @@ -3,7 +3,6 @@ from .dep_parser import DependencyParser from .edit_tree_lemmatizer import EditTreeLemmatizer from .entity_linker import EntityLinker from .ner import EntityRecognizer -from .entity_ruler import EntityRuler from .lemmatizer import Lemmatizer from .morphologizer import Morphologizer from .pipe import Pipe @@ -23,7 +22,6 @@ __all__ = [ "DependencyParser", "EntityLinker", "EntityRecognizer", - "EntityRuler", "Morphologizer", "Lemmatizer", "MultiLabel_TextCategorizer", diff --git a/spacy/pipeline/entity_ruler.py b/spacy/pipeline/entity_ruler.py deleted file mode 100644 index 8154a077d..000000000 --- a/spacy/pipeline/entity_ruler.py +++ /dev/null @@ -1,525 +0,0 @@ -from typing import Optional, Union, List, Dict, Tuple, Iterable, Any, Callable, Sequence -import warnings -from collections import defaultdict -from pathlib import Path -import srsly - -from .pipe import Pipe -from ..training import Example -from ..language import Language -from ..errors import Errors, Warnings -from ..util import ensure_path, to_disk, from_disk, SimpleFrozenList, registry -from ..tokens import Doc, Span -from ..matcher import Matcher, PhraseMatcher -from ..scorer import get_ner_prf - - -DEFAULT_ENT_ID_SEP = "||" -PatternType = Dict[str, Union[str, List[Dict[str, Any]]]] - - -@Language.factory( - "entity_ruler", - assigns=["doc.ents", "token.ent_type", "token.ent_iob"], - default_config={ - "phrase_matcher_attr": None, - "validate": False, - "overwrite_ents": False, - "ent_id_sep": DEFAULT_ENT_ID_SEP, - "scorer": {"@scorers": "spacy.entity_ruler_scorer.v1"}, - }, - default_score_weights={ - "ents_f": 1.0, - "ents_p": 0.0, - "ents_r": 0.0, - "ents_per_type": None, - }, -) -def make_entity_ruler( - nlp: Language, - name: str, - phrase_matcher_attr: Optional[Union[int, str]], - validate: bool, - overwrite_ents: bool, - ent_id_sep: str, - scorer: Optional[Callable], -): - return EntityRuler( - nlp, - name, - phrase_matcher_attr=phrase_matcher_attr, - validate=validate, - overwrite_ents=overwrite_ents, - ent_id_sep=ent_id_sep, - scorer=scorer, - ) - - -def entity_ruler_score(examples, **kwargs): - return get_ner_prf(examples) - - -@registry.scorers("spacy.entity_ruler_scorer.v1") -def make_entity_ruler_scorer(): - return entity_ruler_score - - -class EntityRuler(Pipe): - """The EntityRuler lets you add spans to the `Doc.ents` using token-based - rules or exact phrase matches. It can be combined with the statistical - `EntityRecognizer` to boost accuracy, or used on its own to implement a - purely rule-based entity recognition system. After initialization, the - component is typically added to the pipeline using `nlp.add_pipe`. - - DOCS: https://spacy.io/api/entityruler - USAGE: https://spacy.io/usage/rule-based-matching#entityruler - """ - - def __init__( - self, - nlp: Language, - name: str = "entity_ruler", - *, - phrase_matcher_attr: Optional[Union[int, str]] = None, - validate: bool = False, - overwrite_ents: bool = False, - ent_id_sep: str = DEFAULT_ENT_ID_SEP, - patterns: Optional[List[PatternType]] = None, - scorer: Optional[Callable] = entity_ruler_score, - ) -> None: - """Initialize the entity ruler. If patterns are supplied here, they - need to be a list of dictionaries with a `"label"` and `"pattern"` - key. A pattern can either be a token pattern (list) or a phrase pattern - (string). For example: `{'label': 'ORG', 'pattern': 'Apple'}`. - - nlp (Language): The shared nlp object to pass the vocab to the matchers - and process phrase patterns. - name (str): Instance name of the current pipeline component. Typically - passed in automatically from the factory when the component is - added. Used to disable the current entity ruler while creating - phrase patterns with the nlp object. - phrase_matcher_attr (int / str): Token attribute to match on, passed - to the internal PhraseMatcher as `attr` - validate (bool): Whether patterns should be validated, passed to - Matcher and PhraseMatcher as `validate` - patterns (iterable): Optional patterns to load in. - overwrite_ents (bool): If existing entities are present, e.g. entities - added by the model, overwrite them by matches if necessary. - ent_id_sep (str): Separator used internally for entity IDs. - scorer (Optional[Callable]): The scoring method. Defaults to - spacy.scorer.get_ner_prf. - - DOCS: https://spacy.io/api/entityruler#init - """ - self.nlp = nlp - self.name = name - self.overwrite = overwrite_ents - self.token_patterns = defaultdict(list) # type: ignore - self.phrase_patterns = defaultdict(list) # type: ignore - self._validate = validate - self.matcher = Matcher(nlp.vocab, validate=validate) - self.phrase_matcher_attr = phrase_matcher_attr - self.phrase_matcher = PhraseMatcher( - nlp.vocab, attr=self.phrase_matcher_attr, validate=validate - ) - self.ent_id_sep = ent_id_sep - self._ent_ids = defaultdict(tuple) # type: ignore - if patterns is not None: - self.add_patterns(patterns) - self.scorer = scorer - - def __len__(self) -> int: - """The number of all patterns added to the entity ruler.""" - n_token_patterns = sum(len(p) for p in self.token_patterns.values()) - n_phrase_patterns = sum(len(p) for p in self.phrase_patterns.values()) - return n_token_patterns + n_phrase_patterns - - def __contains__(self, label: str) -> bool: - """Whether a label is present in the patterns.""" - return label in self.token_patterns or label in self.phrase_patterns - - def __call__(self, doc: Doc) -> Doc: - """Find matches in document and add them as entities. - - doc (Doc): The Doc object in the pipeline. - RETURNS (Doc): The Doc with added entities, if available. - - DOCS: https://spacy.io/api/entityruler#call - """ - error_handler = self.get_error_handler() - try: - matches = self.match(doc) - self.set_annotations(doc, matches) - return doc - except Exception as e: - return error_handler(self.name, self, [doc], e) - - def match(self, doc: Doc): - self._require_patterns() - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", message="\\[W036") - matches = list(self.matcher(doc)) + list(self.phrase_matcher(doc)) - - final_matches = set( - [(m_id, start, end) for m_id, start, end in matches if start != end] - ) - get_sort_key = lambda m: (m[2] - m[1], -m[1]) - final_matches = sorted(final_matches, key=get_sort_key, reverse=True) - return final_matches - - def set_annotations(self, doc, matches): - """Modify the document in place""" - entities = list(doc.ents) - new_entities = [] - seen_tokens = set() - for match_id, start, end in matches: - if any(t.ent_type for t in doc[start:end]) and not self.overwrite: - continue - # check for end - 1 here because boundaries are inclusive - if start not in seen_tokens and end - 1 not in seen_tokens: - if match_id in self._ent_ids: - label, ent_id = self._ent_ids[match_id] - span = Span(doc, start, end, label=label, span_id=ent_id) - else: - span = Span(doc, start, end, label=match_id) - new_entities.append(span) - entities = [ - e for e in entities if not (e.start < end and e.end > start) - ] - seen_tokens.update(range(start, end)) - doc.ents = entities + new_entities - - @property - def labels(self) -> Tuple[str, ...]: - """All labels present in the match patterns. - - RETURNS (set): The string labels. - - DOCS: https://spacy.io/api/entityruler#labels - """ - keys = set(self.token_patterns.keys()) - keys.update(self.phrase_patterns.keys()) - all_labels = set() - - for l in keys: - if self.ent_id_sep in l: - label, _ = self._split_label(l) - all_labels.add(label) - else: - all_labels.add(l) - return tuple(sorted(all_labels)) - - def initialize( - self, - get_examples: Callable[[], Iterable[Example]], - *, - nlp: Optional[Language] = None, - patterns: Optional[Sequence[PatternType]] = None, - ): - """Initialize the pipe for training. - - get_examples (Callable[[], Iterable[Example]]): Function that - returns a representative sample of gold-standard Example objects. - nlp (Language): The current nlp object the component is part of. - patterns Optional[Iterable[PatternType]]: The list of patterns. - - DOCS: https://spacy.io/api/entityruler#initialize - """ - self.clear() - if patterns: - self.add_patterns(patterns) # type: ignore[arg-type] - - @property - def ent_ids(self) -> Tuple[Optional[str], ...]: - """All entity ids present in the match patterns `id` properties - - RETURNS (set): The string entity ids. - - DOCS: https://spacy.io/api/entityruler#ent_ids - """ - keys = set(self.token_patterns.keys()) - keys.update(self.phrase_patterns.keys()) - all_ent_ids = set() - - for l in keys: - if self.ent_id_sep in l: - _, ent_id = self._split_label(l) - all_ent_ids.add(ent_id) - return tuple(all_ent_ids) - - @property - def patterns(self) -> List[PatternType]: - """Get all patterns that were added to the entity ruler. - - RETURNS (list): The original patterns, one dictionary per pattern. - - DOCS: https://spacy.io/api/entityruler#patterns - """ - all_patterns = [] - for label, patterns in self.token_patterns.items(): - for pattern in patterns: - ent_label, ent_id = self._split_label(label) - p = {"label": ent_label, "pattern": pattern} - if ent_id: - p["id"] = ent_id - all_patterns.append(p) - for label, patterns in self.phrase_patterns.items(): - for pattern in patterns: - ent_label, ent_id = self._split_label(label) - p = {"label": ent_label, "pattern": pattern.text} - if ent_id: - p["id"] = ent_id - all_patterns.append(p) - return all_patterns - - def add_patterns(self, patterns: List[PatternType]) -> None: - """Add patterns to the entity ruler. A pattern can either be a token - pattern (list of dicts) or a phrase pattern (string). For example: - {'label': 'ORG', 'pattern': 'Apple'} - {'label': 'GPE', 'pattern': [{'lower': 'san'}, {'lower': 'francisco'}]} - - patterns (list): The patterns to add. - - DOCS: https://spacy.io/api/entityruler#add_patterns - """ - - # disable the nlp components after this one in case they hadn't been initialized / deserialised yet - try: - current_index = -1 - for i, (name, pipe) in enumerate(self.nlp.pipeline): - if self == pipe: - current_index = i - break - subsequent_pipes = [pipe for pipe in self.nlp.pipe_names[current_index:]] - except ValueError: - subsequent_pipes = [] - with self.nlp.select_pipes(disable=subsequent_pipes): - token_patterns = [] - phrase_pattern_labels = [] - phrase_pattern_texts = [] - phrase_pattern_ids = [] - for entry in patterns: - if isinstance(entry["pattern"], str): - phrase_pattern_labels.append(entry["label"]) - phrase_pattern_texts.append(entry["pattern"]) - phrase_pattern_ids.append(entry.get("id")) - elif isinstance(entry["pattern"], list): - token_patterns.append(entry) - phrase_patterns = [] - for label, pattern, ent_id in zip( - phrase_pattern_labels, - self.nlp.pipe(phrase_pattern_texts), - phrase_pattern_ids, - ): - phrase_pattern = {"label": label, "pattern": pattern} - if ent_id: - phrase_pattern["id"] = ent_id - phrase_patterns.append(phrase_pattern) - for entry in token_patterns + phrase_patterns: # type: ignore[operator] - label = entry["label"] # type: ignore - if "id" in entry: - ent_label = label - label = self._create_label(label, entry["id"]) - key = self.matcher._normalize_key(label) - self._ent_ids[key] = (ent_label, entry["id"]) - pattern = entry["pattern"] # type: ignore - if isinstance(pattern, Doc): - self.phrase_patterns[label].append(pattern) - self.phrase_matcher.add(label, [pattern]) # type: ignore - elif isinstance(pattern, list): - self.token_patterns[label].append(pattern) - self.matcher.add(label, [pattern]) - else: - raise ValueError(Errors.E097.format(pattern=pattern)) - - def clear(self) -> None: - """Reset all patterns.""" - self.token_patterns = defaultdict(list) - self.phrase_patterns = defaultdict(list) - self._ent_ids = defaultdict(tuple) - self.matcher = Matcher(self.nlp.vocab, validate=self._validate) - self.phrase_matcher = PhraseMatcher( - self.nlp.vocab, attr=self.phrase_matcher_attr, validate=self._validate - ) - - def remove(self, ent_id: str) -> None: - """Remove a pattern by its ent_id if a pattern with this ent_id was added before - - ent_id (str): id of the pattern to be removed - RETURNS: None - DOCS: https://spacy.io/api/entityruler#remove - """ - label_id_pairs = [ - (label, eid) for (label, eid) in self._ent_ids.values() if eid == ent_id - ] - if not label_id_pairs: - raise ValueError( - Errors.E1024.format(attr_type="ID", label=ent_id, component=self.name) - ) - created_labels = [ - self._create_label(label, eid) for (label, eid) in label_id_pairs - ] - # remove the patterns from self.phrase_patterns - self.phrase_patterns = defaultdict( - list, - { - label: val - for (label, val) in self.phrase_patterns.items() - if label not in created_labels - }, - ) - # remove the patterns from self.token_pattern - self.token_patterns = defaultdict( - list, - { - label: val - for (label, val) in self.token_patterns.items() - if label not in created_labels - }, - ) - # remove the patterns from self.token_pattern - for label in created_labels: - if label in self.phrase_matcher: - self.phrase_matcher.remove(label) - else: - self.matcher.remove(label) - - def _require_patterns(self) -> None: - """Raise a warning if this component has no patterns defined.""" - if len(self) == 0: - warnings.warn(Warnings.W036.format(name=self.name)) - - def _split_label(self, label: str) -> Tuple[str, Optional[str]]: - """Split Entity label into ent_label and ent_id if it contains self.ent_id_sep - - label (str): The value of label in a pattern entry - RETURNS (tuple): ent_label, ent_id - """ - if self.ent_id_sep in label: - ent_label, ent_id = label.rsplit(self.ent_id_sep, 1) - else: - ent_label = label - ent_id = None # type: ignore - return ent_label, ent_id - - def _create_label(self, label: Any, ent_id: Any) -> str: - """Join Entity label with ent_id if the pattern has an `id` attribute - If ent_id is not a string, the label is returned as is. - - label (str): The label to set for ent.label_ - ent_id (str): The label - RETURNS (str): The ent_label joined with configured `ent_id_sep` - """ - if isinstance(ent_id, str): - label = f"{label}{self.ent_id_sep}{ent_id}" - return label - - def from_bytes( - self, patterns_bytes: bytes, *, exclude: Iterable[str] = SimpleFrozenList() - ) -> "EntityRuler": - """Load the entity ruler from a bytestring. - - patterns_bytes (bytes): The bytestring to load. - RETURNS (EntityRuler): The loaded entity ruler. - - DOCS: https://spacy.io/api/entityruler#from_bytes - """ - cfg = srsly.msgpack_loads(patterns_bytes) - self.clear() - if isinstance(cfg, dict): - self.add_patterns(cfg.get("patterns", cfg)) - self.overwrite = cfg.get("overwrite", False) - self.phrase_matcher_attr = cfg.get("phrase_matcher_attr", None) - self.phrase_matcher = PhraseMatcher( - self.nlp.vocab, attr=self.phrase_matcher_attr - ) - self.ent_id_sep = cfg.get("ent_id_sep", DEFAULT_ENT_ID_SEP) - else: - self.add_patterns(cfg) - return self - - def to_bytes(self, *, exclude: Iterable[str] = SimpleFrozenList()) -> bytes: - """Serialize the entity ruler patterns to a bytestring. - - RETURNS (bytes): The serialized patterns. - - DOCS: https://spacy.io/api/entityruler#to_bytes - """ - serial = { - "overwrite": self.overwrite, - "ent_id_sep": self.ent_id_sep, - "phrase_matcher_attr": self.phrase_matcher_attr, - "patterns": self.patterns, - } - return srsly.msgpack_dumps(serial) - - def from_disk( - self, path: Union[str, Path], *, exclude: Iterable[str] = SimpleFrozenList() - ) -> "EntityRuler": - """Load the entity ruler from a file. Expects a file containing - newline-delimited JSON (JSONL) with one entry per line. - - path (str / Path): The JSONL file to load. - RETURNS (EntityRuler): The loaded entity ruler. - - DOCS: https://spacy.io/api/entityruler#from_disk - """ - path = ensure_path(path) - self.clear() - depr_patterns_path = path.with_suffix(".jsonl") - if path.suffix == ".jsonl": # user provides a jsonl - if path.is_file: - patterns = srsly.read_jsonl(path) - self.add_patterns(patterns) - else: - raise ValueError(Errors.E1023.format(path=path)) - elif depr_patterns_path.is_file(): - patterns = srsly.read_jsonl(depr_patterns_path) - self.add_patterns(patterns) - elif path.is_dir(): # path is a valid directory - cfg = {} - deserializers_patterns = { - "patterns": lambda p: self.add_patterns( - srsly.read_jsonl(p.with_suffix(".jsonl")) - ) - } - deserializers_cfg = {"cfg": lambda p: cfg.update(srsly.read_json(p))} - from_disk(path, deserializers_cfg, {}) - self.overwrite = cfg.get("overwrite", False) - self.phrase_matcher_attr = cfg.get("phrase_matcher_attr") - self.ent_id_sep = cfg.get("ent_id_sep", DEFAULT_ENT_ID_SEP) - - self.phrase_matcher = PhraseMatcher( - self.nlp.vocab, attr=self.phrase_matcher_attr - ) - from_disk(path, deserializers_patterns, {}) - else: # path is not a valid directory or file - raise ValueError(Errors.E146.format(path=path)) - return self - - def to_disk( - self, path: Union[str, Path], *, exclude: Iterable[str] = SimpleFrozenList() - ) -> None: - """Save the entity ruler patterns to a directory. The patterns will be - saved as newline-delimited JSON (JSONL). - - path (str / Path): The JSONL file to save. - - DOCS: https://spacy.io/api/entityruler#to_disk - """ - path = ensure_path(path) - cfg = { - "overwrite": self.overwrite, - "phrase_matcher_attr": self.phrase_matcher_attr, - "ent_id_sep": self.ent_id_sep, - } - serializers = { - "patterns": lambda p: srsly.write_jsonl( - p.with_suffix(".jsonl"), self.patterns - ), - "cfg": lambda p: srsly.write_json(p, cfg), - } - if path.suffix == ".jsonl": # user wants to save only JSONL - srsly.write_jsonl(path, self.patterns) - else: - to_disk(path, serializers, {}) diff --git a/spacy/pipeline/span_ruler.py b/spacy/pipeline/span_ruler.py index 807a4ffe5..e39b89073 100644 --- a/spacy/pipeline/span_ruler.py +++ b/spacy/pipeline/span_ruler.py @@ -11,7 +11,7 @@ from ..language import Language from ..errors import Errors, Warnings from ..util import ensure_path, SimpleFrozenList, registry from ..tokens import Doc, Span -from ..scorer import Scorer +from ..scorer import Scorer, get_ner_prf from ..matcher import Matcher, PhraseMatcher from .. import util @@ -20,7 +20,7 @@ DEFAULT_SPANS_KEY = "ruler" @Language.factory( - "future_entity_ruler", + "entity_ruler", assigns=["doc.ents"], default_config={ "phrase_matcher_attr": None, @@ -63,6 +63,15 @@ def make_entity_ruler( ) +def entity_ruler_score(examples, **kwargs): + return get_ner_prf(examples) + + +@registry.scorers("spacy.entity_ruler_scorer.v1") +def make_entity_ruler_scorer(): + return entity_ruler_score + + @Language.factory( "span_ruler", assigns=["doc.spans"], @@ -117,7 +126,7 @@ def prioritize_new_ents_filter( ) -> List[Span]: """Merge entities and spans into one list without overlaps by allowing spans to overwrite any entities that they overlap with. Intended to - replicate the overwrite_ents=True behavior from the EntityRuler. + replicate the overwrite_ents=True behavior from the v3 EntityRuler. entities (Iterable[Span]): The entities, already filtered for overlaps. spans (Iterable[Span]): The spans to merge, may contain overlaps. @@ -148,7 +157,7 @@ def prioritize_existing_ents_filter( ) -> List[Span]: """Merge entities and spans into one list without overlaps by prioritizing existing entities. Intended to replicate the overwrite_ents=False behavior - from the EntityRuler. + from the v3 EntityRuler. entities (Iterable[Span]): The entities, already filtered for overlaps. spans (Iterable[Span]): The spans to merge, may contain overlaps. diff --git a/spacy/tests/matcher/test_phrase_matcher.py b/spacy/tests/matcher/test_phrase_matcher.py index b462b1878..20d0febb8 100644 --- a/spacy/tests/matcher/test_phrase_matcher.py +++ b/spacy/tests/matcher/test_phrase_matcher.py @@ -87,14 +87,15 @@ def test_issue4373(): @pytest.mark.issue(4651) def test_issue4651_with_phrase_matcher_attr(): - """Test that the EntityRuler PhraseMatcher is deserialized correctly using - the method from_disk when the EntityRuler argument phrase_matcher_attr is + """Test that the entity_ruler PhraseMatcher is deserialized correctly using + the method from_disk when the entity_ruler argument phrase_matcher_attr is specified. """ text = "Spacy is a python library for nlp" nlp = English() patterns = [{"label": "PYTHON_LIB", "pattern": "spacy", "id": "spaCy"}] - ruler = nlp.add_pipe("entity_ruler", config={"phrase_matcher_attr": "LOWER"}) + config = {"phrase_matcher_attr": "LOWER"} + ruler = nlp.add_pipe("entity_ruler", config=config) ruler.add_patterns(patterns) doc = nlp(text) res = [(ent.text, ent.label_, ent.ent_id_) for ent in doc.ents] @@ -102,7 +103,7 @@ def test_issue4651_with_phrase_matcher_attr(): with make_tempdir() as d: file_path = d / "entityruler" ruler.to_disk(file_path) - nlp_reloaded.add_pipe("entity_ruler").from_disk(file_path) + nlp_reloaded.add_pipe("entity_ruler", config=config).from_disk(file_path) doc_reloaded = nlp_reloaded(text) res_reloaded = [(ent.text, ent.label_, ent.ent_id_) for ent in doc_reloaded.ents] assert res == res_reloaded diff --git a/spacy/tests/pipeline/test_entity_ruler.py b/spacy/tests/pipeline/test_entity_ruler.py index 6851e2a7c..440849e84 100644 --- a/spacy/tests/pipeline/test_entity_ruler.py +++ b/spacy/tests/pipeline/test_entity_ruler.py @@ -4,7 +4,7 @@ from spacy import registry from spacy.tokens import Doc, Span from spacy.language import Language from spacy.lang.en import English -from spacy.pipeline import EntityRuler, EntityRecognizer, merge_entities +from spacy.pipeline import EntityRecognizer, merge_entities from spacy.pipeline import SpanRuler from spacy.pipeline.ner import DEFAULT_NER_MODEL from spacy.errors import MatchPatternError @@ -12,8 +12,6 @@ from spacy.tests.util import make_tempdir from thinc.api import NumpyOps, get_current_ops -ENTITY_RULERS = ["entity_ruler", "future_entity_ruler"] - @pytest.fixture def nlp(): @@ -40,13 +38,12 @@ def add_ent_component(doc): @pytest.mark.issue(3345) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_issue3345(entity_ruler_factory): +def test_issue3345(): """Test case where preset entity crosses sentence boundary.""" nlp = English() doc = Doc(nlp.vocab, words=["I", "live", "in", "New", "York"]) doc[4].is_sent_start = True - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns([{"label": "GPE", "pattern": "New York"}]) cfg = {"model": DEFAULT_NER_MODEL} model = registry.resolve(cfg, validate=True)["model"] @@ -65,15 +62,14 @@ def test_issue3345(entity_ruler_factory): @pytest.mark.issue(4849) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_issue4849(entity_ruler_factory): +def test_issue4849(): nlp = English() patterns = [ {"label": "PERSON", "pattern": "joe biden", "id": "joe-biden"}, {"label": "PERSON", "pattern": "bernie sanders", "id": "bernie-sanders"}, ] ruler = nlp.add_pipe( - entity_ruler_factory, + "entity_ruler", name="entity_ruler", config={"phrase_matcher_attr": "LOWER"}, ) @@ -96,11 +92,10 @@ def test_issue4849(entity_ruler_factory): @pytest.mark.issue(5918) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_issue5918(entity_ruler_factory): +def test_issue5918(): # Test edge case when merging entities. nlp = English() - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "ORG", "pattern": "Digicon Inc"}, {"label": "ORG", "pattern": "Rotan Mosle Inc's"}, @@ -125,10 +120,9 @@ def test_issue5918(entity_ruler_factory): @pytest.mark.issue(8168) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_issue8168(entity_ruler_factory): +def test_issue8168(): nlp = English() - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "ORG", "pattern": "Apple"}, { @@ -148,12 +142,9 @@ def test_issue8168(entity_ruler_factory): @pytest.mark.issue(8216) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_fix8216(nlp, patterns, entity_ruler_factory): +def test_entity_ruler_fix8216(nlp, patterns): """Test that patterns don't get added excessively.""" - ruler = nlp.add_pipe( - entity_ruler_factory, name="entity_ruler", config={"validate": True} - ) + ruler = nlp.add_pipe("entity_ruler", config={"validate": True}) ruler.add_patterns(patterns) pattern_count = sum(len(mm) for mm in ruler.matcher._patterns.values()) assert pattern_count > 0 @@ -162,16 +153,15 @@ def test_entity_ruler_fix8216(nlp, patterns, entity_ruler_factory): assert after_count == pattern_count -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_init(nlp, patterns, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_init(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) assert len(ruler) == len(patterns) assert len(ruler.labels) == 4 assert "HELLO" in ruler assert "BYE" in ruler nlp.remove_pipe("entity_ruler") - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) doc = nlp("hello world bye bye") assert len(doc.ents) == 2 @@ -179,23 +169,21 @@ def test_entity_ruler_init(nlp, patterns, entity_ruler_factory): assert doc.ents[1].label_ == "BYE" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_no_patterns_warns(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_no_patterns_warns(nlp): + ruler = nlp.add_pipe("entity_ruler") assert len(ruler) == 0 assert len(ruler.labels) == 0 nlp.remove_pipe("entity_ruler") - nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + nlp.add_pipe("entity_ruler") assert nlp.pipe_names == ["entity_ruler"] with pytest.warns(UserWarning): doc = nlp("hello world bye bye") assert len(doc.ents) == 0 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_init_patterns(nlp, patterns, entity_ruler_factory): +def test_entity_ruler_init_patterns(nlp, patterns): # initialize with patterns - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") assert len(ruler.labels) == 0 ruler.initialize(lambda: [], patterns=patterns) assert len(ruler.labels) == 4 @@ -207,7 +195,7 @@ def test_entity_ruler_init_patterns(nlp, patterns, entity_ruler_factory): nlp.config["initialize"]["components"]["entity_ruler"] = { "patterns": {"@misc": "entity_ruler_patterns"} } - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") assert len(ruler.labels) == 0 nlp.initialize() assert len(ruler.labels) == 4 @@ -216,20 +204,18 @@ def test_entity_ruler_init_patterns(nlp, patterns, entity_ruler_factory): assert doc.ents[1].label_ == "BYE" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_init_clear(nlp, patterns, entity_ruler_factory): +def test_entity_ruler_init_clear(nlp, patterns): """Test that initialization clears patterns.""" - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) assert len(ruler.labels) == 4 ruler.initialize(lambda: []) assert len(ruler.labels) == 0 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_clear(nlp, patterns, entity_ruler_factory): +def test_entity_ruler_clear(nlp, patterns): """Test that initialization clears patterns.""" - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) assert len(ruler.labels) == 4 doc = nlp("hello world") @@ -241,9 +227,8 @@ def test_entity_ruler_clear(nlp, patterns, entity_ruler_factory): assert len(doc.ents) == 0 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_existing(nlp, patterns, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_existing(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) nlp.add_pipe("add_ent", before="entity_ruler") doc = nlp("OH HELLO WORLD bye bye") @@ -252,11 +237,8 @@ def test_entity_ruler_existing(nlp, patterns, entity_ruler_factory): assert doc.ents[1].label_ == "BYE" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_existing_overwrite(nlp, patterns, entity_ruler_factory): - ruler = nlp.add_pipe( - entity_ruler_factory, name="entity_ruler", config={"overwrite_ents": True} - ) +def test_entity_ruler_existing_overwrite(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler", config={"overwrite_ents": True}) ruler.add_patterns(patterns) nlp.add_pipe("add_ent", before="entity_ruler") doc = nlp("OH HELLO WORLD bye bye") @@ -266,11 +248,8 @@ def test_entity_ruler_existing_overwrite(nlp, patterns, entity_ruler_factory): assert doc.ents[1].label_ == "BYE" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_existing_complex(nlp, patterns, entity_ruler_factory): - ruler = nlp.add_pipe( - entity_ruler_factory, name="entity_ruler", config={"overwrite_ents": True} - ) +def test_entity_ruler_existing_complex(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler", config={"overwrite_ents": True}) ruler.add_patterns(patterns) nlp.add_pipe("add_ent", before="entity_ruler") doc = nlp("foo foo bye bye") @@ -281,11 +260,8 @@ def test_entity_ruler_existing_complex(nlp, patterns, entity_ruler_factory): assert len(doc.ents[1]) == 2 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_entity_id(nlp, patterns, entity_ruler_factory): - ruler = nlp.add_pipe( - entity_ruler_factory, name="entity_ruler", config={"overwrite_ents": True} - ) +def test_entity_ruler_entity_id(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler", config={"overwrite_ents": True}) ruler.add_patterns(patterns) doc = nlp("Apple is a technology company") assert len(doc.ents) == 1 @@ -293,26 +269,23 @@ def test_entity_ruler_entity_id(nlp, patterns, entity_ruler_factory): assert doc.ents[0].ent_id_ == "a1" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_cfg_ent_id_sep(nlp, patterns, entity_ruler_factory): +def test_entity_ruler_cfg_ent_id_sep(nlp, patterns): config = {"overwrite_ents": True, "ent_id_sep": "**"} - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler", config=config) + ruler = nlp.add_pipe("entity_ruler", config=config) ruler.add_patterns(patterns) doc = nlp("Apple is a technology company") - if isinstance(ruler, EntityRuler): - assert "TECH_ORG**a1" in ruler.phrase_patterns assert len(doc.ents) == 1 assert doc.ents[0].label_ == "TECH_ORG" assert doc.ents[0].ent_id_ == "a1" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_serialize_bytes(nlp, patterns, entity_ruler_factory): - ruler = EntityRuler(nlp, patterns=patterns) +def test_entity_ruler_serialize_bytes(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler") + ruler.add_patterns(patterns) assert len(ruler) == len(patterns) assert len(ruler.labels) == 4 ruler_bytes = ruler.to_bytes() - new_ruler = EntityRuler(nlp) + new_ruler = nlp.add_pipe("entity_ruler", name="new_ruler") assert len(new_ruler) == 0 assert len(new_ruler.labels) == 0 new_ruler = new_ruler.from_bytes(ruler_bytes) @@ -324,28 +297,27 @@ def test_entity_ruler_serialize_bytes(nlp, patterns, entity_ruler_factory): assert sorted(new_ruler.labels) == sorted(ruler.labels) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_serialize_phrase_matcher_attr_bytes( - nlp, patterns, entity_ruler_factory -): - ruler = EntityRuler(nlp, phrase_matcher_attr="LOWER", patterns=patterns) +def test_entity_ruler_serialize_phrase_matcher_attr_bytes(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler", config={"phrase_matcher_attr": "LOWER"}) + ruler.add_patterns(patterns) assert len(ruler) == len(patterns) assert len(ruler.labels) == 4 ruler_bytes = ruler.to_bytes() - new_ruler = EntityRuler(nlp) + new_ruler = nlp.add_pipe( + "entity_ruler", name="new_ruler", config={"phrase_matcher_attr": "LOWER"} + ) assert len(new_ruler) == 0 assert len(new_ruler.labels) == 0 - assert new_ruler.phrase_matcher_attr is None new_ruler = new_ruler.from_bytes(ruler_bytes) assert len(new_ruler) == len(patterns) assert len(new_ruler.labels) == 4 - assert new_ruler.phrase_matcher_attr == "LOWER" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_validate(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") - validated_ruler = EntityRuler(nlp, validate=True) +def test_entity_ruler_validate(nlp): + ruler = nlp.add_pipe("entity_ruler") + validated_ruler = nlp.add_pipe( + "entity_ruler", name="validated_ruler", config={"validate": True} + ) valid_pattern = {"label": "HELLO", "pattern": [{"LOWER": "HELLO"}]} invalid_pattern = {"label": "HELLO", "pattern": [{"ASDF": "HELLO"}]} @@ -362,16 +334,15 @@ def test_entity_ruler_validate(nlp, entity_ruler_factory): validated_ruler.add_patterns([invalid_pattern]) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_properties(nlp, patterns, entity_ruler_factory): - ruler = EntityRuler(nlp, patterns=patterns, overwrite_ents=True) +def test_entity_ruler_properties(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler", config={"overwrite_ents": True}) + ruler.add_patterns(patterns) assert sorted(ruler.labels) == sorted(["HELLO", "BYE", "COMPLEX", "TECH_ORG"]) - assert sorted(ruler.ent_ids) == ["a1", "a2"] + assert sorted(ruler.ids) == ["a1", "a2"] -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_overlapping_spans(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_overlapping_spans(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "FOOBAR", "pattern": "foo bar"}, {"label": "BARBAZ", "pattern": "bar baz"}, @@ -383,14 +354,13 @@ def test_entity_ruler_overlapping_spans(nlp, entity_ruler_factory): @pytest.mark.parametrize("n_process", [1, 2]) -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_multiprocessing(nlp, n_process, entity_ruler_factory): +def test_entity_ruler_multiprocessing(nlp, n_process): if isinstance(get_current_ops, NumpyOps) or n_process < 2: texts = ["I enjoy eating Pizza Hut pizza."] patterns = [{"label": "FASTFOOD", "pattern": "Pizza Hut", "id": "1234"}] - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) for doc in nlp.pipe(texts, n_process=2): @@ -398,9 +368,8 @@ def test_entity_ruler_multiprocessing(nlp, n_process, entity_ruler_factory): assert ent.ent_id_ == "1234" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_serialize_jsonl(nlp, patterns, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_serialize_jsonl(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) with make_tempdir() as d: ruler.to_disk(d / "test_ruler.jsonl") @@ -409,9 +378,8 @@ def test_entity_ruler_serialize_jsonl(nlp, patterns, entity_ruler_factory): ruler.from_disk(d / "non_existing.jsonl") # read from a bad jsonl file -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_serialize_dir(nlp, patterns, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_serialize_dir(nlp, patterns): + ruler = nlp.add_pipe("entity_ruler") ruler.add_patterns(patterns) with make_tempdir() as d: ruler.to_disk(d / "test_ruler") @@ -420,9 +388,8 @@ def test_entity_ruler_serialize_dir(nlp, patterns, entity_ruler_factory): ruler.from_disk(d / "non_existing_dir") # read from a bad directory -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_remove_basic(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_remove_basic(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "PERSON", "pattern": "Dina", "id": "dina"}, {"label": "ORG", "pattern": "ACME", "id": "acme"}, @@ -432,24 +399,16 @@ def test_entity_ruler_remove_basic(nlp, entity_ruler_factory): doc = nlp("Dina went to school") assert len(ruler.patterns) == 3 assert len(doc.ents) == 1 - if isinstance(ruler, EntityRuler): - assert "PERSON||dina" in ruler.phrase_matcher assert doc.ents[0].label_ == "PERSON" assert doc.ents[0].text == "Dina" - if isinstance(ruler, EntityRuler): - ruler.remove("dina") - else: - ruler.remove_by_id("dina") + ruler.remove_by_id("dina") doc = nlp("Dina went to school") assert len(doc.ents) == 0 - if isinstance(ruler, EntityRuler): - assert "PERSON||dina" not in ruler.phrase_matcher assert len(ruler.patterns) == 2 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_remove_same_id_multiple_patterns(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_remove_same_id_multiple_patterns(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "PERSON", "pattern": "Dina", "id": "dina"}, {"label": "ORG", "pattern": "DinaCorp", "id": "dina"}, @@ -458,25 +417,15 @@ def test_entity_ruler_remove_same_id_multiple_patterns(nlp, entity_ruler_factory ruler.add_patterns(patterns) doc = nlp("Dina founded DinaCorp and ACME.") assert len(ruler.patterns) == 3 - if isinstance(ruler, EntityRuler): - assert "PERSON||dina" in ruler.phrase_matcher - assert "ORG||dina" in ruler.phrase_matcher assert len(doc.ents) == 3 - if isinstance(ruler, EntityRuler): - ruler.remove("dina") - else: - ruler.remove_by_id("dina") + ruler.remove_by_id("dina") doc = nlp("Dina founded DinaCorp and ACME.") assert len(ruler.patterns) == 1 - if isinstance(ruler, EntityRuler): - assert "PERSON||dina" not in ruler.phrase_matcher - assert "ORG||dina" not in ruler.phrase_matcher assert len(doc.ents) == 1 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_remove_nonexisting_pattern(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_remove_nonexisting_pattern(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "PERSON", "pattern": "Dina", "id": "dina"}, {"label": "ORG", "pattern": "ACME", "id": "acme"}, @@ -491,9 +440,8 @@ def test_entity_ruler_remove_nonexisting_pattern(nlp, entity_ruler_factory): ruler.remove_by_id("nepattern") -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_remove_several_patterns(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_remove_several_patterns(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "PERSON", "pattern": "Dina", "id": "dina"}, {"label": "ORG", "pattern": "ACME", "id": "acme"}, @@ -507,27 +455,20 @@ def test_entity_ruler_remove_several_patterns(nlp, entity_ruler_factory): assert doc.ents[0].text == "Dina" assert doc.ents[1].label_ == "ORG" assert doc.ents[1].text == "ACME" - if isinstance(ruler, EntityRuler): - ruler.remove("dina") - else: - ruler.remove_by_id("dina") + ruler.remove_by_id("dina") doc = nlp("Dina founded her company ACME") assert len(ruler.patterns) == 2 assert len(doc.ents) == 1 assert doc.ents[0].label_ == "ORG" assert doc.ents[0].text == "ACME" - if isinstance(ruler, EntityRuler): - ruler.remove("acme") - else: - ruler.remove_by_id("acme") + ruler.remove_by_id("acme") doc = nlp("Dina founded her company ACME") assert len(ruler.patterns) == 1 assert len(doc.ents) == 0 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_remove_patterns_in_a_row(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_remove_patterns_in_a_row(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "PERSON", "pattern": "Dina", "id": "dina"}, {"label": "ORG", "pattern": "ACME", "id": "acme"}, @@ -543,21 +484,15 @@ def test_entity_ruler_remove_patterns_in_a_row(nlp, entity_ruler_factory): assert doc.ents[1].text == "ACME" assert doc.ents[2].label_ == "DATE" assert doc.ents[2].text == "her birthday" - if isinstance(ruler, EntityRuler): - ruler.remove("dina") - ruler.remove("acme") - ruler.remove("bday") - else: - ruler.remove_by_id("dina") - ruler.remove_by_id("acme") - ruler.remove_by_id("bday") + ruler.remove_by_id("dina") + ruler.remove_by_id("acme") + ruler.remove_by_id("bday") doc = nlp("Dina went to school") assert len(doc.ents) == 0 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_remove_all_patterns(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_remove_all_patterns(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "PERSON", "pattern": "Dina", "id": "dina"}, {"label": "ORG", "pattern": "ACME", "id": "acme"}, @@ -565,29 +500,19 @@ def test_entity_ruler_remove_all_patterns(nlp, entity_ruler_factory): ] ruler.add_patterns(patterns) assert len(ruler.patterns) == 3 - if isinstance(ruler, EntityRuler): - ruler.remove("dina") - else: - ruler.remove_by_id("dina") + ruler.remove_by_id("dina") assert len(ruler.patterns) == 2 - if isinstance(ruler, EntityRuler): - ruler.remove("acme") - else: - ruler.remove_by_id("acme") + ruler.remove_by_id("acme") assert len(ruler.patterns) == 1 - if isinstance(ruler, EntityRuler): - ruler.remove("bday") - else: - ruler.remove_by_id("bday") + ruler.remove_by_id("bday") assert len(ruler.patterns) == 0 with pytest.warns(UserWarning): doc = nlp("Dina founded her company ACME on her birthday") assert len(doc.ents) == 0 -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_remove_and_add(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +def test_entity_ruler_remove_and_add(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [{"label": "DATE", "pattern": "last time"}] ruler.add_patterns(patterns) doc = ruler( @@ -608,10 +533,7 @@ def test_entity_ruler_remove_and_add(nlp, entity_ruler_factory): assert doc.ents[0].text == "last time" assert doc.ents[1].label_ == "DATE" assert doc.ents[1].text == "this time" - if isinstance(ruler, EntityRuler): - ruler.remove("ttime") - else: - ruler.remove_by_id("ttime") + ruler.remove_by_id("ttime") doc = ruler( nlp.make_doc("I saw him last time we met, this time he brought some flowers") ) @@ -634,10 +556,7 @@ def test_entity_ruler_remove_and_add(nlp, entity_ruler_factory): ) assert len(ruler.patterns) == 3 assert len(doc.ents) == 3 - if isinstance(ruler, EntityRuler): - ruler.remove("ttime") - else: - ruler.remove_by_id("ttime") + ruler.remove_by_id("ttime") doc = ruler( nlp.make_doc( "I saw him last time we met, this time he brought some flowers, another time some chocolate." diff --git a/spacy/tests/serialize/test_serialize_pipeline.py b/spacy/tests/serialize/test_serialize_pipeline.py index b948bb76c..e49882441 100644 --- a/spacy/tests/serialize/test_serialize_pipeline.py +++ b/spacy/tests/serialize/test_serialize_pipeline.py @@ -8,7 +8,7 @@ import spacy from spacy import Vocab, load, registry from spacy.lang.en import English from spacy.language import Language -from spacy.pipeline import DependencyParser, EntityRecognizer, EntityRuler +from spacy.pipeline import DependencyParser, EntityRecognizer from spacy.pipeline import SentenceRecognizer, Tagger, TextCategorizer from spacy.pipeline import TrainablePipe from spacy.pipeline.dep_parser import DEFAULT_PARSER_MODEL @@ -85,58 +85,17 @@ def test_issue_3526_1(en_vocab): {"label": "TECH_ORG", "pattern": "Apple", "id": "a1"}, ] nlp = Language(vocab=en_vocab) - ruler = EntityRuler(nlp, patterns=patterns, overwrite_ents=True) + ruler = nlp.add_pipe("entity_ruler", config={"overwrite_ents": True}) + ruler.add_patterns(patterns) ruler_bytes = ruler.to_bytes() assert len(ruler) == len(patterns) assert len(ruler.labels) == 4 - assert ruler.overwrite - new_ruler = EntityRuler(nlp) + new_ruler = nlp.add_pipe( + "entity_ruler", name="new_ruler", config={"overwrite_ents": True} + ) new_ruler = new_ruler.from_bytes(ruler_bytes) assert len(new_ruler) == len(ruler) assert len(new_ruler.labels) == 4 - assert new_ruler.overwrite == ruler.overwrite - assert new_ruler.ent_id_sep == ruler.ent_id_sep - - -@pytest.mark.issue(3526) -def test_issue_3526_2(en_vocab): - patterns = [ - {"label": "HELLO", "pattern": "hello world"}, - {"label": "BYE", "pattern": [{"LOWER": "bye"}, {"LOWER": "bye"}]}, - {"label": "HELLO", "pattern": [{"ORTH": "HELLO"}]}, - {"label": "COMPLEX", "pattern": [{"ORTH": "foo", "OP": "*"}]}, - {"label": "TECH_ORG", "pattern": "Apple", "id": "a1"}, - ] - nlp = Language(vocab=en_vocab) - ruler = EntityRuler(nlp, patterns=patterns, overwrite_ents=True) - bytes_old_style = srsly.msgpack_dumps(ruler.patterns) - new_ruler = EntityRuler(nlp) - new_ruler = new_ruler.from_bytes(bytes_old_style) - assert len(new_ruler) == len(ruler) - for pattern in ruler.patterns: - assert pattern in new_ruler.patterns - assert new_ruler.overwrite is not ruler.overwrite - - -@pytest.mark.issue(3526) -def test_issue_3526_3(en_vocab): - patterns = [ - {"label": "HELLO", "pattern": "hello world"}, - {"label": "BYE", "pattern": [{"LOWER": "bye"}, {"LOWER": "bye"}]}, - {"label": "HELLO", "pattern": [{"ORTH": "HELLO"}]}, - {"label": "COMPLEX", "pattern": [{"ORTH": "foo", "OP": "*"}]}, - {"label": "TECH_ORG", "pattern": "Apple", "id": "a1"}, - ] - nlp = Language(vocab=en_vocab) - ruler = EntityRuler(nlp, patterns=patterns, overwrite_ents=True) - with make_tempdir() as tmpdir: - out_file = tmpdir / "entity_ruler" - srsly.write_jsonl(out_file.with_suffix(".jsonl"), ruler.patterns) - new_ruler = EntityRuler(nlp).from_disk(out_file) - for pattern in ruler.patterns: - assert pattern in new_ruler.patterns - assert len(new_ruler) == len(ruler) - assert new_ruler.overwrite is not ruler.overwrite @pytest.mark.issue(3526) @@ -150,16 +109,14 @@ def test_issue_3526_4(en_vocab): nlp.to_disk(tmpdir) ruler = nlp.get_pipe("entity_ruler") assert ruler.patterns == [{"label": "ORG", "pattern": "Apple"}] - assert ruler.overwrite is True nlp2 = load(tmpdir) new_ruler = nlp2.get_pipe("entity_ruler") assert new_ruler.patterns == [{"label": "ORG", "pattern": "Apple"}] - assert new_ruler.overwrite is True @pytest.mark.issue(4042) def test_issue4042(): - """Test that serialization of an EntityRuler before NER works fine.""" + """Test that serialization of an entity_ruler before NER works fine.""" nlp = English() # add ner pipe ner = nlp.add_pipe("ner") diff --git a/website/docs/api/entityruler.md b/website/docs/api/entityruler.md index ef7acbbf1..651c87585 100644 --- a/website/docs/api/entityruler.md +++ b/website/docs/api/entityruler.md @@ -1,13 +1,24 @@ --- title: EntityRuler -tag: class -source: spacy/pipeline/entity_ruler.py new: 2.1 teaser: 'Pipeline component for rule-based named entity recognition' api_string_name: entity_ruler api_trainable: false --- + + +As of spaCy v4, there is no separate `EntityRuler` class. The entity ruler is +implemented as a special case of the `SpanRuler` component. + +See the [migration guide](#migrating) below for differences between the v3 +`EntityRuler` and v4 `SpanRuler` implementations of the `entity_ruler` +component. + +See the [`SpanRuler`](/api/spanruler) API docs for the full API. + + + The entity ruler lets you add spans to the [`Doc.ents`](/api/doc#ents) using token-based rules or exact phrase matches. It can be combined with the statistical [`EntityRecognizer`](/api/entityrecognizer) to boost accuracy, or @@ -63,271 +74,51 @@ how the component should be configured. You can override its settings via the | `ent_id_sep` | Separator used internally for entity IDs. Defaults to `"\|\|"`. ~~str~~ | | `scorer` | The scoring method. Defaults to [`spacy.scorer.get_ner_prf`](/api/scorer#get_ner_prf). ~~Optional[Callable]~~ | -```python -%%GITHUB_SPACY/spacy/pipeline/entity_ruler.py +## Migrating from v3 {#migrating} + +### Loading patterns + +Unlike the v3 `EntityRuler`, the `SpanRuler` cannot load patterns on +initialization with `SpanRuler(patterns=patterns)` or directly from a JSONL file +path with `SpanRuler.from_disk(jsonl_path)`. Patterns should be loaded from the +JSONL file separately and then added through +[`SpanRuler.initialize`](/api/spanruler#initialize]) or +[`SpanRuler.add_patterns`](/api/spanruler#add_patterns). + +```diff + ruler = nlp.get_pipe("entity_ruler") +- ruler.from_disk("patterns.jsonl") ++ import srsly ++ patterns = srsly.read_jsonl("patterns.jsonl") ++ ruler.add_patterns(patterns) ``` -## EntityRuler.\_\_init\_\_ {#init tag="method"} +### Saving patterns -Initialize the entity ruler. If patterns are supplied here, they need to be a -list of dictionaries with a `"label"` and `"pattern"` key. A pattern can either -be a token pattern (list) or a phrase pattern (string). For example: -`{"label": "ORG", "pattern": "Apple"}`. +`SpanRuler.to_disk` always saves the full component data to a directory and does +not include an option to save the patterns to a single JSONL file. -> #### Example -> -> ```python -> # Construction via add_pipe -> ruler = nlp.add_pipe("entity_ruler") -> -> # Construction from class -> from spacy.pipeline import EntityRuler -> ruler = EntityRuler(nlp, overwrite_ents=True) -> ``` +```diff + ruler = nlp.get_pipe("entity_ruler") +- ruler.to_disk("patterns.jsonl") ++ import srsly ++ srsly.write_jsonl("patterns.jsonl", ruler.patterns) +``` -| Name | Description | -| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `nlp` | The shared nlp object to pass the vocab to the matchers and process phrase patterns. ~~Language~~ | -| `name` 3 | Instance name of the current pipeline component. Typically passed in automatically from the factory when the component is added. Used to disable the current entity ruler while creating phrase patterns with the nlp object. ~~str~~ | -| _keyword-only_ | | -| `phrase_matcher_attr` | Optional attribute name match on for the internal [`PhraseMatcher`](/api/phrasematcher), e.g. `LOWER` to match on the lowercase token text. Defaults to `None`. ~~Optional[Union[int, str]]~~ | -| `validate` | Whether patterns should be validated, passed to Matcher and PhraseMatcher as `validate`. Defaults to `False`. ~~bool~~ | -| `overwrite_ents` | If existing entities are present, e.g. entities added by the model, overwrite them by matches if necessary. Defaults to `False`. ~~bool~~ | -| `ent_id_sep` | Separator used internally for entity IDs. Defaults to `"\|\|"`. ~~str~~ | -| `patterns` | Optional patterns to load in on initialization. ~~Optional[List[Dict[str, Union[str, List[dict]]]]]~~ | +### Accessing token and phrase patterns -## EntityRuler.initialize {#initialize tag="method" new="3"} +The separate token patterns and phrase patterns are no longer accessible under +`ruler.token_patterns` or `ruler.phrase_patterns`. You can access the combined +patterns in their original format using the property +[`SpanRuler.patterns`](/api/spanruler#patterns). -Initialize the component with data and used before training to load in rules -from a [pattern file](/usage/rule-based-matching/#entityruler-files). This method -is typically called by [`Language.initialize`](/api/language#initialize) and -lets you customize arguments it receives via the -[`[initialize.components]`](/api/data-formats#config-initialize) block in the -config. +### Removing patterns by ID -> #### Example -> -> ```python -> entity_ruler = nlp.add_pipe("entity_ruler") -> entity_ruler.initialize(lambda: [], nlp=nlp, patterns=patterns) -> ``` -> -> ```ini -> ### config.cfg -> [initialize.components.entity_ruler] -> -> [initialize.components.entity_ruler.patterns] -> @readers = "srsly.read_jsonl.v1" -> path = "corpus/entity_ruler_patterns.jsonl -> ``` +[`SpanRuler.remove`](/api/spanruler#remove) removes by label rather than ID. To +remove by ID, use [`SpanRuler.remove_by_id`](/api/spanruler#remove_by_id): -| Name | Description | -| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `get_examples` | Function that returns gold-standard annotations in the form of [`Example`](/api/example) objects. Not used by the `EntityRuler`. ~~Callable[[], Iterable[Example]]~~ | -| _keyword-only_ | | -| `nlp` | The current `nlp` object. Defaults to `None`. ~~Optional[Language]~~ | -| `patterns` | The list of patterns. Defaults to `None`. ~~Optional[Sequence[Dict[str, Union[str, List[Dict[str, Any]]]]]]~~ | - -## EntityRuler.\_\len\_\_ {#len tag="method"} - -The number of all patterns added to the entity ruler. - -> #### Example -> -> ```python -> ruler = nlp.add_pipe("entity_ruler") -> assert len(ruler) == 0 -> ruler.add_patterns([{"label": "ORG", "pattern": "Apple"}]) -> assert len(ruler) == 1 -> ``` - -| Name | Description | -| ----------- | ------------------------------- | -| **RETURNS** | The number of patterns. ~~int~~ | - -## EntityRuler.\_\_contains\_\_ {#contains tag="method"} - -Whether a label is present in the patterns. - -> #### Example -> -> ```python -> ruler = nlp.add_pipe("entity_ruler") -> ruler.add_patterns([{"label": "ORG", "pattern": "Apple"}]) -> assert "ORG" in ruler -> assert not "PERSON" in ruler -> ``` - -| Name | Description | -| ----------- | ----------------------------------------------------- | -| `label` | The label to check. ~~str~~ | -| **RETURNS** | Whether the entity ruler contains the label. ~~bool~~ | - -## EntityRuler.\_\_call\_\_ {#call tag="method"} - -Find matches in the `Doc` and add them to the `doc.ents`. Typically, this -happens automatically after the component has been added to the pipeline using -[`nlp.add_pipe`](/api/language#add_pipe). If the entity ruler was initialized -with `overwrite_ents=True`, existing entities will be replaced if they overlap -with the matches. When matches overlap in a Doc, the entity ruler prioritizes -longer patterns over shorter, and if equal the match occuring first in the Doc -is chosen. - -> #### Example -> -> ```python -> ruler = nlp.add_pipe("entity_ruler") -> ruler.add_patterns([{"label": "ORG", "pattern": "Apple"}]) -> -> doc = nlp("A text about Apple.") -> ents = [(ent.text, ent.label_) for ent in doc.ents] -> assert ents == [("Apple", "ORG")] -> ``` - -| Name | Description | -| ----------- | -------------------------------------------------------------------- | -| `doc` | The `Doc` object to process, e.g. the `Doc` in the pipeline. ~~Doc~~ | -| **RETURNS** | The modified `Doc` with added entities, if available. ~~Doc~~ | - -## EntityRuler.add_patterns {#add_patterns tag="method"} - -Add patterns to the entity ruler. A pattern can either be a token pattern (list -of dicts) or a phrase pattern (string). For more details, see the usage guide on -[rule-based matching](/usage/rule-based-matching). - -> #### Example -> -> ```python -> patterns = [ -> {"label": "ORG", "pattern": "Apple"}, -> {"label": "GPE", "pattern": [{"lower": "san"}, {"lower": "francisco"}]} -> ] -> ruler = nlp.add_pipe("entity_ruler") -> ruler.add_patterns(patterns) -> ``` - -| Name | Description | -| ---------- | ---------------------------------------------------------------- | -| `patterns` | The patterns to add. ~~List[Dict[str, Union[str, List[dict]]]]~~ | - - -## EntityRuler.remove {#remove tag="method" new="3.2.1"} - -Remove a pattern by its ID from the entity ruler. A `ValueError` is raised if the ID does not exist. - -> #### Example -> -> ```python -> patterns = [{"label": "ORG", "pattern": "Apple", "id": "apple"}] -> ruler = nlp.add_pipe("entity_ruler") -> ruler.add_patterns(patterns) -> ruler.remove("apple") -> ``` - -| Name | Description | -| ---------- | ---------------------------------------------------------------- | -| `id` | The ID of the pattern rule. ~~str~~ | - -## EntityRuler.to_disk {#to_disk tag="method"} - -Save the entity ruler patterns to a directory. The patterns will be saved as -newline-delimited JSON (JSONL). If a file with the suffix `.jsonl` is provided, -only the patterns are saved as JSONL. If a directory name is provided, a -`patterns.jsonl` and `cfg` file with the component configuration is exported. - -> #### Example -> -> ```python -> ruler = nlp.add_pipe("entity_ruler") -> ruler.to_disk("/path/to/patterns.jsonl") # saves patterns only -> ruler.to_disk("/path/to/entity_ruler") # saves patterns and config -> ``` - -| Name | Description | -| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `path` | A path to a JSONL file or directory, which will be created if it doesn't exist. Paths may be either strings or `Path`-like objects. ~~Union[str, Path]~~ | - -## EntityRuler.from_disk {#from_disk tag="method"} - -Load the entity ruler from a path. Expects either a file containing -newline-delimited JSON (JSONL) with one entry per line, or a directory -containing a `patterns.jsonl` file and a `cfg` file with the component -configuration. - -> #### Example -> -> ```python -> ruler = nlp.add_pipe("entity_ruler") -> ruler.from_disk("/path/to/patterns.jsonl") # loads patterns only -> ruler.from_disk("/path/to/entity_ruler") # loads patterns and config -> ``` - -| Name | Description | -| ----------- | ------------------------------------------------------------------------------------------------------------- | -| `path` | A path to a JSONL file or directory. Paths may be either strings or `Path`-like objects. ~~Union[str, Path]~~ | -| **RETURNS** | The modified `EntityRuler` object. ~~EntityRuler~~ | - -## EntityRuler.to_bytes {#to_bytes tag="method"} - -Serialize the entity ruler patterns to a bytestring. - -> #### Example -> -> ```python -> ruler = nlp.add_pipe("entity_ruler") -> ruler_bytes = ruler.to_bytes() -> ``` - -| Name | Description | -| ----------- | ---------------------------------- | -| **RETURNS** | The serialized patterns. ~~bytes~~ | - -## EntityRuler.from_bytes {#from_bytes tag="method"} - -Load the pipe from a bytestring. Modifies the object in place and returns it. - -> #### Example -> -> ```python -> ruler_bytes = ruler.to_bytes() -> ruler = nlp.add_pipe("entity_ruler") -> ruler.from_bytes(ruler_bytes) -> ``` - -| Name | Description | -| ------------ | -------------------------------------------------- | -| `bytes_data` | The bytestring to load. ~~bytes~~ | -| **RETURNS** | The modified `EntityRuler` object. ~~EntityRuler~~ | - -## EntityRuler.labels {#labels tag="property"} - -All labels present in the match patterns. - -| Name | Description | -| ----------- | -------------------------------------- | -| **RETURNS** | The string labels. ~~Tuple[str, ...]~~ | - -## EntityRuler.ent_ids {#ent_ids tag="property" new="2.2.2"} - -All entity IDs present in the `id` properties of the match patterns. - -| Name | Description | -| ----------- | ----------------------------------- | -| **RETURNS** | The string IDs. ~~Tuple[str, ...]~~ | - -## EntityRuler.patterns {#patterns tag="property"} - -Get all patterns that were added to the entity ruler. - -| Name | Description | -| ----------- | ---------------------------------------------------------------------------------------- | -| **RETURNS** | The original patterns, one dictionary per pattern. ~~List[Dict[str, Union[str, dict]]]~~ | - -## Attributes {#attributes} - -| Name | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------------- | -| `matcher` | The underlying matcher used to process token patterns. ~~Matcher~~ | -| `phrase_matcher` | The underlying phrase matcher used to process phrase patterns. ~~PhraseMatcher~~ | -| `token_patterns` | The token patterns present in the entity ruler, keyed by label. ~~Dict[str, List[Dict[str, Union[str, List[dict]]]]~~ | -| `phrase_patterns` | The phrase patterns present in the entity ruler, keyed by label. ~~Dict[str, List[Doc]]~~ | +```diff + ruler = nlp.get_pipe("entity_ruler") +- ruler.remove("id") ++ ruler.remove_by_id("id") +``` diff --git a/website/docs/api/spanruler.md b/website/docs/api/spanruler.md index b573f7c58..1339d0967 100644 --- a/website/docs/api/spanruler.md +++ b/website/docs/api/spanruler.md @@ -13,6 +13,17 @@ The span ruler lets you add spans to [`Doc.spans`](/api/doc#spans) and/or usage examples, see the docs on [rule-based span matching](/usage/rule-based-matching#spanruler). + + +As of spaCy v4, there is no separate `EntityRuler` class. The entity ruler is +implemented as a special case of the `SpanRuler` component. + +See the [migration guide](/api/entityruler#migrating) for differences between +the v3 `EntityRuler` and v4 `SpanRuler` implementations of the `entity_ruler` +component. + + + ## Assigned Attributes {#assigned-attributes} Matches will be saved to `Doc.spans[spans_key]` as a diff --git a/website/docs/usage/101/_architecture.md b/website/docs/usage/101/_architecture.md index 4ebca2756..ecc7f2fd9 100644 --- a/website/docs/usage/101/_architecture.md +++ b/website/docs/usage/101/_architecture.md @@ -41,25 +41,27 @@ components for different language processing tasks and also allows adding ![The processing pipeline](../../images/pipeline.svg) -| Name | Description | -| ----------------------------------------------- | ------------------------------------------------------------------------------------------- | -| [`AttributeRuler`](/api/attributeruler) | Set token attributes using matcher rules. | -| [`DependencyParser`](/api/dependencyparser) | Predict syntactic dependencies. | -| [`EditTreeLemmatizer`](/api/edittreelemmatizer) | Predict base forms of words. | -| [`EntityLinker`](/api/entitylinker) | Disambiguate named entities to nodes in a knowledge base. | -| [`EntityRecognizer`](/api/entityrecognizer) | Predict named entities, e.g. persons or products. | -| [`EntityRuler`](/api/entityruler) | Add entity spans to the `Doc` using token-based rules or exact phrase matches. | -| [`Lemmatizer`](/api/lemmatizer) | Determine the base forms of words using rules and lookups. | -| [`Morphologizer`](/api/morphologizer) | Predict morphological features and coarse-grained part-of-speech tags. | -| [`SentenceRecognizer`](/api/sentencerecognizer) | Predict sentence boundaries. | -| [`Sentencizer`](/api/sentencizer) | Implement rule-based sentence boundary detection that doesn't require the dependency parse. | -| [`Tagger`](/api/tagger) | Predict part-of-speech tags. | -| [`TextCategorizer`](/api/textcategorizer) | Predict categories or labels over the whole document. | -| [`Tok2Vec`](/api/tok2vec) | Apply a "token-to-vector" model and set its outputs. | -| [`Tokenizer`](/api/tokenizer) | Segment raw text and create `Doc` objects from the words. | -| [`TrainablePipe`](/api/pipe) | Class that all trainable pipeline components inherit from. | -| [`Transformer`](/api/transformer) | Use a transformer model and set its outputs. | -| [Other functions](/api/pipeline-functions) | Automatically apply something to the `Doc`, e.g. to merge spans of tokens. | +| Component name | Component class | Description | +| ---------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------- | +| `attribute_ruler` | [`AttributeRuler`](/api/attributeruler) | Set token attributes using matcher rules. | +| `entity_linker` | [`EntityLinker`](/api/entitylinker) | Disambiguate named entities to nodes in a knowledge base. | +| `entity_ruler` | [`SpanRuler`](/api/spanruler) | Add entity spans to the `Doc` using token-based rules or exact phrase matches. | +| `lemmatizer` | [`Lemmatizer`](/api/lemmatizer) | Determine the base forms of words using rules and lookups. | +| `morphologizer` | [`Morphologizer`](/api/morphologizer) | Predict morphological features and coarse-grained part-of-speech tags. | +| `ner` | [`EntityRecognizer`](/api/entityrecognizer) | Predict named entities, e.g. persons or products. | +| `parser` | [`DependencyParser`](/api/dependencyparser) | Predict syntactic dependencies. | +| `senter` | [`SentenceRecognizer`](/api/sentencerecognizer) | Predict sentence boundaries. | +| `sentencizer` | [`Sentencizer`](/api/sentencizer) | Implement rule-based sentence boundary detection that doesn't require the dependency parse. | +| `span_ruler` | [`SpanRuler`](/api/spanruler) | Add spans to the `Doc` using token-based rules or exact phrase matches. | +| `tagger` | [`Tagger`](/api/tagger) | Predict part-of-speech tags. | +| `textcat` | [`TextCategorizer`](/api/textcategorizer) | Predict exactly one category or label over a whole document. | +| `textcat_multilabel` | [`MultiLabel_TextCategorizer`](/api/textcategorizer) | Predict 0, 1 or more categories or labels over a whole document. | +| `tok2vec` | [`Tok2Vec`](/api/tok2vec) | Apply a "token-to-vector" model and set its outputs. | +| `tokenizer` | [`Tokenizer`](/api/tokenizer) | Segment raw text and create `Doc` objects from the words. | +| `trainable_lemmatizer` | [`EditTreeLemmatizer`](/api/edittreelemmatizer) | Predict base forms of words. | +| `transformer` | [`Transformer`](/api/transformer) | Use a transformer model and set its outputs. | +| - | [`TrainablePipe`](/api/pipe) | Class that all trainable pipeline components inherit from. | +| - | [Other functions](/api/pipeline-functions) | Automatically apply something to the `Doc`, e.g. to merge spans of tokens. | ### Matchers {#architecture-matchers} diff --git a/website/docs/usage/101/_pipelines.md b/website/docs/usage/101/_pipelines.md index f43219f41..3a6d67a37 100644 --- a/website/docs/usage/101/_pipelines.md +++ b/website/docs/usage/101/_pipelines.md @@ -53,9 +53,9 @@ example, a custom lemmatizer may need the part-of-speech tags assigned, so it'll only work if it's added after the tagger. The parser will respect pre-defined sentence boundaries, so if a previous component in the pipeline sets them, its dependency predictions may be different. Similarly, it matters if you add the -[`EntityRuler`](/api/entityruler) before or after the statistical entity -recognizer: if it's added before, the entity recognizer will take the existing -entities into account when making predictions. The +[`SpanRuler`](/api/spanruler) before or after the statistical entity recognizer: +if it's added before and it is writing to `doc.ents`, then the entity recognizer +will take those existing entities into account when making predictions. The [`EntityLinker`](/api/entitylinker), which resolves named entities to knowledge base IDs, should be preceded by a pipeline component that recognizes entities such as the [`EntityRecognizer`](/api/entityrecognizer). diff --git a/website/docs/usage/processing-pipelines.md b/website/docs/usage/processing-pipelines.md index bd28810ae..2463b523f 100644 --- a/website/docs/usage/processing-pipelines.md +++ b/website/docs/usage/processing-pipelines.md @@ -303,13 +303,14 @@ available pipeline components and component functions. > ruler = nlp.add_pipe("entity_ruler") > ``` -| String name | Component | Description | +| Component name | Component class | Description | | ---------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------- | | `tagger` | [`Tagger`](/api/tagger) | Assign part-of-speech-tags. | | `parser` | [`DependencyParser`](/api/dependencyparser) | Assign dependency labels. | | `ner` | [`EntityRecognizer`](/api/entityrecognizer) | Assign named entities. | | `entity_linker` | [`EntityLinker`](/api/entitylinker) | Assign knowledge base IDs to named entities. Should be added after the entity recognizer. | -| `entity_ruler` | [`EntityRuler`](/api/entityruler) | Assign named entities based on pattern rules and dictionaries. | +| `span_ruler` | [`SpanRuler`](/api/spanruler) | Assign spans based on pattern rules and dictionaries. | +| `entity_ruler` | [`SpanRuler`](/api/spanruler) | Assign named entities based on pattern rules and dictionaries. | | `textcat` | [`TextCategorizer`](/api/textcategorizer) | Assign text categories: exactly one category is predicted per document. | | `textcat_multilabel` | [`MultiLabel_TextCategorizer`](/api/textcategorizer) | Assign text categories in a multi-label setting: zero, one or more labels per document. | | `lemmatizer` | [`Lemmatizer`](/api/lemmatizer) | Assign base forms to words using rules and lookups. | diff --git a/website/docs/usage/rule-based-matching.md b/website/docs/usage/rule-based-matching.md index bf1891df1..d9f551820 100644 --- a/website/docs/usage/rule-based-matching.md +++ b/website/docs/usage/rule-based-matching.md @@ -375,7 +375,7 @@ scoped quantifiers – instead, you can build those behaviors with `on_match` callbacks. | OP | Description | -|---------|------------------------------------------------------------------------| +| ------- | ---------------------------------------------------------------------- | | `!` | Negate the pattern, by requiring it to match exactly 0 times. | | `?` | Make the pattern optional, by allowing it to match 0 or 1 times. | | `+` | Require the pattern to match 1 or more times. | @@ -471,7 +471,7 @@ matches = matcher(doc) ``` A very similar logic has been implemented in the built-in -[`EntityRuler`](/api/entityruler) by the way. It also takes care of handling +[`entity_ruler`](/api/entityruler) by the way. It also takes care of handling overlapping matches, which you would otherwise have to take care of yourself. > #### Tip: Visualizing matches @@ -1270,7 +1270,7 @@ of patterns such as `{}` that match any token in the sentence. ## Rule-based entity recognition {#entityruler new="2.1"} -The [`EntityRuler`](/api/entityruler) is a component that lets you add named +The [`entity_ruler`](/api/entityruler) is a component that lets you add named entities based on pattern dictionaries, which makes it easy to combine rule-based and statistical named entity recognition for even more powerful pipelines. @@ -1295,13 +1295,12 @@ pattern. The entity ruler accepts two types of patterns: ### Using the entity ruler {#entityruler-usage} -The [`EntityRuler`](/api/entityruler) is a pipeline component that's typically -added via [`nlp.add_pipe`](/api/language#add_pipe). When the `nlp` object is -called on a text, it will find matches in the `doc` and add them as entities to -the `doc.ents`, using the specified pattern label as the entity label. If any -matches were to overlap, the pattern matching most tokens takes priority. If -they also happen to be equally long, then the match occurring first in the `Doc` -is chosen. +The `entity_ruler` is a pipeline component that's typically added via +[`nlp.add_pipe`](/api/language#add_pipe). When the `nlp` object is called on a +text, it will find matches in the `doc` and add them as entities to `doc.ents`, +using the specified pattern label as the entity label. If any matches were to +overlap, the pattern matching most tokens takes priority. If they also happen to +be equally long, then the match occurring first in the `Doc` is chosen. ```python ### {executable="true"} @@ -1339,7 +1338,7 @@ doc = nlp("MyCorp Inc. is a company in the U.S.") print([(ent.text, ent.label_) for ent in doc.ents]) ``` -#### Validating and debugging EntityRuler patterns {#entityruler-pattern-validation new="2.1.8"} +#### Validating and debugging entity ruler patterns {#entityruler-pattern-validation new="2.1.8"} The entity ruler can validate patterns against a JSON schema with the config setting `"validate"`. See details under @@ -1351,9 +1350,9 @@ ruler = nlp.add_pipe("entity_ruler", config={"validate": True}) ### Adding IDs to patterns {#entityruler-ent-ids new="2.2.2"} -The [`EntityRuler`](/api/entityruler) can also accept an `id` attribute for each -pattern. Using the `id` attribute allows multiple patterns to be associated with -the same entity. +The [`entity_ruler`](/api/entityruler) can also accept an `id` attribute for +each pattern. Using the `id` attribute allows multiple patterns to be associated +with the same entity. ```python ### {executable="true"} @@ -1373,10 +1372,10 @@ doc2 = nlp("Apple is opening its first big office in San Fran.") print([(ent.text, ent.label_, ent.id_) for ent in doc2.ents]) ``` -If the `id` attribute is included in the [`EntityRuler`](/api/entityruler) -patterns, the `id_` property of the matched entity is set to the `id` given -in the patterns. So in the example above it's easy to identify that "San -Francisco" and "San Fran" are both the same entity. +If the `id` attribute is included in the [`entity_ruler`](/api/entityruler) +patterns, the `id_` property of the matched entity is set to the `id` given in +the patterns. So in the example above it's easy to identify that "San Francisco" +and "San Fran" are both the same entity. ### Using pattern files {#entityruler-files} @@ -1400,13 +1399,13 @@ new_ruler = nlp.add_pipe("entity_ruler").from_disk("./patterns.jsonl") If you're using the [Prodigy](https://prodi.gy) annotation tool, you might recognize these pattern files from bootstrapping your named entity and text -classification labelling. The patterns for the `EntityRuler` follow the same +classification labelling. The patterns for the `entity_ruler` follow the same syntax, so you can use your existing Prodigy pattern files in spaCy, and vice versa. -When you save out an `nlp` object that has an `EntityRuler` added to its +When you save out an `nlp` object that has an `entity_ruler` added to its pipeline, its patterns are automatically exported to the pipeline directory: ```python @@ -1429,9 +1428,9 @@ rules included! When using a large amount of **phrase patterns** (roughly > 10000) it's useful to understand how the `add_patterns` function of the entity ruler works. For -each **phrase pattern**, the EntityRuler calls the nlp object to construct a doc -object. This happens in case you try to add the EntityRuler at the end of an -existing pipeline with, for example, a POS tagger and want to extract matches +each **phrase pattern**, the entity ruler calls the nlp object to construct a +doc object. This happens in case you try to add the entity ruler at the end of +an existing pipeline with, for example, a POS tagger and want to extract matches based on the pattern's POS signature. In this case you would pass a config value of `"phrase_matcher_attr": "POS"` for the entity ruler. diff --git a/website/docs/usage/saving-loading.md b/website/docs/usage/saving-loading.md index 9a4b584a3..d2b67b199 100644 --- a/website/docs/usage/saving-loading.md +++ b/website/docs/usage/saving-loading.md @@ -193,13 +193,13 @@ the data to and from a JSON file. > #### Real-world example > -> To see custom serialization methods in action, check out the new -> [`EntityRuler`](/api/entityruler) component and its -> [source](%%GITHUB_SPACY/spacy/pipeline/entity_ruler.py). Patterns added to the +> To see custom serialization methods in action, check out the +> [`SpanRuler`](/api/spanruler) component and its +> [source](%%GITHUB_SPACY/spacy/pipeline/span_ruler.py). Patterns added to the > component will be saved to a `.jsonl` file if the pipeline is serialized to > disk, and to a bytestring if the pipeline is serialized to bytes. This allows -> saving out a pipeline with a rule-based entity recognizer and including all -> rules _with_ the component data. +> saving out a pipeline with rule-based components _with_ all the component +> data. ```python ### {highlight="16-23,25-30"} diff --git a/website/docs/usage/training.md b/website/docs/usage/training.md index 27a8bbca7..5ee148224 100644 --- a/website/docs/usage/training.md +++ b/website/docs/usage/training.md @@ -424,7 +424,7 @@ your components during training, and the most common scenarios are: 2. Update an existing **trained component** with more examples. 3. Include an existing trained component without updating it. 4. Include a non-trainable component, like a rule-based - [`EntityRuler`](/api/entityruler) or [`Sentencizer`](/api/sentencizer), or a + [`SpanRuler`](/api/spanruler) or [`Sentencizer`](/api/sentencizer), or a fully [custom component](/usage/processing-pipelines#custom-components). If a component block defines a `factory`, spaCy will look it up in the From e79910d57ec4f2f5d02e0c8d137a7ae8cd608135 Mon Sep 17 00:00:00 2001 From: Edward <43848523+thomashacker@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:09:32 +0100 Subject: [PATCH 021/123] Remove sentiment extension (#11722) * remove sentiment attribute * remove sentiment from docs * add test for backwards compatibility * replace from_disk with from_bytes * Fix docs and format file * Fix formatting --- spacy/lexeme.pyi | 1 - spacy/lexeme.pyx | 13 ----------- spacy/tests/README.md | 2 +- spacy/tests/doc/test_doc_api.py | 13 ++++++++--- spacy/tests/doc/test_span.py | 25 ---------------------- spacy/tests/matcher/test_matcher_api.py | 3 --- spacy/tokens/doc.pxd | 2 -- spacy/tokens/doc.pyi | 1 - spacy/tokens/doc.pyx | 5 ----- spacy/tokens/span.pyi | 2 -- spacy/tokens/span.pyx | 10 --------- spacy/tokens/token.pyi | 2 -- spacy/tokens/token.pyx | 8 ------- website/docs/api/doc.md | 2 -- website/docs/api/lexeme.md | 1 - website/docs/api/span.md | 1 - website/docs/api/token.md | 1 - website/docs/usage/processing-pipelines.md | 2 +- website/docs/usage/rule-based-matching.md | 14 +++++++----- 19 files changed, 21 insertions(+), 87 deletions(-) diff --git a/spacy/lexeme.pyi b/spacy/lexeme.pyi index 4fcaa82cf..4942b18aa 100644 --- a/spacy/lexeme.pyi +++ b/spacy/lexeme.pyi @@ -20,7 +20,6 @@ class Lexeme: def vector_norm(self) -> float: ... vector: Floats1d rank: int - sentiment: float @property def orth_(self) -> str: ... @property diff --git a/spacy/lexeme.pyx b/spacy/lexeme.pyx index 6c66effde..73bf28dc2 100644 --- a/spacy/lexeme.pyx +++ b/spacy/lexeme.pyx @@ -173,19 +173,6 @@ cdef class Lexeme: def __set__(self, value): self.c.id = value - property sentiment: - """RETURNS (float): A scalar value indicating the positivity or - negativity of the lexeme.""" - def __get__(self): - sentiment_table = self.vocab.lookups.get_table("lexeme_sentiment", {}) - return sentiment_table.get(self.c.orth, 0.0) - - def __set__(self, float x): - if "lexeme_sentiment" not in self.vocab.lookups: - self.vocab.lookups.add_table("lexeme_sentiment") - sentiment_table = self.vocab.lookups.get_table("lexeme_sentiment") - sentiment_table[self.c.orth] = x - @property def orth_(self): """RETURNS (str): The original verbatim text of the lexeme diff --git a/spacy/tests/README.md b/spacy/tests/README.md index 82fabcc77..f3c96a39e 100644 --- a/spacy/tests/README.md +++ b/spacy/tests/README.md @@ -40,7 +40,7 @@ py.test spacy/tests/tokenizer/test_exceptions.py::test_tokenizer_handles_emoji # To keep the behavior of the tests consistent and predictable, we try to follow a few basic conventions: -- **Test names** should follow a pattern of `test_[module]_[tested behaviour]`. For example: `test_tokenizer_keeps_email` or `test_spans_override_sentiment`. +- **Test names** should follow a pattern of `test_[module]_[tested behaviour]`. For example: `test_tokenizer_keeps_email`. - If you're testing for a bug reported in a specific issue, always create a **regression test**. Regression tests should be named `test_issue[ISSUE NUMBER]` and live in the [`regression`](regression) directory. - Only use `@pytest.mark.xfail` for tests that **should pass, but currently fail**. To test for desired negative behavior, use `assert not` in your test. - Very **extensive tests** that take a long time to run should be marked with `@pytest.mark.slow`. If your slow test is testing important behavior, consider adding an additional simpler version. diff --git a/spacy/tests/doc/test_doc_api.py b/spacy/tests/doc/test_doc_api.py index 38003dea9..f77d54493 100644 --- a/spacy/tests/doc/test_doc_api.py +++ b/spacy/tests/doc/test_doc_api.py @@ -380,9 +380,7 @@ def test_doc_api_serialize(en_tokenizer, text): assert [t.text for t in tokens] == [t.text for t in new_tokens] assert [t.orth for t in tokens] == [t.orth for t in new_tokens] - new_tokens = Doc(tokens.vocab).from_bytes( - tokens.to_bytes(exclude=["sentiment"]), exclude=["sentiment"] - ) + new_tokens = Doc(tokens.vocab).from_bytes(tokens.to_bytes()) assert tokens.text == new_tokens.text assert [t.text for t in tokens] == [t.text for t in new_tokens] assert [t.orth for t in tokens] == [t.orth for t in new_tokens] @@ -990,3 +988,12 @@ def test_doc_spans_setdefault(en_tokenizer): assert len(doc.spans["key2"]) == 1 doc.spans.setdefault("key3", default=SpanGroup(doc, spans=[doc[0:1], doc[1:2]])) assert len(doc.spans["key3"]) == 2 + + +def test_doc_sentiment_from_bytes_v3_to_v4(): + """Test if a doc with sentiment attribute created in v3.x works with '.from_bytes' in v4.x without throwing errors. The sentiment attribute was removed in v4""" + doc_bytes = b"\x89\xa4text\xa5happy\xaaarray_head\x9fGQACKOLMN\xcd\x01\xc4\xcd\x01\xc6I\xcd\x01\xc5JP\xaaarray_body\x85\xc4\x02nd\xc3\xc4\x04type\xa3 FloatsXd: ... @property - def sentiment(self) -> float: ... - @property def text(self) -> str: ... @property def text_with_ws(self) -> str: ... diff --git a/spacy/tokens/span.pyx b/spacy/tokens/span.pyx index 89d9727e9..5530dd127 100644 --- a/spacy/tokens/span.pyx +++ b/spacy/tokens/span.pyx @@ -566,16 +566,6 @@ cdef class Span: return None return self.doc.tensor[self.start : self.end] - @property - def sentiment(self): - """RETURNS (float): A scalar value indicating the positivity or - negativity of the span. - """ - if "sentiment" in self.doc.user_span_hooks: - return self.doc.user_span_hooks["sentiment"](self) - else: - return sum([token.sentiment for token in self]) / len(self) - @property def text(self): """RETURNS (str): The original verbatim text of the span.""" diff --git a/spacy/tokens/token.pyi b/spacy/tokens/token.pyi index bd585d034..6de7e984a 100644 --- a/spacy/tokens/token.pyi +++ b/spacy/tokens/token.pyi @@ -79,8 +79,6 @@ class Token: @property def prob(self) -> float: ... @property - def sentiment(self) -> float: ... - @property def lang(self) -> int: ... @property def idx(self) -> int: ... diff --git a/spacy/tokens/token.pyx b/spacy/tokens/token.pyx index cee903f48..64c707acd 100644 --- a/spacy/tokens/token.pyx +++ b/spacy/tokens/token.pyx @@ -283,14 +283,6 @@ cdef class Token: """RETURNS (float): Smoothed log probability estimate of token type.""" return self.vocab[self.c.lex.orth].prob - @property - def sentiment(self): - """RETURNS (float): A scalar value indicating the positivity or - negativity of the token.""" - if "sentiment" in self.doc.user_token_hooks: - return self.doc.user_token_hooks["sentiment"](self) - return self.vocab[self.c.lex.orth].sentiment - @property def lang(self): """RETURNS (uint64): ID of the language of the parent document's diff --git a/website/docs/api/doc.md b/website/docs/api/doc.md index 19eb5052e..433134278 100644 --- a/website/docs/api/doc.md +++ b/website/docs/api/doc.md @@ -761,7 +761,6 @@ The L2 norm of the document's vector representation. | `user_data` | A generic storage area, for user custom data. ~~Dict[str, Any]~~ | | `lang` 2.1 | Language of the document's vocabulary. ~~int~~ | | `lang_` 2.1 | Language of the document's vocabulary. ~~str~~ | -| `sentiment` | The document's positivity/negativity score, if available. ~~float~~ | | `user_hooks` | A dictionary that allows customization of the `Doc`'s properties. ~~Dict[str, Callable]~~ | | `user_token_hooks` | A dictionary that allows customization of properties of `Token` children. ~~Dict[str, Callable]~~ | | `user_span_hooks` | A dictionary that allows customization of properties of `Span` children. ~~Dict[str, Callable]~~ | @@ -785,7 +784,6 @@ serialization by passing in the string names via the `exclude` argument. | Name | Description | | ------------------ | --------------------------------------------- | | `text` | The value of the `Doc.text` attribute. | -| `sentiment` | The value of the `Doc.sentiment` attribute. | | `tensor` | The value of the `Doc.tensor` attribute. | | `user_data` | The value of the `Doc.user_data` dictionary. | | `user_data_keys` | The keys of the `Doc.user_data` dictionary. | diff --git a/website/docs/api/lexeme.md b/website/docs/api/lexeme.md index c5d4b7544..db1aba7aa 100644 --- a/website/docs/api/lexeme.md +++ b/website/docs/api/lexeme.md @@ -161,4 +161,3 @@ The L2 norm of the lexeme's vector representation. | `lang_` | Language of the parent vocabulary. ~~str~~ | | `prob` | Smoothed log probability estimate of the lexeme's word type (context-independent entry in the vocabulary). ~~float~~ | | `cluster` | Brown cluster ID. ~~int~~ | -| `sentiment` | A scalar value indicating the positivity or negativity of the lexeme. ~~float~~ | diff --git a/website/docs/api/span.md b/website/docs/api/span.md index be522c31f..9bca0c410 100644 --- a/website/docs/api/span.md +++ b/website/docs/api/span.md @@ -565,5 +565,4 @@ overlaps with will be returned. | `ent_id_` | Alias for `id_`: the span's ID. ~~str~~ | | `id` | The hash value of the span's ID. ~~int~~ | | `id_` | The span's ID. ~~str~~ | -| `sentiment` | A scalar value indicating the positivity or negativity of the span. ~~float~~ | | `_` | User space for adding custom [attribute extensions](/usage/processing-pipelines#custom-components-attributes). ~~Underscore~~ | diff --git a/website/docs/api/token.md b/website/docs/api/token.md index 73447e4d3..6c35d47b1 100644 --- a/website/docs/api/token.md +++ b/website/docs/api/token.md @@ -470,7 +470,6 @@ The L2 norm of the token's vector representation. | `lang_` | Language of the parent document's vocabulary. ~~str~~ | | `prob` | Smoothed log probability estimate of token's word type (context-independent entry in the vocabulary). ~~float~~ | | `idx` | The character offset of the token within the parent document. ~~int~~ | -| `sentiment` | A scalar value indicating the positivity or negativity of the token. ~~float~~ | | `lex_id` | Sequential ID of the token's lexical type, used to index into tables, e.g. for word vectors. ~~int~~ | | `rank` | Sequential ID of the token's lexical type, used to index into tables, e.g. for word vectors. ~~int~~ | | `cluster` | Brown cluster ID. ~~int~~ | diff --git a/website/docs/usage/processing-pipelines.md b/website/docs/usage/processing-pipelines.md index 2463b523f..67c88700d 100644 --- a/website/docs/usage/processing-pipelines.md +++ b/website/docs/usage/processing-pipelines.md @@ -1400,7 +1400,7 @@ separation and makes it easier to ensure backwards compatibility. For example, if you've implemented your own `.coref` property and spaCy claims it one day, it'll break your code. Similarly, just by looking at the code, you'll immediately know what's built-in and what's custom – for example, -`doc.sentiment` is spaCy, while `doc._.sent_score` isn't. +`doc.lang` is spaCy, while `doc._.language` isn't. diff --git a/website/docs/usage/rule-based-matching.md b/website/docs/usage/rule-based-matching.md index 8e55d54d6..77461c495 100644 --- a/website/docs/usage/rule-based-matching.md +++ b/website/docs/usage/rule-based-matching.md @@ -776,6 +776,9 @@ whitespace, making them easy to match as well. ### {executable="true"} from spacy.lang.en import English from spacy.matcher import Matcher +from spacy.tokens import Doc + +Doc.set_extension("sentiment", default=0.0) nlp = English() # We only want the tokenizer, so no need to load a pipeline matcher = Matcher(nlp.vocab) @@ -791,9 +794,9 @@ neg_patterns = [[{"ORTH": emoji}] for emoji in neg_emoji] def label_sentiment(matcher, doc, i, matches): match_id, start, end = matches[i] if doc.vocab.strings[match_id] == "HAPPY": # Don't forget to get string! - doc.sentiment += 0.1 # Add 0.1 for positive sentiment + doc._.sentiment += 0.1 # Add 0.1 for positive sentiment elif doc.vocab.strings[match_id] == "SAD": - doc.sentiment -= 0.1 # Subtract 0.1 for negative sentiment + doc._.sentiment -= 0.1 # Subtract 0.1 for negative sentiment matcher.add("HAPPY", pos_patterns, on_match=label_sentiment) # Add positive pattern matcher.add("SAD", neg_patterns, on_match=label_sentiment) # Add negative pattern @@ -823,16 +826,17 @@ the emoji span will make it available as `span._.emoji_desc`. ```python from emojipedia import Emojipedia # Installation: pip install emojipedia -from spacy.tokens import Span # Get the global Span object +from spacy.tokens import Doc, Span # Get the global Doc and Span object Span.set_extension("emoji_desc", default=None) # Register the custom attribute +Doc.set_extension("sentiment", default=0.0) def label_sentiment(matcher, doc, i, matches): match_id, start, end = matches[i] if doc.vocab.strings[match_id] == "HAPPY": # Don't forget to get string! - doc.sentiment += 0.1 # Add 0.1 for positive sentiment + doc._.sentiment += 0.1 # Add 0.1 for positive sentiment elif doc.vocab.strings[match_id] == "SAD": - doc.sentiment -= 0.1 # Subtract 0.1 for negative sentiment + doc._.sentiment -= 0.1 # Subtract 0.1 for negative sentiment span = doc[start:end] emoji = Emojipedia.search(span[0].text) # Get data for emoji span._.emoji_desc = emoji.title # Assign emoji description From 799d2266762b443097f8f2125c93148c2156be1b Mon Sep 17 00:00:00 2001 From: svlandeg Date: Mon, 5 Dec 2022 08:57:24 +0100 Subject: [PATCH 022/123] prettier formatting --- website/docs/api/cli.md | 3 +-- website/docs/usage/index.md | 12 ++++++------ website/docs/usage/processing-pipelines.md | 7 ++++--- website/docs/usage/v3-4.md | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/website/docs/api/cli.md b/website/docs/api/cli.md index 8823a3bd8..92a123241 100644 --- a/website/docs/api/cli.md +++ b/website/docs/api/cli.md @@ -474,7 +474,7 @@ report span characteristics such as the average span length and the span (or span boundary) distinctiveness. The distinctiveness measure shows how different the tokens are with respect to the rest of the corpus using the KL-divergence of the token distributions. To learn more, you can check out Papay et al.'s work on -[*Dissecting Span Identification Tasks with Performance Prediction* (EMNLP 2020)](https://aclanthology.org/2020.emnlp-main.396/). +[_Dissecting Span Identification Tasks with Performance Prediction_ (EMNLP 2020)](https://aclanthology.org/2020.emnlp-main.396/). @@ -1187,7 +1187,6 @@ be provided. > $ python -m spacy find-threshold my_nlp data.spacy spancat threshold spans_sc_f > ``` - | Name | Description | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `model` | Pipeline to evaluate. Can be a package or a path to a data directory. ~~str (positional)~~ | diff --git a/website/docs/usage/index.md b/website/docs/usage/index.md index dff5a16ba..d6ad6681c 100644 --- a/website/docs/usage/index.md +++ b/website/docs/usage/index.md @@ -235,10 +235,10 @@ package to see what the oldest recommended versions of `numpy` are. Some additional options may be useful for spaCy developers who are editing the source code and recompiling frequently. -- Install in editable mode. Changes to `.py` files will be reflected as soon - as the files are saved, but edits to Cython files (`.pxd`, `.pyx`) will - require the `pip install` command below to be run again. Before installing in - editable mode, be sure you have removed any previous installs with +- Install in editable mode. Changes to `.py` files will be reflected as soon as + the files are saved, but edits to Cython files (`.pxd`, `.pyx`) will require + the `pip install` command below to be run again. Before installing in editable + mode, be sure you have removed any previous installs with `pip uninstall spacy`, which you may need to run multiple times to remove all traces of earlier installs. @@ -247,8 +247,8 @@ source code and recompiling frequently. $ pip install --no-build-isolation --editable . ``` -- Build in parallel. Starting in v3.4.0, you can specify the number of - build jobs with the environment variable `SPACY_NUM_BUILD_JOBS`: +- Build in parallel. Starting in v3.4.0, you can specify the number of build + jobs with the environment variable `SPACY_NUM_BUILD_JOBS`: ```bash $ pip install -r requirements.txt diff --git a/website/docs/usage/processing-pipelines.md b/website/docs/usage/processing-pipelines.md index 9bf85e54c..b3940458b 100644 --- a/website/docs/usage/processing-pipelines.md +++ b/website/docs/usage/processing-pipelines.md @@ -365,7 +365,8 @@ nlp.enable_pipe("tagger") In addition to `disable`, `spacy.load()` also accepts `enable`. If `enable` is set, all components except for those in `enable` are disabled. If `enable` and -`disable` conflict (i.e. the same component is included in both), an error is raised. +`disable` conflict (i.e. the same component is included in both), an error is +raised. ```python # Load the complete pipeline, but disable all components except for tok2vec and tagger @@ -1400,8 +1401,8 @@ Writing to a `._` attribute instead of to the `Doc` directly keeps a clearer separation and makes it easier to ensure backwards compatibility. For example, if you've implemented your own `.coref` property and spaCy claims it one day, it'll break your code. Similarly, just by looking at the code, you'll -immediately know what's built-in and what's custom – for example, -`doc.lang` is spaCy, while `doc._.language` isn't. +immediately know what's built-in and what's custom – for example, `doc.lang` is +spaCy, while `doc._.language` isn't. diff --git a/website/docs/usage/v3-4.md b/website/docs/usage/v3-4.md index e10110b71..e6987e7a2 100644 --- a/website/docs/usage/v3-4.md +++ b/website/docs/usage/v3-4.md @@ -63,8 +63,8 @@ All CNN pipelines have been extended with whitespace augmentation. The English CNN pipelines have new word vectors: -| Package | Model Version | TAG | Parser LAS | NER F | -| ----------------------------------------------- | ------------- | ---: | ---------: | ----: | +| Package | Model Version | TAG | Parser LAS | NER F | +| --------------------------------------------- | ------------- | ---: | ---------: | ----: | | [`en_core_web_md`](/models/en#en_core_web_md) | v3.3.0 | 97.3 | 90.1 | 84.6 | | [`en_core_web_md`](/models/en#en_core_web_md) | v3.4.0 | 97.2 | 90.3 | 85.5 | | [`en_core_web_lg`](/models/en#en_core_web_lg) | v3.3.0 | 97.4 | 90.1 | 85.3 | From 8267aa1b65783ea29e42f470eaf7553ff7508206 Mon Sep 17 00:00:00 2001 From: Paul O'Leary McCann Date: Mon, 5 Dec 2022 17:43:23 +0900 Subject: [PATCH 023/123] Switch ubuntu-latest to ubuntu-20.04 in main tests (#11928) * Switch ubuntu-latest to ubuntu-20.04 in main tests * Only use 20.04 for 3.6 --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9c3b92f06..0f7ea91f9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -41,7 +41,7 @@ jobs: matrix: # We're only running one platform per Python version to speed up builds Python36Linux: - imageName: "ubuntu-latest" + imageName: "ubuntu-20.04" python.version: "3.6" # Python36Windows: # imageName: "windows-latest" @@ -50,7 +50,7 @@ jobs: # imageName: "macos-latest" # python.version: "3.6" # Python37Linux: - # imageName: "ubuntu-latest" + # imageName: "ubuntu-20.04" # python.version: "3.7" Python37Windows: imageName: "windows-latest" From 6b9af38eeb1fdcb50e50f5bb0093472f7e22f6ff Mon Sep 17 00:00:00 2001 From: Paul O'Leary McCann Date: Thu, 8 Dec 2022 19:43:52 +0900 Subject: [PATCH 024/123] Remove all references to "begin_training" (#11943) When v3 was released, `begin_training` was renamed to `initialize`. There were warnings in the code and docs about that. This PR removes them. --- spacy/errors.py | 7 ------- spacy/language.py | 9 --------- spacy/pipeline/pipe.pyx | 7 ------- spacy/tests/pipeline/test_pipe_methods.py | 11 ----------- website/docs/api/dependencyparser.md | 6 ------ website/docs/api/entitylinker.md | 6 ------ website/docs/api/entityrecognizer.md | 6 ------ website/docs/api/language.md | 9 --------- website/docs/api/pipe.md | 6 ------ website/docs/api/tagger.md | 6 ------ website/docs/api/textcategorizer.md | 6 ------ 11 files changed, 79 deletions(-) diff --git a/spacy/errors.py b/spacy/errors.py index 82e7c52bc..31230d7a4 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -131,13 +131,6 @@ class Warnings(metaclass=ErrorsWithCodes): "and make it independent. For example, `replace_listeners = " "[\"model.tok2vec\"]` See the documentation for details: " "https://spacy.io/usage/training#config-components-listeners") - W088 = ("The pipeline component {name} implements a `begin_training` " - "method, which won't be called by spaCy. As of v3.0, `begin_training` " - "has been renamed to `initialize`, so you likely want to rename the " - "component method. See the documentation for details: " - "https://spacy.io/api/language#initialize") - W089 = ("As of spaCy v3.0, the `nlp.begin_training` method has been renamed " - "to `nlp.initialize`.") W090 = ("Could not locate any {format} files in path '{path}'.") W091 = ("Could not clean/remove the temp directory at {dir}: {msg}.") W092 = ("Ignoring annotations for sentence starts, as dependency heads are set.") diff --git a/spacy/language.py b/spacy/language.py index e0abfd5e7..dcb62aef0 100644 --- a/spacy/language.py +++ b/spacy/language.py @@ -1239,15 +1239,6 @@ class Language: sgd(key, W, dW) # type: ignore[call-arg, misc] return losses - def begin_training( - self, - get_examples: Optional[Callable[[], Iterable[Example]]] = None, - *, - sgd: Optional[Optimizer] = None, - ) -> Optimizer: - warnings.warn(Warnings.W089, DeprecationWarning) - return self.initialize(get_examples, sgd=sgd) - def initialize( self, get_examples: Optional[Callable[[], Iterable[Example]]] = None, diff --git a/spacy/pipeline/pipe.pyx b/spacy/pipeline/pipe.pyx index 8407acc45..c5650382b 100644 --- a/spacy/pipeline/pipe.pyx +++ b/spacy/pipeline/pipe.pyx @@ -19,13 +19,6 @@ cdef class Pipe: DOCS: https://spacy.io/api/pipe """ - @classmethod - def __init_subclass__(cls, **kwargs): - """Raise a warning if an inheriting class implements 'begin_training' - (from v2) instead of the new 'initialize' method (from v3)""" - if hasattr(cls, "begin_training"): - warnings.warn(Warnings.W088.format(name=cls.__name__)) - def __call__(self, Doc doc) -> Doc: """Apply the pipe to one document. The document is modified in place, and returned. This usually happens under the hood when the nlp object diff --git a/spacy/tests/pipeline/test_pipe_methods.py b/spacy/tests/pipeline/test_pipe_methods.py index 4dd7bae16..9b9786f04 100644 --- a/spacy/tests/pipeline/test_pipe_methods.py +++ b/spacy/tests/pipeline/test_pipe_methods.py @@ -529,17 +529,6 @@ def test_pipe_label_data_no_labels(pipe): assert "labels" not in get_arg_names(initialize) -def test_warning_pipe_begin_training(): - with pytest.warns(UserWarning, match="begin_training"): - - class IncompatPipe(TrainablePipe): - def __init__(self): - ... - - def begin_training(*args, **kwargs): - ... - - def test_pipe_methods_initialize(): """Test that the [initialize] config reflects the components correctly.""" nlp = Language() diff --git a/website/docs/api/dependencyparser.md b/website/docs/api/dependencyparser.md index 27e315592..c30d39b57 100644 --- a/website/docs/api/dependencyparser.md +++ b/website/docs/api/dependencyparser.md @@ -169,12 +169,6 @@ arguments it receives via the [`[initialize.components]`](/api/data-formats#config-initialize) block in the config. - - -This method was previously called `begin_training`. - - - > #### Example > > ```python diff --git a/website/docs/api/entitylinker.md b/website/docs/api/entitylinker.md index 10132acd9..b116c4be4 100644 --- a/website/docs/api/entitylinker.md +++ b/website/docs/api/entitylinker.md @@ -200,12 +200,6 @@ knowledge base. This argument should be a function that takes a `Vocab` instance and creates the `KnowledgeBase`, ensuring that the strings of the knowledge base are synced with the current vocab. - - -This method was previously called `begin_training`. - - - > #### Example > > ```python diff --git a/website/docs/api/entityrecognizer.md b/website/docs/api/entityrecognizer.md index a535e8316..06828eb04 100644 --- a/website/docs/api/entityrecognizer.md +++ b/website/docs/api/entityrecognizer.md @@ -165,12 +165,6 @@ arguments it receives via the [`[initialize.components]`](/api/data-formats#config-initialize) block in the config. - - -This method was previously called `begin_training`. - - - > #### Example > > ```python diff --git a/website/docs/api/language.md b/website/docs/api/language.md index ad0ac2a46..4d568df62 100644 --- a/website/docs/api/language.md +++ b/website/docs/api/language.md @@ -259,15 +259,6 @@ either in the [config](/usage/training#config), or by calling [`pipe.add_label`](/api/pipe#add_label) for each possible output label (e.g. for the tagger or textcat). - - -This method was previously called `begin_training`. It now also takes a -**function** that is called with no arguments and returns a sequence of -[`Example`](/api/example) objects instead of tuples of `Doc` and `GoldParse` -objects. - - - > #### Example > > ```python diff --git a/website/docs/api/pipe.md b/website/docs/api/pipe.md index 263942e3e..70a4648b6 100644 --- a/website/docs/api/pipe.md +++ b/website/docs/api/pipe.md @@ -152,12 +152,6 @@ network, setting up the label scheme based on the data. This method is typically called by [`Language.initialize`](/api/language#initialize). - - -This method was previously called `begin_training`. - - - > #### Example > > ```python diff --git a/website/docs/api/tagger.md b/website/docs/api/tagger.md index 0d77d9bf4..102793377 100644 --- a/website/docs/api/tagger.md +++ b/website/docs/api/tagger.md @@ -142,12 +142,6 @@ arguments it receives via the [`[initialize.components]`](/api/data-formats#config-initialize) block in the config. - - -This method was previously called `begin_training`. - - - > #### Example > > ```python diff --git a/website/docs/api/textcategorizer.md b/website/docs/api/textcategorizer.md index ed1205d8c..b69c87a28 100644 --- a/website/docs/api/textcategorizer.md +++ b/website/docs/api/textcategorizer.md @@ -187,12 +187,6 @@ arguments it receives via the [`[initialize.components]`](/api/data-formats#config-initialize) block in the config. - - -This method was previously called `begin_training`. - - - > #### Example > > ```python From d60997febb1c2710543b46c18e3875317349dcf9 Mon Sep 17 00:00:00 2001 From: Paul O'Leary McCann Date: Thu, 8 Dec 2022 19:45:52 +0900 Subject: [PATCH 025/123] Remove old model shortcuts (#11916) * Remove old model shortcuts * Remove error, docs warnings about shortcuts * Fix import in util Accidentally deleted the whole import and not just the old part... * Change universe example to v3 style * Switch ubuntu-latest to ubuntu-20.04 in main tests (#11928) * Switch ubuntu-latest to ubuntu-20.04 in main tests * Only use 20.04 for 3.6 * Update some model loading in Universe * Add v2 tag to neuralcoref * Use the spacy-version feature instead of a v2 tag Co-authored-by: svlandeg --- spacy/cli/download.py | 7 ------- spacy/errors.py | 16 ---------------- spacy/util.py | 4 +--- website/UNIVERSE.md | 2 +- website/docs/usage/models.md | 27 --------------------------- website/meta/universe.json | 20 ++++++++++++-------- 6 files changed, 14 insertions(+), 62 deletions(-) diff --git a/spacy/cli/download.py b/spacy/cli/download.py index 0c9a32b93..4c998a6e0 100644 --- a/spacy/cli/download.py +++ b/spacy/cli/download.py @@ -8,7 +8,6 @@ from ._util import app, Arg, Opt, WHEEL_SUFFIX, SDIST_SUFFIX from .. import about from ..util import is_package, get_minor_version, run_command from ..util import is_prerelease_version -from ..errors import OLD_MODEL_SHORTCUTS @app.command( @@ -61,12 +60,6 @@ def download( version = components[-1] else: model_name = model - if model in OLD_MODEL_SHORTCUTS: - msg.warn( - f"As of spaCy v3.0, shortcuts like '{model}' are deprecated. Please " - f"use the full pipeline package name '{OLD_MODEL_SHORTCUTS[model]}' instead." - ) - model_name = OLD_MODEL_SHORTCUTS[model] compatibility = get_compatibility() version = get_version(model_name, compatibility) diff --git a/spacy/errors.py b/spacy/errors.py index 31230d7a4..9ad7d1292 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -720,13 +720,6 @@ class Errors(metaclass=ErrorsWithCodes): "method in component '{name}'. If you want to use this " "method, make sure it's overwritten on the subclass.") E940 = ("Found NaN values in scores.") - E941 = ("Can't find model '{name}'. It looks like you're trying to load a " - "model from a shortcut, which is obsolete as of spaCy v3.0. To " - "load the model, use its full name instead:\n\n" - "nlp = spacy.load(\"{full}\")\n\nFor more details on the available " - "models, see the models directory: https://spacy.io/models. If you " - "want to create a blank model, use spacy.blank: " - "nlp = spacy.blank(\"{name}\")") E942 = ("Executing `after_{name}` callback failed. Expected the function to " "return an initialized nlp object but got: {value}. Maybe " "you forgot to return the modified object in your function?") @@ -955,15 +948,6 @@ class Errors(metaclass=ErrorsWithCodes): "but got '{received_type}'") -# Deprecated model shortcuts, only used in errors and warnings -OLD_MODEL_SHORTCUTS = { - "en": "en_core_web_sm", "de": "de_core_news_sm", "es": "es_core_news_sm", - "pt": "pt_core_news_sm", "fr": "fr_core_news_sm", "it": "it_core_news_sm", - "nl": "nl_core_news_sm", "el": "el_core_news_sm", "nb": "nb_core_news_sm", - "lt": "lt_core_news_sm", "xx": "xx_ent_wiki_sm" -} - - # fmt: on diff --git a/spacy/util.py b/spacy/util.py index 4bdde1ad1..d674fb9ce 100644 --- a/spacy/util.py +++ b/spacy/util.py @@ -40,7 +40,7 @@ except ImportError: from .symbols import ORTH from .compat import cupy, CudaStream, is_windows, importlib_metadata -from .errors import Errors, Warnings, OLD_MODEL_SHORTCUTS +from .errors import Errors, Warnings from . import about if TYPE_CHECKING: @@ -427,8 +427,6 @@ def load_model( return load_model_from_path(Path(name), **kwargs) # type: ignore[arg-type] elif hasattr(name, "exists"): # Path or Path-like to model data return load_model_from_path(name, **kwargs) # type: ignore[arg-type] - if name in OLD_MODEL_SHORTCUTS: - raise IOError(Errors.E941.format(name=name, full=OLD_MODEL_SHORTCUTS[name])) # type: ignore[index] raise IOError(Errors.E050.format(name=name)) diff --git a/website/UNIVERSE.md b/website/UNIVERSE.md index 770bbde13..c3e49ba43 100644 --- a/website/UNIVERSE.md +++ b/website/UNIVERSE.md @@ -51,7 +51,7 @@ markup is correct. "import spacy", "import package_name", "", - "nlp = spacy.load('en')", + "nlp = spacy.load('en_core_web_sm')", "nlp.add_pipe(package_name)" ], "code_language": "python", diff --git a/website/docs/usage/models.md b/website/docs/usage/models.md index 3b1558bd8..03d0d535c 100644 --- a/website/docs/usage/models.md +++ b/website/docs/usage/models.md @@ -342,22 +342,6 @@ The easiest way to download a trained pipeline is via spaCy's [`download`](/api/cli#download) command. It takes care of finding the best-matching package compatible with your spaCy installation. -> #### Important note for v3.0 -> -> Note that as of spaCy v3.0, shortcut links like `en` that create (potentially -> brittle) symlinks in your spaCy installation are **deprecated**. To download -> and load an installed pipeline package, use its full name: -> -> ```diff -> - python -m spacy download en -> + python -m spacy download en_core_web_sm -> ``` -> -> ```diff -> - nlp = spacy.load("en") -> + nlp = spacy.load("en_core_web_sm") -> ``` - ```cli # Download best-matching version of a package for your spaCy installation $ python -m spacy download en_core_web_sm @@ -489,17 +473,6 @@ spacy.cli.download("en_core_web_sm") To load a pipeline package, use [`spacy.load`](/api/top-level#spacy.load) with the package name or a path to the data directory: -> #### Important note for v3.0 -> -> Note that as of spaCy v3.0, shortcut links like `en` that create (potentially -> brittle) symlinks in your spaCy installation are **deprecated**. To download -> and load an installed pipeline package, use its full name: -> -> ```diff -> - python -m spacy download en -> + python -m spacy download en_core_web_sm -> ``` - ```python import spacy nlp = spacy.load("en_core_web_sm") # load package "en_core_web_sm" diff --git a/website/meta/universe.json b/website/meta/universe.json index 97b53e9c5..168a39a5f 100644 --- a/website/meta/universe.json +++ b/website/meta/universe.json @@ -1021,7 +1021,8 @@ "author_links": { "github": "mholtzscher" }, - "category": ["pipeline"] + "category": ["pipeline"], + "spacy_version": 2 }, { "id": "spacy-sentence-segmenter", @@ -1045,7 +1046,7 @@ { "id": "spacy_cld", "title": "spaCy-CLD", - "slogan": "Add language detection to your spaCy pipeline using CLD2", + "slogan": "Add language detection to your spaCy v2 pipeline using CLD2", "description": "spaCy-CLD operates on `Doc` and `Span` spaCy objects. When called on a `Doc` or `Span`, the object is given two attributes: `languages` (a list of up to 3 language codes) and `language_scores` (a dictionary mapping language codes to confidence scores between 0 and 1).\n\nspacy-cld is a little extension that wraps the [PYCLD2](https://github.com/aboSamoor/pycld2) Python library, which in turn wraps the [Compact Language Detector 2](https://github.com/CLD2Owners/cld2) C library originally built at Google for the Chromium project. CLD2 uses character n-grams as features and a Naive Bayes classifier to identify 80+ languages from Unicode text strings (or XML/HTML). It can detect up to 3 different languages in a given document, and reports a confidence score (reported in with each language.", "github": "nickdavidhaynes/spacy-cld", "pip": "spacy_cld", @@ -1065,7 +1066,8 @@ "author_links": { "github": "nickdavidhaynes" }, - "category": ["pipeline"] + "category": ["pipeline"], + "spacy_version": 2 }, { "id": "spacy-iwnlp", @@ -1139,7 +1141,8 @@ "github": "sammous" }, "category": ["pipeline"], - "tags": ["pos", "lemmatizer", "french"] + "tags": ["pos", "lemmatizer", "french"], + "spacy_version": 2 }, { "id": "lemmy", @@ -1333,8 +1336,8 @@ }, { "id": "neuralcoref", - "slogan": "State-of-the-art coreference resolution based on neural nets and spaCy", - "description": "This coreference resolution module is based on the super fast [spaCy](https://spacy.io/) parser and uses the neural net scoring model described in [Deep Reinforcement Learning for Mention-Ranking Coreference Models](http://cs.stanford.edu/people/kevclark/resources/clark-manning-emnlp2016-deep.pdf) by Kevin Clark and Christopher D. Manning, EMNLP 2016. Since ✨Neuralcoref v2.0, you can train the coreference resolution system on your own dataset — e.g., another language than English! — **provided you have an annotated dataset**. Note that to use neuralcoref with spaCy > 2.1.0, you'll have to install neuralcoref from source.", + "slogan": "State-of-the-art coreference resolution based on neural nets and spaCy v2", + "description": "This coreference resolution module is based on the super fast spaCy parser and uses the neural net scoring model described in [Deep Reinforcement Learning for Mention-Ranking Coreference Models](http://cs.stanford.edu/people/kevclark/resources/clark-manning-emnlp2016-deep.pdf) by Kevin Clark and Christopher D. Manning, EMNLP 2016. Since ✨Neuralcoref v2.0, you can train the coreference resolution system on your own dataset — e.g., another language than English! — **provided you have an annotated dataset**. Note that to use neuralcoref with spaCy > 2.1.0, you'll have to install neuralcoref from source, and v3+ is not supported.", "github": "huggingface/neuralcoref", "thumb": "https://i.imgur.com/j6FO9O6.jpg", "code_example": [ @@ -1355,7 +1358,8 @@ "github": "huggingface" }, "category": ["standalone", "conversational", "models"], - "tags": ["coref"] + "tags": ["coref"], + "spacy_version": 2 }, { "id": "neuralcoref-vizualizer", @@ -1431,7 +1435,7 @@ "import spacy", "import explacy", "", - "nlp = spacy.load('en')", + "nlp = spacy.load('en_core_web_sm')", "explacy.print_parse_info(nlp, 'The salad was surprisingly tasty.')" ], "author": "Tyler Neylon", From f5aabaf7d69e1dc5a1f510bb47297b7f45f49100 Mon Sep 17 00:00:00 2001 From: Madeesh Kannan Date: Thu, 8 Dec 2022 13:24:45 +0100 Subject: [PATCH 026/123] Remove unused, experimental multi-task components (#11919) * Remove experimental multi-task components These are incomplete implementations and are not usable in their current state. * Remove orphaned error message * Switch ubuntu-latest to ubuntu-20.04 in main tests (#11928) * Switch ubuntu-latest to ubuntu-20.04 in main tests * Only use 20.04 for 3.6 * Revert "Switch ubuntu-latest to ubuntu-20.04 in main tests (#11928)" This reverts commit 77c0fd7b176be80e8438fa21440a85d1fe26e39b. Co-authored-by: Paul O'Leary McCann --- setup.py | 1 - spacy/errors.py | 2 - spacy/pipeline/multitask.pyx | 221 ----------------------------------- 3 files changed, 224 deletions(-) delete mode 100644 spacy/pipeline/multitask.pyx diff --git a/setup.py b/setup.py index bc911276f..55494344b 100755 --- a/setup.py +++ b/setup.py @@ -38,7 +38,6 @@ MOD_NAMES = [ "spacy.pipeline.dep_parser", "spacy.pipeline._edit_tree_internals.edit_trees", "spacy.pipeline.morphologizer", - "spacy.pipeline.multitask", "spacy.pipeline.ner", "spacy.pipeline.pipe", "spacy.pipeline.trainable_pipe", diff --git a/spacy/errors.py b/spacy/errors.py index 9ad7d1292..c097348ef 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -243,8 +243,6 @@ class Errors(metaclass=ErrorsWithCodes): "https://spacy.io/usage/models") E011 = ("Unknown operator: '{op}'. Options: {opts}") E012 = ("Cannot add pattern for zero tokens to matcher.\nKey: {key}") - E016 = ("MultitaskObjective target should be function or one of: dep, " - "tag, ent, dep_tag_offset, ent_tag.") E017 = ("Can only add 'str' inputs to StringStore. Got type: {value_type}") E018 = ("Can't retrieve string for hash '{hash_value}'. This usually " "refers to an issue with the `Vocab` or `StringStore`.") diff --git a/spacy/pipeline/multitask.pyx b/spacy/pipeline/multitask.pyx deleted file mode 100644 index 8c44061e2..000000000 --- a/spacy/pipeline/multitask.pyx +++ /dev/null @@ -1,221 +0,0 @@ -# cython: infer_types=True, profile=True, binding=True -from typing import Optional -import numpy -from thinc.api import CosineDistance, to_categorical, Model, Config -from thinc.api import set_dropout_rate - -from ..tokens.doc cimport Doc - -from .trainable_pipe import TrainablePipe -from .tagger import Tagger -from ..training import validate_examples -from ..language import Language -from ._parser_internals import nonproj -from ..attrs import POS, ID -from ..errors import Errors - - -default_model_config = """ -[model] -@architectures = "spacy.MultiTask.v1" -maxout_pieces = 3 -token_vector_width = 96 - -[model.tok2vec] -@architectures = "spacy.HashEmbedCNN.v2" -pretrained_vectors = null -width = 96 -depth = 4 -embed_size = 2000 -window_size = 1 -maxout_pieces = 2 -subword_features = true -""" -DEFAULT_MT_MODEL = Config().from_str(default_model_config)["model"] - - -@Language.factory( - "nn_labeller", - default_config={"labels": None, "target": "dep_tag_offset", "model": DEFAULT_MT_MODEL} -) -def make_nn_labeller(nlp: Language, name: str, model: Model, labels: Optional[dict], target: str): - return MultitaskObjective(nlp.vocab, model, name) - - -class MultitaskObjective(Tagger): - """Experimental: Assist training of a parser or tagger, by training a - side-objective. - """ - - def __init__(self, vocab, model, name="nn_labeller", *, target): - self.vocab = vocab - self.model = model - self.name = name - if target == "dep": - self.make_label = self.make_dep - elif target == "tag": - self.make_label = self.make_tag - elif target == "ent": - self.make_label = self.make_ent - elif target == "dep_tag_offset": - self.make_label = self.make_dep_tag_offset - elif target == "ent_tag": - self.make_label = self.make_ent_tag - elif target == "sent_start": - self.make_label = self.make_sent_start - elif hasattr(target, "__call__"): - self.make_label = target - else: - raise ValueError(Errors.E016) - cfg = {"labels": {}, "target": target} - self.cfg = dict(cfg) - - @property - def labels(self): - return self.cfg.setdefault("labels", {}) - - @labels.setter - def labels(self, value): - self.cfg["labels"] = value - - def set_annotations(self, docs, dep_ids): - pass - - def initialize(self, get_examples, nlp=None, labels=None): - if not hasattr(get_examples, "__call__"): - err = Errors.E930.format(name="MultitaskObjective", obj=type(get_examples)) - raise ValueError(err) - if labels is not None: - self.labels = labels - else: - for example in get_examples(): - for token in example.y: - label = self.make_label(token) - if label is not None and label not in self.labels: - self.labels[label] = len(self.labels) - self.model.initialize() # TODO: fix initialization by defining X and Y - - def predict(self, docs): - tokvecs = self.model.get_ref("tok2vec")(docs) - scores = self.model.get_ref("softmax")(tokvecs) - return tokvecs, scores - - def get_loss(self, examples, scores): - cdef int idx = 0 - correct = numpy.zeros((scores.shape[0],), dtype="i") - guesses = scores.argmax(axis=1) - docs = [eg.predicted for eg in examples] - for i, eg in enumerate(examples): - # Handles alignment for tokenization differences - doc_annots = eg.get_aligned() # TODO - for j in range(len(eg.predicted)): - tok_annots = {key: values[j] for key, values in tok_annots.items()} - label = self.make_label(j, tok_annots) - if label is None or label not in self.labels: - correct[idx] = guesses[idx] - else: - correct[idx] = self.labels[label] - idx += 1 - correct = self.model.ops.xp.array(correct, dtype="i") - d_scores = scores - to_categorical(correct, n_classes=scores.shape[1]) - loss = (d_scores**2).sum() - return float(loss), d_scores - - @staticmethod - def make_dep(token): - return token.dep_ - - @staticmethod - def make_tag(token): - return token.tag_ - - @staticmethod - def make_ent(token): - if token.ent_iob_ == "O": - return "O" - else: - return token.ent_iob_ + "-" + token.ent_type_ - - @staticmethod - def make_dep_tag_offset(token): - dep = token.dep_ - tag = token.tag_ - offset = token.head.i - token.i - offset = min(offset, 2) - offset = max(offset, -2) - return f"{dep}-{tag}:{offset}" - - @staticmethod - def make_ent_tag(token): - if token.ent_iob_ == "O": - ent = "O" - else: - ent = token.ent_iob_ + "-" + token.ent_type_ - tag = token.tag_ - return f"{tag}-{ent}" - - @staticmethod - def make_sent_start(token): - """A multi-task objective for representing sentence boundaries, - using BILU scheme. (O is impossible) - """ - if token.is_sent_start and token.is_sent_end: - return "U-SENT" - elif token.is_sent_start: - return "B-SENT" - else: - return "I-SENT" - - -class ClozeMultitask(TrainablePipe): - def __init__(self, vocab, model, **cfg): - self.vocab = vocab - self.model = model - self.cfg = cfg - self.distance = CosineDistance(ignore_zeros=True, normalize=False) # TODO: in config - - def set_annotations(self, docs, dep_ids): - pass - - def initialize(self, get_examples, nlp=None): - self.model.initialize() # TODO: fix initialization by defining X and Y - X = self.model.ops.alloc((5, self.model.get_ref("tok2vec").get_dim("nO"))) - self.model.output_layer.initialize(X) - - def predict(self, docs): - tokvecs = self.model.get_ref("tok2vec")(docs) - vectors = self.model.get_ref("output_layer")(tokvecs) - return tokvecs, vectors - - def get_loss(self, examples, vectors, prediction): - validate_examples(examples, "ClozeMultitask.get_loss") - # The simplest way to implement this would be to vstack the - # token.vector values, but that's a bit inefficient, especially on GPU. - # Instead we fetch the index into the vectors table for each of our tokens, - # and look them up all at once. This prevents data copying. - ids = self.model.ops.flatten([eg.predicted.to_array(ID).ravel() for eg in examples]) - target = vectors[ids] - gradient = self.distance.get_grad(prediction, target) - loss = self.distance.get_loss(prediction, target) - return float(loss), gradient - - def update(self, examples, *, drop=0., sgd=None, losses=None): - pass - - def rehearse(self, examples, drop=0., sgd=None, losses=None): - if losses is not None and self.name not in losses: - losses[self.name] = 0. - set_dropout_rate(self.model, drop) - validate_examples(examples, "ClozeMultitask.rehearse") - docs = [eg.predicted for eg in examples] - predictions, bp_predictions = self.model.begin_update() - loss, d_predictions = self.get_loss(examples, self.vocab.vectors.data, predictions) - bp_predictions(d_predictions) - if sgd is not None: - self.finish_update(sgd) - if losses is not None: - losses[self.name] += loss - return losses - - def add_label(self, label): - raise NotImplementedError From ca75190a3d2972392d9333d731fdf6d1b4a48793 Mon Sep 17 00:00:00 2001 From: Edward <43848523+thomashacker@users.noreply.github.com> Date: Mon, 12 Dec 2022 08:55:53 +0100 Subject: [PATCH 027/123] Custom extensions for spans with equal boundaries (#11429) * Init * Fix return type for mypy * adjust types and improve setting new attributes * Add underscore changes to json conversion * Add test and underscore changes to from_docs * add underscore changes and test to span.to_doc * update return values Co-authored-by: Sofie Van Landeghem * Add types to function Co-authored-by: Sofie Van Landeghem * adjust formatting Co-authored-by: Sofie Van Landeghem * shorten return type Co-authored-by: Sofie Van Landeghem * add helper function to improve readability * Improve code and add comments * rerun azure tests * Fix tests for json conversion Co-authored-by: Sofie Van Landeghem --- spacy/tests/doc/test_underscore.py | 119 +++++++++++++++++++++++++++++ spacy/tokens/doc.pyx | 30 ++++++-- spacy/tokens/span.pyx | 38 +++++++-- spacy/tokens/underscore.py | 44 ++++++++++- 4 files changed, 214 insertions(+), 17 deletions(-) diff --git a/spacy/tests/doc/test_underscore.py b/spacy/tests/doc/test_underscore.py index b934221af..d23bb3162 100644 --- a/spacy/tests/doc/test_underscore.py +++ b/spacy/tests/doc/test_underscore.py @@ -3,6 +3,10 @@ from mock import Mock from spacy.tokens import Doc, Span, Token from spacy.tokens.underscore import Underscore +# Helper functions +def _get_tuple(s: Span): + return "._.", "span_extension", s.start_char, s.end_char, s.label, s.kb_id, s.id + @pytest.fixture(scope="function", autouse=True) def clean_underscore(): @@ -171,3 +175,118 @@ def test_underscore_docstring(en_vocab): doc = Doc(en_vocab, words=["hello", "world"]) assert test_method.__doc__ == "I am a docstring" assert doc._.test_docstrings.__doc__.rsplit(". ")[-1] == "I am a docstring" + + +def test_underscore_for_unique_span(en_tokenizer): + """Test that spans with the same boundaries but with different labels are uniquely identified (see #9706).""" + Doc.set_extension(name="doc_extension", default=None) + Span.set_extension(name="span_extension", default=None) + Token.set_extension(name="token_extension", default=None) + + # Initialize doc + text = "Hello, world!" + doc = en_tokenizer(text) + span_1 = Span(doc, 0, 2, "SPAN_1") + span_2 = Span(doc, 0, 2, "SPAN_2") + + # Set custom extensions + doc._.doc_extension = "doc extension" + doc[0]._.token_extension = "token extension" + span_1._.span_extension = "span_1 extension" + span_2._.span_extension = "span_2 extension" + + # Assert extensions + assert doc.user_data[_get_tuple(span_1)] == "span_1 extension" + assert doc.user_data[_get_tuple(span_2)] == "span_2 extension" + + # Change label of span and assert extensions + span_1.label_ = "NEW_LABEL" + assert doc.user_data[_get_tuple(span_1)] == "span_1 extension" + assert doc.user_data[_get_tuple(span_2)] == "span_2 extension" + + # Change KB_ID and assert extensions + span_1.kb_id_ = "KB_ID" + assert doc.user_data[_get_tuple(span_1)] == "span_1 extension" + assert doc.user_data[_get_tuple(span_2)] == "span_2 extension" + + # Change extensions and assert + span_2._.span_extension = "updated span_2 extension" + assert doc.user_data[_get_tuple(span_1)] == "span_1 extension" + assert doc.user_data[_get_tuple(span_2)] == "updated span_2 extension" + + # Change span ID and assert extensions + span_2.id = 2 + assert doc.user_data[_get_tuple(span_1)] == "span_1 extension" + assert doc.user_data[_get_tuple(span_2)] == "updated span_2 extension" + + # Assert extensions with original key + assert doc.user_data[("._.", "doc_extension", None, None)] == "doc extension" + assert doc.user_data[("._.", "token_extension", 0, None)] == "token extension" + + +def test_underscore_for_unique_span_from_docs(en_tokenizer): + """Test that spans in the user_data keep the same data structure when using Doc.from_docs""" + Span.set_extension(name="span_extension", default=None) + Token.set_extension(name="token_extension", default=None) + + # Initialize doc + text_1 = "Hello, world!" + doc_1 = en_tokenizer(text_1) + span_1a = Span(doc_1, 0, 2, "SPAN_1a") + span_1b = Span(doc_1, 0, 2, "SPAN_1b") + + text_2 = "This is a test." + doc_2 = en_tokenizer(text_2) + span_2a = Span(doc_2, 0, 3, "SPAN_2a") + + # Set custom extensions + doc_1[0]._.token_extension = "token_1" + doc_2[1]._.token_extension = "token_2" + span_1a._.span_extension = "span_1a extension" + span_1b._.span_extension = "span_1b extension" + span_2a._.span_extension = "span_2a extension" + + doc = Doc.from_docs([doc_1, doc_2]) + # Assert extensions + assert doc_1.user_data[_get_tuple(span_1a)] == "span_1a extension" + assert doc_1.user_data[_get_tuple(span_1b)] == "span_1b extension" + assert doc_2.user_data[_get_tuple(span_2a)] == "span_2a extension" + + # Check extensions on merged doc + assert doc.user_data[_get_tuple(span_1a)] == "span_1a extension" + assert doc.user_data[_get_tuple(span_1b)] == "span_1b extension" + assert ( + doc.user_data[ + ( + "._.", + "span_extension", + span_2a.start_char + len(doc_1.text) + 1, + span_2a.end_char + len(doc_1.text) + 1, + span_2a.label, + span_2a.kb_id, + span_2a.id, + ) + ] + == "span_2a extension" + ) + + +def test_underscore_for_unique_span_as_span(en_tokenizer): + """Test that spans in the user_data keep the same data structure when using Span.as_doc""" + Span.set_extension(name="span_extension", default=None) + + # Initialize doc + text = "Hello, world!" + doc = en_tokenizer(text) + span_1 = Span(doc, 0, 2, "SPAN_1") + span_2 = Span(doc, 0, 2, "SPAN_2") + + # Set custom extensions + span_1._.span_extension = "span_1 extension" + span_2._.span_extension = "span_2 extension" + + span_doc = span_1.as_doc(copy_user_data=True) + + # Assert extensions + assert span_doc.user_data[_get_tuple(span_1)] == "span_1 extension" + assert span_doc.user_data[_get_tuple(span_2)] == "span_2 extension" diff --git a/spacy/tokens/doc.pyx b/spacy/tokens/doc.pyx index bf3da0ce4..b7506f745 100644 --- a/spacy/tokens/doc.pyx +++ b/spacy/tokens/doc.pyx @@ -1177,13 +1177,22 @@ cdef class Doc: if "user_data" not in exclude: for key, value in doc.user_data.items(): - if isinstance(key, tuple) and len(key) == 4 and key[0] == "._.": - data_type, name, start, end = key + if isinstance(key, tuple) and len(key) >= 4 and key[0] == "._.": + data_type = key[0] + name = key[1] + start = key[2] + end = key[3] if start is not None or end is not None: start += char_offset if end is not None: end += char_offset - concat_user_data[(data_type, name, start, end)] = copy.copy(value) + _label = key[4] + _kb_id = key[5] + _span_id = key[6] + concat_user_data[(data_type, name, start, end, _label, _kb_id, _span_id)] = copy.copy(value) + else: + concat_user_data[(data_type, name, start, end)] = copy.copy(value) + else: warnings.warn(Warnings.W101.format(name=name)) else: @@ -1627,7 +1636,11 @@ cdef class Doc: Span.set_extension(span_attr) for span_data in doc_json["underscore_span"][span_attr]: value = span_data["value"] - self.char_span(span_data["start"], span_data["end"])._.set(span_attr, value) + span = self.char_span(span_data["start"], span_data["end"]) + span.label = span_data["label"] + span.kb_id = span_data["kb_id"] + span.id = span_data["id"] + span._.set(span_attr, value) return self def to_json(self, underscore=None): @@ -1705,13 +1718,16 @@ cdef class Doc: if attr not in data["underscore_token"]: data["underscore_token"][attr] = [] data["underscore_token"][attr].append({"start": start, "value": value}) - # Span attribute - elif start is not None and end is not None: + # Else span attribute + elif end is not None: + _label = data_key[4] + _kb_id = data_key[5] + _span_id = data_key[6] if "underscore_span" not in data: data["underscore_span"] = {} if attr not in data["underscore_span"]: data["underscore_span"][attr] = [] - data["underscore_span"][attr].append({"start": start, "end": end, "value": value}) + data["underscore_span"][attr].append({"start": start, "end": end, "value": value, "label": _label, "kb_id": _kb_id, "id":_span_id}) for attr in underscore: if attr not in user_keys: diff --git a/spacy/tokens/span.pyx b/spacy/tokens/span.pyx index 5530dd127..6f2d0379c 100644 --- a/spacy/tokens/span.pyx +++ b/spacy/tokens/span.pyx @@ -218,11 +218,10 @@ cdef class Span: cdef SpanC* span_c = self.span_c() """Custom extension attributes registered via `set_extension`.""" return Underscore(Underscore.span_extensions, self, - start=span_c.start_char, end=span_c.end_char) + start=span_c.start_char, end=span_c.end_char, label=self.label, kb_id=self.kb_id, span_id=self.id) def as_doc(self, *, bint copy_user_data=False, array_head=None, array=None): """Create a `Doc` object with a copy of the `Span`'s data. - copy_user_data (bool): Whether or not to copy the original doc's user data. array_head (tuple): `Doc` array attrs, can be passed in to speed up computation. array (ndarray): `Doc` as array, can be passed in to speed up computation. @@ -275,12 +274,22 @@ cdef class Span: char_offset = self.start_char for key, value in self.doc.user_data.items(): if isinstance(key, tuple) and len(key) == 4 and key[0] == "._.": - data_type, name, start, end = key + data_type = key[0] + name = key[1] + start = key[2] + end = key[3] if start is not None or end is not None: start -= char_offset + # Check if Span object if end is not None: end -= char_offset - user_data[(data_type, name, start, end)] = copy.copy(value) + _label = key[4] + _kb_id = key[5] + _span_id = key[6] + user_data[(data_type, name, start, end, _label, _kb_id, _span_id)] = copy.copy(value) + # Else Token object + else: + user_data[(data_type, name, start, end)] = copy.copy(value) else: user_data[key] = copy.copy(value) doc.user_data = user_data @@ -781,21 +790,36 @@ cdef class Span: return self.span_c().label def __set__(self, attr_t label): - self.span_c().label = label + if label != self.span_c().label : + old_label = self.span_c().label + self.span_c().label = label + new = Underscore(Underscore.span_extensions, self, start=self.span_c().start_char, end=self.span_c().end_char, label=self.label, kb_id=self.kb_id, span_id=self.id) + old = Underscore(Underscore.span_extensions, self, start=self.span_c().start_char, end=self.span_c().end_char, label=old_label, kb_id=self.kb_id, span_id=self.id) + Underscore._replace_keys(old, new) property kb_id: def __get__(self): return self.span_c().kb_id def __set__(self, attr_t kb_id): - self.span_c().kb_id = kb_id + if kb_id != self.span_c().kb_id : + old_kb_id = self.span_c().kb_id + self.span_c().kb_id = kb_id + new = Underscore(Underscore.span_extensions, self, start=self.span_c().start_char, end=self.span_c().end_char, label=self.label, kb_id=self.kb_id, span_id=self.id) + old = Underscore(Underscore.span_extensions, self, start=self.span_c().start_char, end=self.span_c().end_char, label=self.label, kb_id=old_kb_id, span_id=self.id) + Underscore._replace_keys(old, new) property id: def __get__(self): return self.span_c().id def __set__(self, attr_t id): - self.span_c().id = id + if id != self.span_c().id : + old_id = self.span_c().id + self.span_c().id = id + new = Underscore(Underscore.span_extensions, self, start=self.span_c().start_char, end=self.span_c().end_char, label=self.label, kb_id=self.kb_id, span_id=self.id) + old = Underscore(Underscore.span_extensions, self, start=self.span_c().start_char, end=self.span_c().end_char, label=self.label, kb_id=self.kb_id, span_id=old_id) + Underscore._replace_keys(old, new) property ent_id: """Alias for the span's ID.""" diff --git a/spacy/tokens/underscore.py b/spacy/tokens/underscore.py index e9a4e1862..f2f357441 100644 --- a/spacy/tokens/underscore.py +++ b/spacy/tokens/underscore.py @@ -2,10 +2,10 @@ from typing import Dict, Any, List, Optional, Tuple, Union, TYPE_CHECKING import functools import copy from ..errors import Errors +from .span import Span if TYPE_CHECKING: from .doc import Doc - from .span import Span from .token import Token @@ -25,6 +25,9 @@ class Underscore: obj: Union["Doc", "Span", "Token"], start: Optional[int] = None, end: Optional[int] = None, + label: int = 0, + kb_id: int = 0, + span_id: int = 0, ): object.__setattr__(self, "_extensions", extensions) object.__setattr__(self, "_obj", obj) @@ -36,6 +39,10 @@ class Underscore: object.__setattr__(self, "_doc", obj.doc) object.__setattr__(self, "_start", start) object.__setattr__(self, "_end", end) + if type(obj) == Span: + object.__setattr__(self, "_label", label) + object.__setattr__(self, "_kb_id", kb_id) + object.__setattr__(self, "_span_id", span_id) def __dir__(self) -> List[str]: # Hack to enable autocomplete on custom extensions @@ -88,8 +95,39 @@ class Underscore: def has(self, name: str) -> bool: return name in self._extensions - def _get_key(self, name: str) -> Tuple[str, str, Optional[int], Optional[int]]: - return ("._.", name, self._start, self._end) + def _get_key( + self, name: str + ) -> Union[ + Tuple[str, str, Optional[int], Optional[int]], + Tuple[str, str, Optional[int], Optional[int], int, int, int], + ]: + if hasattr(self, "_label"): + return ( + "._.", + name, + self._start, + self._end, + self._label, + self._kb_id, + self._span_id, + ) + else: + return "._.", name, self._start, self._end + + @staticmethod + def _replace_keys(old_underscore: "Underscore", new_underscore: "Underscore"): + """ + This function is called by Span when its kb_id or label are re-assigned. + It checks if any user_data is stored for this span and replaces the keys + """ + for name in old_underscore._extensions: + old_key = old_underscore._get_key(name) + old_doc = old_underscore._doc + new_key = new_underscore._get_key(name) + if old_key != new_key and old_key in old_doc.user_data: + old_underscore._doc.user_data[ + new_key + ] = old_underscore._doc.user_data.pop(old_key) @classmethod def get_state(cls) -> Tuple[Dict[Any, Any], Dict[Any, Any], Dict[Any, Any]]: From f9308aae1342111416ae2ba0de04ea3643e5f1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Sat, 17 Dec 2022 14:32:19 +0100 Subject: [PATCH 028/123] Fix v4 branch to build against Thinc v9 (#11921) * Move `thinc.extra.search` to `spacy.pipeline._parser_internals` Backport of: https://github.com/explosion/spaCy/pull/11317 Co-authored-by: Madeesh Kannan * Replace references to `thinc.backends.linalg` with `CBlas` Backport of: https://github.com/explosion/spaCy/pull/11292 Co-authored-by: Madeesh Kannan * Use cross entropy from `thinc.legacy` * Require thinc>=9.0.0.dev0,<9.1.0 Co-authored-by: Madeesh Kannan --- pyproject.toml | 2 +- requirements.txt | 2 +- setup.cfg | 2 +- setup.py | 2 + spacy/ml/parser_model.pyx | 24 +- .../_parser_internals/_beam_utils.pxd | 2 +- .../_parser_internals/_beam_utils.pyx | 7 +- .../pipeline/_parser_internals/arc_eager.pyx | 2 +- spacy/pipeline/_parser_internals/ner.pyx | 2 +- spacy/pipeline/_parser_internals/search.pxd | 89 +++++ spacy/pipeline/_parser_internals/search.pyx | 306 ++++++++++++++++++ spacy/pipeline/edit_tree_lemmatizer.py | 7 +- spacy/pipeline/morphologizer.pyx | 5 +- spacy/pipeline/senter.pyx | 6 +- spacy/pipeline/tagger.pyx | 7 +- spacy/pipeline/transition_parser.pyx | 2 +- spacy/tests/conftest.py | 31 ++ spacy/tests/parser/_search.pyx | 119 +++++++ spacy/tests/parser/test_search.py | 3 + 19 files changed, 593 insertions(+), 27 deletions(-) create mode 100644 spacy/pipeline/_parser_internals/search.pxd create mode 100644 spacy/pipeline/_parser_internals/search.pyx create mode 100644 spacy/tests/parser/_search.pyx create mode 100644 spacy/tests/parser/test_search.py diff --git a/pyproject.toml b/pyproject.toml index 7abd7a96f..4b0da39b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "cymem>=2.0.2,<2.1.0", "preshed>=3.0.2,<3.1.0", "murmurhash>=0.28.0,<1.1.0", - "thinc>=8.1.0,<8.2.0", + "thinc>=9.0.0.dev0,<9.1.0", "numpy>=1.15.0", ] build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt index 778c05e21..5bd04aa9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ spacy-legacy>=3.0.10,<3.1.0 spacy-loggers>=1.0.0,<2.0.0 cymem>=2.0.2,<2.1.0 preshed>=3.0.2,<3.1.0 -thinc>=8.1.0,<8.2.0 +thinc>=9.0.0.dev0,<9.1.0 ml_datasets>=0.2.0,<0.3.0 murmurhash>=0.28.0,<1.1.0 wasabi>=0.9.1,<1.1.0 diff --git a/setup.cfg b/setup.cfg index 3c1bf5b0b..0870e032e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,7 +38,7 @@ install_requires = murmurhash>=0.28.0,<1.1.0 cymem>=2.0.2,<2.1.0 preshed>=3.0.2,<3.1.0 - thinc>=8.1.0,<8.2.0 + thinc>=9.0.0.dev0,<9.1.0 wasabi>=0.9.1,<1.1.0 srsly>=2.4.3,<3.0.0 catalogue>=2.0.6,<2.1.0 diff --git a/setup.py b/setup.py index 55494344b..77a4cf283 100755 --- a/setup.py +++ b/setup.py @@ -48,6 +48,7 @@ MOD_NAMES = [ "spacy.pipeline._parser_internals.arc_eager", "spacy.pipeline._parser_internals.ner", "spacy.pipeline._parser_internals.nonproj", + "spacy.pipeline._parser_internals.search", "spacy.pipeline._parser_internals._state", "spacy.pipeline._parser_internals.stateclass", "spacy.pipeline._parser_internals.transition_system", @@ -67,6 +68,7 @@ MOD_NAMES = [ "spacy.matcher.dependencymatcher", "spacy.symbols", "spacy.vectors", + "spacy.tests.parser._search", ] COMPILE_OPTIONS = { "msvc": ["/Ox", "/EHsc"], diff --git a/spacy/ml/parser_model.pyx b/spacy/ml/parser_model.pyx index 055fa0bad..91558683b 100644 --- a/spacy/ml/parser_model.pyx +++ b/spacy/ml/parser_model.pyx @@ -3,7 +3,6 @@ cimport numpy as np from libc.math cimport exp from libc.string cimport memset, memcpy from libc.stdlib cimport calloc, free, realloc -from thinc.backends.linalg cimport Vec, VecVec from thinc.backends.cblas cimport saxpy, sgemm import numpy @@ -102,11 +101,10 @@ cdef void predict_states(CBlas cblas, ActivationsC* A, StateC** states, sum_state_features(cblas, A.unmaxed, W.feat_weights, A.token_ids, n.states, n.feats, n.hiddens * n.pieces) for i in range(n.states): - VecVec.add_i(&A.unmaxed[i*n.hiddens*n.pieces], - W.feat_bias, 1., n.hiddens * n.pieces) + saxpy(cblas)(n.hiddens * n.pieces, 1., W.feat_bias, 1, &A.unmaxed[i*n.hiddens*n.pieces], 1) for j in range(n.hiddens): index = i * n.hiddens * n.pieces + j * n.pieces - which = Vec.arg_max(&A.unmaxed[index], n.pieces) + which = _arg_max(&A.unmaxed[index], n.pieces) A.hiddens[i*n.hiddens + j] = A.unmaxed[index + which] memset(A.scores, 0, n.states * n.classes * sizeof(float)) if W.hidden_weights == NULL: @@ -119,8 +117,7 @@ cdef void predict_states(CBlas cblas, ActivationsC* A, StateC** states, 0.0, A.scores, n.classes) # Add bias for i in range(n.states): - VecVec.add_i(&A.scores[i*n.classes], - W.hidden_bias, 1., n.classes) + saxpy(cblas)(n.classes, 1., W.hidden_bias, 1, &A.scores[i*n.classes], 1) # Set unseen classes to minimum value i = 0 min_ = A.scores[0] @@ -158,7 +155,8 @@ cdef void cpu_log_loss(float* d_scores, """Do multi-label log loss""" cdef double max_, gmax, Z, gZ best = arg_max_if_gold(scores, costs, is_valid, O) - guess = Vec.arg_max(scores, O) + guess = _arg_max(scores, O) + if best == -1 or guess == -1: # These shouldn't happen, but if they do, we want to make sure we don't # cause an OOB access. @@ -488,3 +486,15 @@ cdef class precompute_hiddens: return d_best.reshape((d_best.shape + (1,))) return state_vector, backprop_relu + +cdef inline int _arg_max(const float* scores, const int n_classes) nogil: + if n_classes == 2: + return 0 if scores[0] > scores[1] else 1 + cdef int i + cdef int best = 0 + cdef float mode = scores[0] + for i in range(1, n_classes): + if scores[i] > mode: + mode = scores[i] + best = i + return best diff --git a/spacy/pipeline/_parser_internals/_beam_utils.pxd b/spacy/pipeline/_parser_internals/_beam_utils.pxd index de3573fbc..571f246b1 100644 --- a/spacy/pipeline/_parser_internals/_beam_utils.pxd +++ b/spacy/pipeline/_parser_internals/_beam_utils.pxd @@ -1,6 +1,6 @@ from ...typedefs cimport class_t, hash_t -# These are passed as callbacks to thinc.search.Beam +# These are passed as callbacks to .search.Beam cdef int transition_state(void* _dest, void* _src, class_t clas, void* _moves) except -1 cdef int check_final_state(void* _state, void* extra_args) except -1 diff --git a/spacy/pipeline/_parser_internals/_beam_utils.pyx b/spacy/pipeline/_parser_internals/_beam_utils.pyx index fa7df2056..610c8ddee 100644 --- a/spacy/pipeline/_parser_internals/_beam_utils.pyx +++ b/spacy/pipeline/_parser_internals/_beam_utils.pyx @@ -3,17 +3,16 @@ cimport numpy as np import numpy from cpython.ref cimport PyObject, Py_XDECREF -from thinc.extra.search cimport Beam -from thinc.extra.search import MaxViolation -from thinc.extra.search cimport MaxViolation from ...typedefs cimport hash_t, class_t from .transition_system cimport TransitionSystem, Transition from ...errors import Errors +from .search cimport Beam, MaxViolation +from .search import MaxViolation from .stateclass cimport StateC, StateClass -# These are passed as callbacks to thinc.search.Beam +# These are passed as callbacks to .search.Beam cdef int transition_state(void* _dest, void* _src, class_t clas, void* _moves) except -1: dest = _dest src = _src diff --git a/spacy/pipeline/_parser_internals/arc_eager.pyx b/spacy/pipeline/_parser_internals/arc_eager.pyx index 257b5ef8a..a79aef64a 100644 --- a/spacy/pipeline/_parser_internals/arc_eager.pyx +++ b/spacy/pipeline/_parser_internals/arc_eager.pyx @@ -15,7 +15,7 @@ from ...training.example cimport Example from .stateclass cimport StateClass from ._state cimport StateC, ArcC from ...errors import Errors -from thinc.extra.search cimport Beam +from .search cimport Beam cdef weight_t MIN_SCORE = -90000 cdef attr_t SUBTOK_LABEL = hash_string('subtok') diff --git a/spacy/pipeline/_parser_internals/ner.pyx b/spacy/pipeline/_parser_internals/ner.pyx index cc196d85a..53ed03523 100644 --- a/spacy/pipeline/_parser_internals/ner.pyx +++ b/spacy/pipeline/_parser_internals/ner.pyx @@ -6,7 +6,6 @@ from libcpp.vector cimport vector from cymem.cymem cimport Pool from collections import Counter -from thinc.extra.search cimport Beam from ...tokens.doc cimport Doc from ...tokens.span import Span @@ -17,6 +16,7 @@ from ...attrs cimport IS_SPACE from ...structs cimport TokenC, SpanC from ...training import split_bilu_label from ...training.example cimport Example +from .search cimport Beam from .stateclass cimport StateClass from ._state cimport StateC from .transition_system cimport Transition, do_func_t diff --git a/spacy/pipeline/_parser_internals/search.pxd b/spacy/pipeline/_parser_internals/search.pxd new file mode 100644 index 000000000..dfe30e1c1 --- /dev/null +++ b/spacy/pipeline/_parser_internals/search.pxd @@ -0,0 +1,89 @@ +from cymem.cymem cimport Pool + +from libc.stdint cimport uint32_t +from libc.stdint cimport uint64_t +from libcpp.pair cimport pair +from libcpp.queue cimport priority_queue +from libcpp.vector cimport vector + +from ...typedefs cimport class_t, weight_t, hash_t + +ctypedef pair[weight_t, size_t] Entry +ctypedef priority_queue[Entry] Queue + + +ctypedef int (*trans_func_t)(void* dest, void* src, class_t clas, void* x) except -1 + +ctypedef void* (*init_func_t)(Pool mem, int n, void* extra_args) except NULL + +ctypedef int (*del_func_t)(Pool mem, void* state, void* extra_args) except -1 + +ctypedef int (*finish_func_t)(void* state, void* extra_args) except -1 + +ctypedef hash_t (*hash_func_t)(void* state, void* x) except 0 + + +cdef struct _State: + void* content + class_t* hist + weight_t score + weight_t loss + int i + int t + bint is_done + + +cdef class Beam: + cdef Pool mem + cdef class_t nr_class + cdef class_t width + cdef class_t size + cdef public weight_t min_density + cdef int t + cdef readonly bint is_done + cdef list histories + cdef list _parent_histories + cdef weight_t** scores + cdef int** is_valid + cdef weight_t** costs + cdef _State* _parents + cdef _State* _states + cdef del_func_t del_func + + cdef int _fill(self, Queue* q, weight_t** scores, int** is_valid) except -1 + + cdef inline void* at(self, int i) nogil: + return self._states[i].content + + cdef int initialize(self, init_func_t init_func, del_func_t del_func, int n, void* extra_args) except -1 + cdef int advance(self, trans_func_t transition_func, hash_func_t hash_func, + void* extra_args) except -1 + cdef int check_done(self, finish_func_t finish_func, void* extra_args) except -1 + + + cdef inline void set_cell(self, int i, int j, weight_t score, int is_valid, weight_t cost) nogil: + self.scores[i][j] = score + self.is_valid[i][j] = is_valid + self.costs[i][j] = cost + + cdef int set_row(self, int i, const weight_t* scores, const int* is_valid, + const weight_t* costs) except -1 + cdef int set_table(self, weight_t** scores, int** is_valid, weight_t** costs) except -1 + + +cdef class MaxViolation: + cdef Pool mem + cdef weight_t cost + cdef weight_t delta + cdef readonly weight_t p_score + cdef readonly weight_t g_score + cdef readonly double Z + cdef readonly double gZ + cdef class_t n + cdef readonly list p_hist + cdef readonly list g_hist + cdef readonly list p_probs + cdef readonly list g_probs + + cpdef int check(self, Beam pred, Beam gold) except -1 + cpdef int check_crf(self, Beam pred, Beam gold) except -1 diff --git a/spacy/pipeline/_parser_internals/search.pyx b/spacy/pipeline/_parser_internals/search.pyx new file mode 100644 index 000000000..1d9b6dd7a --- /dev/null +++ b/spacy/pipeline/_parser_internals/search.pyx @@ -0,0 +1,306 @@ +# cython: profile=True, experimental_cpp_class_def=True, cdivision=True, infer_types=True +cimport cython +from libc.string cimport memset, memcpy +from libc.math cimport log, exp +import math + +from cymem.cymem cimport Pool +from preshed.maps cimport PreshMap + + +cdef class Beam: + def __init__(self, class_t nr_class, class_t width, weight_t min_density=0.0): + assert nr_class != 0 + assert width != 0 + self.nr_class = nr_class + self.width = width + self.min_density = min_density + self.size = 1 + self.t = 0 + self.mem = Pool() + self.del_func = NULL + self._parents = <_State*>self.mem.alloc(self.width, sizeof(_State)) + self._states = <_State*>self.mem.alloc(self.width, sizeof(_State)) + cdef int i + self.histories = [[] for i in range(self.width)] + self._parent_histories = [[] for i in range(self.width)] + + self.scores = self.mem.alloc(self.width, sizeof(weight_t*)) + self.is_valid = self.mem.alloc(self.width, sizeof(weight_t*)) + self.costs = self.mem.alloc(self.width, sizeof(weight_t*)) + for i in range(self.width): + self.scores[i] = self.mem.alloc(self.nr_class, sizeof(weight_t)) + self.is_valid[i] = self.mem.alloc(self.nr_class, sizeof(int)) + self.costs[i] = self.mem.alloc(self.nr_class, sizeof(weight_t)) + + def __len__(self): + return self.size + + property score: + def __get__(self): + return self._states[0].score + + property min_score: + def __get__(self): + return self._states[self.size-1].score + + property loss: + def __get__(self): + return self._states[0].loss + + property probs: + def __get__(self): + return _softmax([self._states[i].score for i in range(self.size)]) + + property scores: + def __get__(self): + return [self._states[i].score for i in range(self.size)] + + property histories: + def __get__(self): + return self.histories + + cdef int set_row(self, int i, const weight_t* scores, const int* is_valid, + const weight_t* costs) except -1: + cdef int j + for j in range(self.nr_class): + self.scores[i][j] = scores[j] + self.is_valid[i][j] = is_valid[j] + self.costs[i][j] = costs[j] + + cdef int set_table(self, weight_t** scores, int** is_valid, weight_t** costs) except -1: + cdef int i, j + for i in range(self.width): + memcpy(self.scores[i], scores[i], sizeof(weight_t) * self.nr_class) + memcpy(self.is_valid[i], is_valid[i], sizeof(bint) * self.nr_class) + memcpy(self.costs[i], costs[i], sizeof(int) * self.nr_class) + + cdef int initialize(self, init_func_t init_func, del_func_t del_func, int n, void* extra_args) except -1: + for i in range(self.width): + self._states[i].content = init_func(self.mem, n, extra_args) + self._parents[i].content = init_func(self.mem, n, extra_args) + self.del_func = del_func + + def __dealloc__(self): + if self.del_func == NULL: + return + + for i in range(self.width): + self.del_func(self.mem, self._states[i].content, NULL) + self.del_func(self.mem, self._parents[i].content, NULL) + + @cython.cdivision(True) + cdef int advance(self, trans_func_t transition_func, hash_func_t hash_func, + void* extra_args) except -1: + cdef weight_t** scores = self.scores + cdef int** is_valid = self.is_valid + cdef weight_t** costs = self.costs + + cdef Queue* q = new Queue() + self._fill(q, scores, is_valid) + # For a beam of width k, we only ever need 2k state objects. How? + # Each transition takes a parent and a class and produces a new state. + # So, we don't need the whole history --- just the parent. So at + # each step, we take a parent, and apply one or more extensions to + # it. + self._parents, self._states = self._states, self._parents + self._parent_histories, self.histories = self.histories, self._parent_histories + cdef weight_t score + cdef int p_i + cdef int i = 0 + cdef class_t clas + cdef _State* parent + cdef _State* state + cdef hash_t key + cdef PreshMap seen_states = PreshMap(self.width) + cdef uint64_t is_seen + cdef uint64_t one = 1 + while i < self.width and not q.empty(): + data = q.top() + p_i = data.second / self.nr_class + clas = data.second % self.nr_class + score = data.first + q.pop() + parent = &self._parents[p_i] + # Indicates terminal state reached; i.e. state is done + if parent.is_done: + # Now parent will not be changed, so we don't have to copy. + # Once finished, should also be unbranching. + self._states[i], parent[0] = parent[0], self._states[i] + parent.i = self._states[i].i + parent.t = self._states[i].t + parent.is_done = self._states[i].t + self._states[i].score = score + self.histories[i] = list(self._parent_histories[p_i]) + i += 1 + else: + state = &self._states[i] + # The supplied transition function should adjust the destination + # state to be the result of applying the class to the source state + transition_func(state.content, parent.content, clas, extra_args) + key = hash_func(state.content, extra_args) if hash_func is not NULL else 0 + is_seen = seen_states.get(key) + if key == 0 or key == 1 or not is_seen: + if key != 0 and key != 1: + seen_states.set(key, one) + state.score = score + state.loss = parent.loss + costs[p_i][clas] + self.histories[i] = list(self._parent_histories[p_i]) + self.histories[i].append(clas) + i += 1 + del q + self.size = i + assert self.size >= 1 + for i in range(self.width): + memset(self.scores[i], 0, sizeof(weight_t) * self.nr_class) + memset(self.costs[i], 0, sizeof(weight_t) * self.nr_class) + memset(self.is_valid[i], 0, sizeof(int) * self.nr_class) + self.t += 1 + + cdef int check_done(self, finish_func_t finish_func, void* extra_args) except -1: + cdef int i + for i in range(self.size): + if not self._states[i].is_done: + self._states[i].is_done = finish_func(self._states[i].content, extra_args) + for i in range(self.size): + if not self._states[i].is_done: + self.is_done = False + break + else: + self.is_done = True + + @cython.cdivision(True) + cdef int _fill(self, Queue* q, weight_t** scores, int** is_valid) except -1: + """Populate the queue from a k * n matrix of scores, where k is the + beam-width, and n is the number of classes. + """ + cdef Entry entry + cdef weight_t score + cdef _State* s + cdef int i, j, move_id + assert self.size >= 1 + cdef vector[Entry] entries + for i in range(self.size): + s = &self._states[i] + move_id = i * self.nr_class + if s.is_done: + # Update score by path average, following TACL '13 paper. + if self.histories[i]: + entry.first = s.score + (s.score / self.t) + else: + entry.first = s.score + entry.second = move_id + entries.push_back(entry) + else: + for j in range(self.nr_class): + if is_valid[i][j]: + entry.first = s.score + scores[i][j] + entry.second = move_id + j + entries.push_back(entry) + cdef double max_, Z, cutoff + if self.min_density == 0.0: + for i in range(entries.size()): + q.push(entries[i]) + elif not entries.empty(): + max_ = entries[0].first + Z = 0. + cutoff = 0. + # Softmax into probabilities, so we can prune + for i in range(entries.size()): + if entries[i].first > max_: + max_ = entries[i].first + for i in range(entries.size()): + Z += exp(entries[i].first-max_) + cutoff = (1. / Z) * self.min_density + for i in range(entries.size()): + prob = exp(entries[i].first-max_) / Z + if prob >= cutoff: + q.push(entries[i]) + + +cdef class MaxViolation: + def __init__(self): + self.p_score = 0.0 + self.g_score = 0.0 + self.Z = 0.0 + self.gZ = 0.0 + self.delta = -1 + self.cost = 0 + self.p_hist = [] + self.g_hist = [] + self.p_probs = [] + self.g_probs = [] + + cpdef int check(self, Beam pred, Beam gold) except -1: + cdef _State* p = &pred._states[0] + cdef _State* g = &gold._states[0] + cdef weight_t d = p.score - g.score + if p.loss >= 1 and (self.cost == 0 or d > self.delta): + self.cost = p.loss + self.delta = d + self.p_hist = list(pred.histories[0]) + self.g_hist = list(gold.histories[0]) + self.p_score = p.score + self.g_score = g.score + self.Z = 1e-10 + self.gZ = 1e-10 + for i in range(pred.size): + if pred._states[i].loss > 0: + self.Z += exp(pred._states[i].score) + for i in range(gold.size): + if gold._states[i].loss == 0: + prob = exp(gold._states[i].score) + self.Z += prob + self.gZ += prob + + cpdef int check_crf(self, Beam pred, Beam gold) except -1: + d = pred.score - gold.score + seen_golds = set([tuple(gold.histories[i]) for i in range(gold.size)]) + if pred.loss > 0 and (self.cost == 0 or d > self.delta): + p_hist = [] + p_scores = [] + g_hist = [] + g_scores = [] + for i in range(pred.size): + if pred._states[i].loss > 0: + p_scores.append(pred._states[i].score) + p_hist.append(list(pred.histories[i])) + # This can happen from non-monotonic actions + # If we find a better gold analysis this way, be sure to keep it. + elif pred._states[i].loss <= 0 \ + and tuple(pred.histories[i]) not in seen_golds: + g_scores.append(pred._states[i].score) + g_hist.append(list(pred.histories[i])) + for i in range(gold.size): + if gold._states[i].loss == 0: + g_scores.append(gold._states[i].score) + g_hist.append(list(gold.histories[i])) + + all_probs = _softmax(p_scores + g_scores) + p_probs = all_probs[:len(p_scores)] + g_probs_all = all_probs[len(p_scores):] + g_probs = _softmax(g_scores) + + self.cost = pred.loss + self.delta = d + self.p_hist = p_hist + self.g_hist = g_hist + # TODO: These variables are misnamed! These are the gradients of the loss. + self.p_probs = p_probs + # Intuition here: + # The gradient of the loss is: + # P(model) - P(truth) + # Normally, P(truth) is 1 for the gold + # But, if we want to do the "partial credit" scheme, we want + # to create a distribution over the gold, proportional to the scores + # awarded. + self.g_probs = [x-y for x, y in zip(g_probs_all, g_probs)] + + +def _softmax(nums): + if not nums: + return [] + max_ = max(nums) + nums = [(exp(n-max_) if n is not None else None) for n in nums] + Z = sum(n for n in nums if n is not None) + return [(n/Z if n is not None else None) for n in nums] diff --git a/spacy/pipeline/edit_tree_lemmatizer.py b/spacy/pipeline/edit_tree_lemmatizer.py index 9676e2194..0531d4ba5 100644 --- a/spacy/pipeline/edit_tree_lemmatizer.py +++ b/spacy/pipeline/edit_tree_lemmatizer.py @@ -5,8 +5,9 @@ from itertools import islice import numpy as np import srsly -from thinc.api import Config, Model, SequenceCategoricalCrossentropy +from thinc.api import Config, Model from thinc.types import ArrayXd, Floats2d, Ints1d +from thinc.legacy import LegacySequenceCategoricalCrossentropy from ._edit_tree_internals.edit_trees import EditTrees from ._edit_tree_internals.schemas import validate_edit_tree @@ -129,7 +130,9 @@ class EditTreeLemmatizer(TrainablePipe): self, examples: Iterable[Example], scores: List[Floats2d] ) -> Tuple[float, List[Floats2d]]: validate_examples(examples, "EditTreeLemmatizer.get_loss") - loss_func = SequenceCategoricalCrossentropy(normalize=False, missing_value=-1) + loss_func = LegacySequenceCategoricalCrossentropy( + normalize=False, missing_value=-1 + ) truths = [] for eg in examples: diff --git a/spacy/pipeline/morphologizer.pyx b/spacy/pipeline/morphologizer.pyx index 782a1dabe..293add9e1 100644 --- a/spacy/pipeline/morphologizer.pyx +++ b/spacy/pipeline/morphologizer.pyx @@ -1,7 +1,8 @@ # cython: infer_types=True, profile=True, binding=True from typing import Callable, Dict, Iterable, List, Optional, Union import srsly -from thinc.api import SequenceCategoricalCrossentropy, Model, Config +from thinc.api import Model, Config +from thinc.legacy import LegacySequenceCategoricalCrossentropy from thinc.types import Floats2d, Ints1d from itertools import islice @@ -290,7 +291,7 @@ class Morphologizer(Tagger): DOCS: https://spacy.io/api/morphologizer#get_loss """ validate_examples(examples, "Morphologizer.get_loss") - loss_func = SequenceCategoricalCrossentropy(names=tuple(self.labels), normalize=False) + loss_func = LegacySequenceCategoricalCrossentropy(names=tuple(self.labels), normalize=False) truths = [] for eg in examples: eg_truths = [] diff --git a/spacy/pipeline/senter.pyx b/spacy/pipeline/senter.pyx index 93a7ee796..42feeb277 100644 --- a/spacy/pipeline/senter.pyx +++ b/spacy/pipeline/senter.pyx @@ -3,7 +3,9 @@ from typing import Dict, Iterable, Optional, Callable, List, Union from itertools import islice import srsly -from thinc.api import Model, SequenceCategoricalCrossentropy, Config +from thinc.api import Model, Config +from thinc.legacy import LegacySequenceCategoricalCrossentropy + from thinc.types import Floats2d, Ints1d from ..tokens.doc cimport Doc @@ -161,7 +163,7 @@ class SentenceRecognizer(Tagger): """ validate_examples(examples, "SentenceRecognizer.get_loss") labels = self.labels - loss_func = SequenceCategoricalCrossentropy(names=labels, normalize=False) + loss_func = LegacySequenceCategoricalCrossentropy(names=labels, normalize=False) truths = [] for eg in examples: eg_truth = [] diff --git a/spacy/pipeline/tagger.pyx b/spacy/pipeline/tagger.pyx index 3b4715ce5..e12f116af 100644 --- a/spacy/pipeline/tagger.pyx +++ b/spacy/pipeline/tagger.pyx @@ -2,7 +2,8 @@ from typing import Callable, Dict, Iterable, List, Optional, Union import numpy import srsly -from thinc.api import Model, set_dropout_rate, SequenceCategoricalCrossentropy, Config +from thinc.api import Model, set_dropout_rate, Config +from thinc.legacy import LegacySequenceCategoricalCrossentropy from thinc.types import Floats2d, Ints1d import warnings from itertools import islice @@ -244,7 +245,7 @@ class Tagger(TrainablePipe): DOCS: https://spacy.io/api/tagger#rehearse """ - loss_func = SequenceCategoricalCrossentropy() + loss_func = LegacySequenceCategoricalCrossentropy() if losses is None: losses = {} losses.setdefault(self.name, 0.0) @@ -275,7 +276,7 @@ class Tagger(TrainablePipe): DOCS: https://spacy.io/api/tagger#get_loss """ validate_examples(examples, "Tagger.get_loss") - loss_func = SequenceCategoricalCrossentropy(names=self.labels, normalize=False, neg_prefix=self.cfg["neg_prefix"]) + loss_func = LegacySequenceCategoricalCrossentropy(names=self.labels, normalize=False, neg_prefix=self.cfg["neg_prefix"]) # Convert empty tag "" to missing value None so that both misaligned # tokens and tokens with missing annotation have the default missing # value None. diff --git a/spacy/pipeline/transition_parser.pyx b/spacy/pipeline/transition_parser.pyx index 340334b1a..9d7b258c6 100644 --- a/spacy/pipeline/transition_parser.pyx +++ b/spacy/pipeline/transition_parser.pyx @@ -10,12 +10,12 @@ import random import srsly from thinc.api import get_ops, set_dropout_rate, CupyOps, NumpyOps -from thinc.extra.search cimport Beam import numpy.random import numpy import warnings from ._parser_internals.stateclass cimport StateClass +from ._parser_internals.search cimport Beam from ..ml.parser_model cimport alloc_activations, free_activations from ..ml.parser_model cimport predict_states, arg_max_if_valid from ..ml.parser_model cimport WeightsC, ActivationsC, SizesC, cpu_log_loss diff --git a/spacy/tests/conftest.py b/spacy/tests/conftest.py index 2be286a57..b9c4ef715 100644 --- a/spacy/tests/conftest.py +++ b/spacy/tests/conftest.py @@ -1,6 +1,10 @@ import pytest from spacy.util import get_lang_class +import functools from hypothesis import settings +import inspect +import importlib +import sys # Functionally disable deadline settings for tests # to prevent spurious test failures in CI builds. @@ -47,6 +51,33 @@ def pytest_runtest_setup(item): pytest.skip("not referencing any issues") +# Decorator for Cython-built tests +# https://shwina.github.io/cython-testing/ +def cytest(func): + """ + Wraps `func` in a plain Python function. + """ + + @functools.wraps(func) + def wrapped(*args, **kwargs): + bound = inspect.signature(func).bind(*args, **kwargs) + return func(*bound.args, **bound.kwargs) + + return wrapped + + +def register_cython_tests(cython_mod_name: str, test_mod_name: str): + """ + Registers all callables with name `test_*` in Cython module `cython_mod_name` + as attributes in module `test_mod_name`, making them discoverable by pytest. + """ + cython_mod = importlib.import_module(cython_mod_name) + for name in dir(cython_mod): + item = getattr(cython_mod, name) + if callable(item) and name.startswith("test_"): + setattr(sys.modules[test_mod_name], name, item) + + # Fixtures for language tokenizers (languages sorted alphabetically) diff --git a/spacy/tests/parser/_search.pyx b/spacy/tests/parser/_search.pyx new file mode 100644 index 000000000..23fc81644 --- /dev/null +++ b/spacy/tests/parser/_search.pyx @@ -0,0 +1,119 @@ +# cython: infer_types=True, binding=True +from spacy.pipeline._parser_internals.search cimport Beam, MaxViolation +from spacy.typedefs cimport class_t, weight_t +from cymem.cymem cimport Pool + +from ..conftest import cytest +import pytest + +cdef struct TestState: + int length + int x + Py_UNICODE* string + + +cdef int transition(void* dest, void* src, class_t clas, void* extra_args) except -1: + dest_state = dest + src_state = src + dest_state.length = src_state.length + dest_state.x = src_state.x + dest_state.x += clas + if extra_args != NULL: + dest_state.string = extra_args + else: + dest_state.string = src_state.string + + +cdef void* initialize(Pool mem, int n, void* extra_args) except NULL: + state = mem.alloc(1, sizeof(TestState)) + state.length = n + state.x = 1 + if extra_args == NULL: + state.string = u'default' + else: + state.string = extra_args + return state + + +cdef int destroy(Pool mem, void* state, void* extra_args) except -1: + state = state + mem.free(state) + +@cytest +@pytest.mark.parametrize("nr_class,beam_width", + [ + (2, 3), + (3, 6), + (4, 20), + ] +) +def test_init(nr_class, beam_width): + b = Beam(nr_class, beam_width) + assert b.size == 1 + assert b.width == beam_width + assert b.nr_class == nr_class + +@cytest +def test_init_violn(): + MaxViolation() + +@cytest +@pytest.mark.parametrize("nr_class,beam_width,length", + [ + (2, 3, 3), + (3, 6, 15), + (4, 20, 32), + ] +) +def test_initialize(nr_class, beam_width, length): + b = Beam(nr_class, beam_width) + b.initialize(initialize, destroy, length, NULL) + for i in range(b.width): + s = b.at(i) + assert s.length == length, s.length + assert s.string == 'default' + + +@cytest +@pytest.mark.parametrize("nr_class,beam_width,length,extra", + [ + (2, 3, 4, None), + (3, 6, 15, u"test beam 1"), + ] +) +def test_initialize_extra(nr_class, beam_width, length, extra): + b = Beam(nr_class, beam_width) + if extra is None: + b.initialize(initialize, destroy, length, NULL) + else: + b.initialize(initialize, destroy, length, extra) + for i in range(b.width): + s = b.at(i) + assert s.length == length + + +@cytest +@pytest.mark.parametrize("nr_class,beam_width,length", + [ + (3, 6, 15), + (4, 20, 32), + ] +) +def test_transition(nr_class, beam_width, length): + b = Beam(nr_class, beam_width) + b.initialize(initialize, destroy, length, NULL) + b.set_cell(0, 2, 30, True, 0) + b.set_cell(0, 1, 42, False, 0) + b.advance(transition, NULL, NULL) + assert b.size == 1, b.size + assert b.score == 30, b.score + s = b.at(0) + assert s.x == 3 + assert b._states[0].score == 30, b._states[0].score + b.set_cell(0, 1, 10, True, 0) + b.set_cell(0, 2, 20, True, 0) + b.advance(transition, NULL, NULL) + assert b._states[0].score == 50, b._states[0].score + assert b._states[1].score == 40 + s = b.at(0) + assert s.x == 5 diff --git a/spacy/tests/parser/test_search.py b/spacy/tests/parser/test_search.py new file mode 100644 index 000000000..136c3a11b --- /dev/null +++ b/spacy/tests/parser/test_search.py @@ -0,0 +1,3 @@ +from ..conftest import register_cython_tests + +register_cython_tests("spacy.tests.parser._search", __name__) From 2f08deea2a419d9e7378a159eaa5d67dd7f96dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danie=CC=88l=20de=20Kok?= Date: Thu, 22 Dec 2022 10:23:31 +0100 Subject: [PATCH 029/123] Fix fallout from a previous merge --- spacy/pipeline/textcat_multilabel.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spacy/pipeline/textcat_multilabel.py b/spacy/pipeline/textcat_multilabel.py index bdf933c10..d64be66f6 100644 --- a/spacy/pipeline/textcat_multilabel.py +++ b/spacy/pipeline/textcat_multilabel.py @@ -155,11 +155,8 @@ class MultiLabel_TextCategorizer(TextCategorizer): name (str): The component instance name, used to add entries to the losses during training. threshold (float): Cutoff to consider a prediction "positive". -<<<<<<< HEAD - save_activations (bool): save model activations in Doc when annotating. -======= scorer (Optional[Callable]): The scoring method. ->>>>>>> upstream/master + save_activations (bool): save model activations in Doc when annotating. DOCS: https://spacy.io/api/textcategorizer#init """ From 20b63943f50b9ca5cc888cee4060f317cda9e5f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Thu, 29 Dec 2022 08:03:24 +0100 Subject: [PATCH 030/123] Adjust to new `Schedule` class and pass scores to `Optimizer` (#12008) * Adjust to new `Schedule` class and pass scores to `Optimizer` Requires https://github.com/explosion/thinc/pull/804 * Bump minimum Thinc requirement to 9.0.0.dev1 --- pyproject.toml | 2 +- requirements.txt | 2 +- setup.cfg | 2 +- spacy/training/batchers.py | 26 ++++++++++++++++---------- spacy/training/loop.py | 3 ++- spacy/util.py | 8 ++++---- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4b0da39b9..72f04dee3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "cymem>=2.0.2,<2.1.0", "preshed>=3.0.2,<3.1.0", "murmurhash>=0.28.0,<1.1.0", - "thinc>=9.0.0.dev0,<9.1.0", + "thinc>=9.0.0.dev1,<9.1.0", "numpy>=1.15.0", ] build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt index 2bf16ec2b..02479f946 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ spacy-legacy>=3.0.10,<3.1.0 spacy-loggers>=1.0.0,<2.0.0 cymem>=2.0.2,<2.1.0 preshed>=3.0.2,<3.1.0 -thinc>=9.0.0.dev0,<9.1.0 +thinc>=9.0.0.dev1,<9.1.0 ml_datasets>=0.2.0,<0.3.0 murmurhash>=0.28.0,<1.1.0 wasabi>=0.9.1,<1.2.0 diff --git a/setup.cfg b/setup.cfg index 5158a1086..4a8c350cd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,7 +38,7 @@ install_requires = murmurhash>=0.28.0,<1.1.0 cymem>=2.0.2,<2.1.0 preshed>=3.0.2,<3.1.0 - thinc>=9.0.0.dev0,<9.1.0 + thinc>=9.0.0.dev1,<9.1.0 wasabi>=0.9.1,<1.2.0 srsly>=2.4.3,<3.0.0 catalogue>=2.0.6,<2.1.0 diff --git a/spacy/training/batchers.py b/spacy/training/batchers.py index f0b6c3123..73678c7fc 100644 --- a/spacy/training/batchers.py +++ b/spacy/training/batchers.py @@ -2,11 +2,12 @@ from typing import Union, Iterable, Sequence, TypeVar, List, Callable, Iterator from typing import Optional, Any from functools import partial import itertools +from thinc.schedules import Schedule, constant as constant_schedule from ..util import registry, minibatch -Sizing = Union[Sequence[int], int] +Sizing = Union[Sequence[int], int, Schedule[int]] ItemT = TypeVar("ItemT") BatcherT = Callable[[Iterable[ItemT]], Iterable[List[ItemT]]] @@ -111,12 +112,13 @@ def minibatch_by_padded_size( The `len` function is used by default. """ if isinstance(size, int): - size_ = itertools.repeat(size) # type: Iterator[int] + size_ = constant_schedule(size) else: - size_ = iter(size) - for outer_batch in minibatch(seqs, size=buffer): + assert isinstance(size, Schedule) + size_ = size + for step, outer_batch in enumerate(minibatch(seqs, size=buffer)): outer_batch = list(outer_batch) - target_size = next(size_) + target_size = size_(step) for indices in _batch_by_length(outer_batch, target_size, get_length): subbatch = [outer_batch[i] for i in indices] padded_size = max(len(seq) for seq in subbatch) * len(subbatch) @@ -147,10 +149,12 @@ def minibatch_by_words( item. The `len` function is used by default. """ if isinstance(size, int): - size_ = itertools.repeat(size) # type: Iterator[int] + size_ = constant_schedule(size) else: - size_ = iter(size) - target_size = next(size_) + assert isinstance(size, Schedule) + size_ = size + step = 0 + target_size = size_(step) tol_size = target_size * tolerance batch = [] overflow = [] @@ -175,7 +179,8 @@ def minibatch_by_words( else: if batch: yield batch - target_size = next(size_) + step += 1 + target_size = size_(step) tol_size = target_size * tolerance batch = overflow batch_size = overflow_size @@ -193,7 +198,8 @@ def minibatch_by_words( else: if batch: yield batch - target_size = next(size_) + step += 1 + target_size = size_(step) tol_size = target_size * tolerance batch = [seq] batch_size = n_words diff --git a/spacy/training/loop.py b/spacy/training/loop.py index 885257772..c93cba7a7 100644 --- a/spacy/training/loop.py +++ b/spacy/training/loop.py @@ -204,7 +204,7 @@ def train_while_improving( if before_update: before_update_args = {"step": step, "epoch": epoch} before_update(nlp, before_update_args) - dropout = next(dropouts) # type: ignore + dropout = dropouts(optimizer.step) # type: ignore for subbatch in subdivide_batch(batch, accumulate_gradient): nlp.update( subbatch, @@ -230,6 +230,7 @@ def train_while_improving( score, other_scores = evaluate() else: score, other_scores = evaluate() + optimizer.last_score = score results.append((score, step)) is_best_checkpoint = score == max(results)[0] else: diff --git a/spacy/util.py b/spacy/util.py index d674fb9ce..aafbbb5de 100644 --- a/spacy/util.py +++ b/spacy/util.py @@ -9,7 +9,7 @@ import re from pathlib import Path import thinc from thinc.api import NumpyOps, get_current_ops, Adam, Config, Optimizer -from thinc.api import ConfigValidationError, Model +from thinc.api import ConfigValidationError, Model, constant as constant_schedule import functools import itertools import numpy @@ -1582,12 +1582,12 @@ def minibatch(items, size): so that batch-size can vary on each step. """ if isinstance(size, int): - size_ = itertools.repeat(size) + size_ = constant_schedule(size) else: size_ = size items = iter(items) - while True: - batch_size = next(size_) + for step in itertools.count(): + batch_size = size_(step) batch = list(itertools.islice(items, int(batch_size))) if len(batch) == 0: break From b510fbd0aacfdb96bbb0f25d3cb5960ce74d1a92 Mon Sep 17 00:00:00 2001 From: Tetsuo Kiso Date: Wed, 4 Jan 2023 01:43:09 +0900 Subject: [PATCH 031/123] Delete unused imports for StringStore (#12040) --- spacy/lexeme.pxd | 1 - spacy/tokenizer.pxd | 1 - 2 files changed, 2 deletions(-) diff --git a/spacy/lexeme.pxd b/spacy/lexeme.pxd index 8dea0d6a2..2d14edcd6 100644 --- a/spacy/lexeme.pxd +++ b/spacy/lexeme.pxd @@ -5,7 +5,6 @@ from .attrs cimport attr_id_t from .attrs cimport ID, ORTH, LOWER, NORM, SHAPE, PREFIX, SUFFIX, LENGTH, LANG from .structs cimport LexemeC -from .strings cimport StringStore from .vocab cimport Vocab diff --git a/spacy/tokenizer.pxd b/spacy/tokenizer.pxd index 86e62ddbf..6f9dfc90f 100644 --- a/spacy/tokenizer.pxd +++ b/spacy/tokenizer.pxd @@ -4,7 +4,6 @@ from cymem.cymem cimport Pool from .typedefs cimport hash_t from .structs cimport LexemeC, SpanC, TokenC -from .strings cimport StringStore from .tokens.doc cimport Doc from .vocab cimport Vocab, LexemesOrTokens, _Cached from .matcher.phrasematcher cimport PhraseMatcher From a231bf65af99c8e71212f59fcd7df350dd01597c Mon Sep 17 00:00:00 2001 From: Madeesh Kannan Date: Mon, 9 Jan 2023 20:15:02 +0100 Subject: [PATCH 032/123] Pass `step=0` to `Schedule` class to yield initial learning rate (#12078) --- spacy/training/loop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spacy/training/loop.py b/spacy/training/loop.py index c93cba7a7..fc929816d 100644 --- a/spacy/training/loop.py +++ b/spacy/training/loop.py @@ -100,7 +100,7 @@ def train( stdout.write( msg.info(f"Set annotations on update for: {annotating_components}") + "\n" ) - stdout.write(msg.info(f"Initial learn rate: {optimizer.learn_rate}") + "\n") + stdout.write(msg.info(f"Initial learn rate: {optimizer.learn_rate(step=0)}") + "\n") with nlp.select_pipes(disable=frozen_components): log_step, finalize_logger = train_logger(nlp, stdout, stderr) try: From 6ff5eb256c858dc3f3f4688fb0b6f3e770b828f1 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 11 Jan 2023 18:57:50 +0100 Subject: [PATCH 033/123] update tests from master to follow v4 principles --- spacy/tests/pipeline/test_entity_ruler.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/spacy/tests/pipeline/test_entity_ruler.py b/spacy/tests/pipeline/test_entity_ruler.py index ac2f45276..1ac78e531 100644 --- a/spacy/tests/pipeline/test_entity_ruler.py +++ b/spacy/tests/pipeline/test_entity_ruler.py @@ -353,9 +353,9 @@ def test_entity_ruler_overlapping_spans(nlp): assert doc.ents[0].label_ == "FOOBAR" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_fuzzy_pipe(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +@pytest.mark.parametrize() +def test_entity_ruler_fuzzy_pipe(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [{"label": "HELLO", "pattern": [{"LOWER": {"FUZZY": "hello"}}]}] ruler.add_patterns(patterns) doc = nlp("helloo") @@ -363,9 +363,9 @@ def test_entity_ruler_fuzzy_pipe(nlp, entity_ruler_factory): assert doc.ents[0].label_ == "HELLO" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_fuzzy(nlp, entity_ruler_factory): - ruler = nlp.add_pipe(entity_ruler_factory, name="entity_ruler") +@pytest.mark.parametrize() +def test_entity_ruler_fuzzy(nlp): + ruler = nlp.add_pipe("entity_ruler") patterns = [{"label": "HELLO", "pattern": [{"LOWER": {"FUZZY": "hello"}}]}] ruler.add_patterns(patterns) doc = nlp("helloo") @@ -373,15 +373,14 @@ def test_entity_ruler_fuzzy(nlp, entity_ruler_factory): assert doc.ents[0].label_ == "HELLO" -@pytest.mark.parametrize("entity_ruler_factory", ENTITY_RULERS) -def test_entity_ruler_fuzzy_disabled(nlp, entity_ruler_factory): +@pytest.mark.parametrize() +def test_entity_ruler_fuzzy_disabled(nlp): @registry.misc("test_fuzzy_compare_disabled") def make_test_fuzzy_compare_disabled(): return lambda x, y, z: False ruler = nlp.add_pipe( - entity_ruler_factory, - name="entity_ruler", + "entity_ruler", config={"matcher_fuzzy_compare": {"@misc": "test_fuzzy_compare_disabled"}}, ) patterns = [{"label": "HELLO", "pattern": [{"LOWER": {"FUZZY": "hello"}}]}] From fc2723925bcbb47a27262d0a63e11295f00e9d3b Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 11 Jan 2023 19:04:06 +0100 Subject: [PATCH 034/123] update tests from master to follow v4 principles (2) --- spacy/tests/pipeline/test_entity_ruler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/spacy/tests/pipeline/test_entity_ruler.py b/spacy/tests/pipeline/test_entity_ruler.py index 1ac78e531..db502e13f 100644 --- a/spacy/tests/pipeline/test_entity_ruler.py +++ b/spacy/tests/pipeline/test_entity_ruler.py @@ -353,7 +353,6 @@ def test_entity_ruler_overlapping_spans(nlp): assert doc.ents[0].label_ == "FOOBAR" -@pytest.mark.parametrize() def test_entity_ruler_fuzzy_pipe(nlp): ruler = nlp.add_pipe("entity_ruler") patterns = [{"label": "HELLO", "pattern": [{"LOWER": {"FUZZY": "hello"}}]}] @@ -363,7 +362,6 @@ def test_entity_ruler_fuzzy_pipe(nlp): assert doc.ents[0].label_ == "HELLO" -@pytest.mark.parametrize() def test_entity_ruler_fuzzy(nlp): ruler = nlp.add_pipe("entity_ruler") patterns = [{"label": "HELLO", "pattern": [{"LOWER": {"FUZZY": "hello"}}]}] @@ -373,7 +371,6 @@ def test_entity_ruler_fuzzy(nlp): assert doc.ents[0].label_ == "HELLO" -@pytest.mark.parametrize() def test_entity_ruler_fuzzy_disabled(nlp): @registry.misc("test_fuzzy_compare_disabled") def make_test_fuzzy_compare_disabled(): From c2f3e699ca3a92966510d4370a37c02f57912da3 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Fri, 13 Jan 2023 11:14:58 +0100 Subject: [PATCH 035/123] fix anchors (#12095) --- website/docs/api/stringstore.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/api/stringstore.mdx b/website/docs/api/stringstore.mdx index 542ee1ab9..7e380f5f8 100644 --- a/website/docs/api/stringstore.mdx +++ b/website/docs/api/stringstore.mdx @@ -90,7 +90,7 @@ Iterate over the stored strings in insertion order. | ----------- | ------------------------------ | | **RETURNS** | A string in the store. ~~str~~ | -## StringStore.items {id="iter", tag="method", version="4"} +## StringStore.items {id="items", tag="method", version="4"} Iterate over the stored string-hash pairs in insertion order. @@ -106,7 +106,7 @@ Iterate over the stored string-hash pairs in insertion order. | ----------- | ------------------------------------------------------ | | **RETURNS** | A list of string-hash pairs. ~~List[Tuple[str, int]]~~ | -## StringStore.keys {id="iter", tag="method", version="4"} +## StringStore.keys {id="keys", tag="method", version="4"} Iterate over the stored strings in insertion order. @@ -122,7 +122,7 @@ Iterate over the stored strings in insertion order. | ----------- | -------------------------------- | | **RETURNS** | A list of strings. ~~List[str]~~ | -## StringStore.values {id="iter", tag="method", version="4"} +## StringStore.values {id="values", tag="method", version="4"} Iterate over the stored string hashes in insertion order. From 5e297aa20e351bd1672c03a6298f4ac8fcac748e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Mon, 16 Jan 2023 10:25:53 +0100 Subject: [PATCH 036/123] Add `TrainablePipe.{distill,get_teacher_student_loss}` (#12016) * Add `TrainablePipe.{distill,get_teacher_student_loss}` This change adds two methods: - `TrainablePipe::distill` which performs a training step of a student pipe on a teacher pipe, giving a batch of `Doc`s. - `TrainablePipe::get_teacher_student_loss` computes the loss of a student relative to the teacher. The `distill` or `get_teacher_student_loss` methods are also implemented in the tagger, edit tree lemmatizer, and parser pipes, to enable distillation in those pipes and as an example for other pipes. * Fix stray `Beam` import * Fix incorrect import * Apply suggestions from code review Co-authored-by: Sofie Van Landeghem * Apply suggestions from code review Co-authored-by: Sofie Van Landeghem * TrainablePipe.distill: use `Iterable[Example]` * Add Pipe.is_distillable method * Add `validate_distillation_examples` This first calls `validate_examples` and then checks that the student/teacher tokens are the same. * Update distill documentation * Add distill documentation for all pipes that support distillation * Fix incorrect identifier * Apply suggestions from code review Co-authored-by: Sofie Van Landeghem * Add comment to explain `is_distillable` Co-authored-by: Sofie Van Landeghem --- spacy/errors.py | 3 + spacy/ml/callbacks.py | 1 + spacy/pipeline/edit_tree_lemmatizer.py | 19 +++ spacy/pipeline/pipe.pyx | 4 + spacy/pipeline/tagger.pyx | 26 ++- spacy/pipeline/trainable_pipe.pyx | 70 +++++++- spacy/pipeline/transition_parser.pyx | 156 +++++++++++++++++- spacy/tests/parser/test_ner.py | 46 ++++++ spacy/tests/parser/test_parse.py | 49 ++++++ .../pipeline/test_edit_tree_lemmatizer.py | 47 ++++++ spacy/tests/pipeline/test_morphologizer.py | 6 + spacy/tests/pipeline/test_senter.py | 6 + spacy/tests/pipeline/test_tagger.py | 46 ++++++ spacy/tests/pipeline/test_textcat.py | 6 + spacy/tests/training/test_training.py | 15 +- spacy/training/__init__.py | 1 + spacy/training/example.pyx | 7 + website/docs/api/dependencyparser.mdx | 54 ++++++ website/docs/api/edittreelemmatizer.mdx | 54 ++++++ website/docs/api/entityrecognizer.mdx | 54 ++++++ website/docs/api/morphologizer.mdx | 54 ++++++ website/docs/api/pipe.mdx | 61 +++++++ website/docs/api/sentencerecognizer.mdx | 54 ++++++ website/docs/api/tagger.mdx | 54 ++++++ website/docs/api/top-level.mdx | 3 +- website/docs/usage/processing-pipelines.mdx | 14 +- 26 files changed, 897 insertions(+), 13 deletions(-) diff --git a/spacy/errors.py b/spacy/errors.py index ad90dcf8b..91e7a6006 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -955,6 +955,9 @@ class Errors(metaclass=ErrorsWithCodes): E4000 = ("Expected a Doc as input, but got: '{type}'") E4001 = ("Expected input to be one of the following types: ({expected_types}), " "but got '{received_type}'") + E4002 = ("Pipe '{name}' requires a teacher pipe for distillation.") + E4003 = ("Training examples for distillation must have the exact same tokens in the " + "reference and predicted docs.") # fmt: on diff --git a/spacy/ml/callbacks.py b/spacy/ml/callbacks.py index 3b60ec2ab..393f208a6 100644 --- a/spacy/ml/callbacks.py +++ b/spacy/ml/callbacks.py @@ -23,6 +23,7 @@ DEFAULT_NVTX_ANNOTATABLE_PIPE_METHODS = [ "update", "rehearse", "get_loss", + "get_teacher_student_loss", "initialize", "begin_update", "finish_update", diff --git a/spacy/pipeline/edit_tree_lemmatizer.py b/spacy/pipeline/edit_tree_lemmatizer.py index 2a2242aa4..20f83fffc 100644 --- a/spacy/pipeline/edit_tree_lemmatizer.py +++ b/spacy/pipeline/edit_tree_lemmatizer.py @@ -155,6 +155,25 @@ class EditTreeLemmatizer(TrainablePipe): return float(loss), d_scores + def get_teacher_student_loss( + self, teacher_scores: List[Floats2d], student_scores: List[Floats2d] + ) -> Tuple[float, List[Floats2d]]: + """Calculate the loss and its gradient for a batch of student + scores, relative to teacher scores. + + teacher_scores: Scores representing the teacher model's predictions. + student_scores: Scores representing the student model's predictions. + + RETURNS (Tuple[float, float]): The loss and the gradient. + + DOCS: https://spacy.io/api/edittreelemmatizer#get_teacher_student_loss + """ + loss_func = LegacySequenceCategoricalCrossentropy(normalize=False) + d_scores, loss = loss_func(student_scores, teacher_scores) + if self.model.ops.xp.isnan(loss): + raise ValueError(Errors.E910.format(name=self.name)) + return float(loss), d_scores + def predict(self, docs: Iterable[Doc]) -> ActivationsT: n_docs = len(list(docs)) if not any(len(doc) for doc in docs): diff --git a/spacy/pipeline/pipe.pyx b/spacy/pipeline/pipe.pyx index c5650382b..8b8fdc361 100644 --- a/spacy/pipeline/pipe.pyx +++ b/spacy/pipeline/pipe.pyx @@ -87,6 +87,10 @@ cdef class Pipe: return self.scorer(examples, **scorer_kwargs) return {} + @property + def is_distillable(self) -> bool: + return False + @property def is_trainable(self) -> bool: return False diff --git a/spacy/pipeline/tagger.pyx b/spacy/pipeline/tagger.pyx index e12f116af..a6be51c3c 100644 --- a/spacy/pipeline/tagger.pyx +++ b/spacy/pipeline/tagger.pyx @@ -1,5 +1,6 @@ # cython: infer_types=True, profile=True, binding=True from typing import Callable, Dict, Iterable, List, Optional, Union +from typing import Tuple import numpy import srsly from thinc.api import Model, set_dropout_rate, Config @@ -245,7 +246,6 @@ class Tagger(TrainablePipe): DOCS: https://spacy.io/api/tagger#rehearse """ - loss_func = LegacySequenceCategoricalCrossentropy() if losses is None: losses = {} losses.setdefault(self.name, 0.0) @@ -259,12 +259,32 @@ class Tagger(TrainablePipe): set_dropout_rate(self.model, drop) tag_scores, bp_tag_scores = self.model.begin_update(docs) tutor_tag_scores, _ = self._rehearsal_model.begin_update(docs) - grads, loss = loss_func(tag_scores, tutor_tag_scores) + loss, grads = self.get_teacher_student_loss(tutor_tag_scores, tag_scores) bp_tag_scores(grads) - self.finish_update(sgd) + if sgd is not None: + self.finish_update(sgd) losses[self.name] += loss return losses + def get_teacher_student_loss( + self, teacher_scores: List[Floats2d], student_scores: List[Floats2d] + ) -> Tuple[float, List[Floats2d]]: + """Calculate the loss and its gradient for a batch of student + scores, relative to teacher scores. + + teacher_scores: Scores representing the teacher model's predictions. + student_scores: Scores representing the student model's predictions. + + RETURNS (Tuple[float, float]): The loss and the gradient. + + DOCS: https://spacy.io/api/tagger#get_teacher_student_loss + """ + loss_func = LegacySequenceCategoricalCrossentropy(normalize=False) + d_scores, loss = loss_func(student_scores, teacher_scores) + if self.model.ops.xp.isnan(loss): + raise ValueError(Errors.E910.format(name=self.name)) + return float(loss), d_scores + def get_loss(self, examples, scores): """Find the loss and gradient of loss for the batch of documents and their predicted scores. diff --git a/spacy/pipeline/trainable_pipe.pyx b/spacy/pipeline/trainable_pipe.pyx index 5bba34e4a..77259fc0b 100644 --- a/spacy/pipeline/trainable_pipe.pyx +++ b/spacy/pipeline/trainable_pipe.pyx @@ -6,7 +6,7 @@ import warnings from ..tokens.doc cimport Doc -from ..training import validate_examples +from ..training import validate_examples, validate_distillation_examples from ..errors import Errors, Warnings from .pipe import Pipe, deserialize_config from .. import util @@ -56,6 +56,53 @@ cdef class TrainablePipe(Pipe): except Exception as e: error_handler(self.name, self, [doc], e) + + def distill(self, + teacher_pipe: Optional["TrainablePipe"], + examples: Iterable["Example"], + *, + drop: float=0.0, + sgd: Optional[Optimizer]=None, + losses: Optional[Dict[str, float]]=None) -> Dict[str, float]: + """Train a pipe (the student) on the predictions of another pipe + (the teacher). The student is typically trained on the probability + distribution of the teacher, but details may differ per pipe. + + teacher_pipe (Optional[TrainablePipe]): The teacher pipe to learn + from. + examples (Iterable[Example]): Distillation examples. The reference + and predicted docs must have the same number of tokens and the + same orthography. + drop (float): dropout rate. + sgd (Optional[Optimizer]): An optimizer. Will be created via + create_optimizer if not set. + losses (Optional[Dict[str, float]]): Optional record of loss during + distillation. + RETURNS: The updated losses dictionary. + + DOCS: https://spacy.io/api/pipe#distill + """ + # By default we require a teacher pipe, but there are downstream + # implementations that don't require a pipe. + if teacher_pipe is None: + raise ValueError(Errors.E4002.format(name=self.name)) + if losses is None: + losses = {} + losses.setdefault(self.name, 0.0) + validate_distillation_examples(examples, "TrainablePipe.distill") + set_dropout_rate(self.model, drop) + for node in teacher_pipe.model.walk(): + if node.name == "softmax": + node.attrs["softmax_normalize"] = True + teacher_scores = teacher_pipe.model.predict([eg.reference for eg in examples]) + student_scores, bp_student_scores = self.model.begin_update([eg.predicted for eg in examples]) + loss, d_scores = self.get_teacher_student_loss(teacher_scores, student_scores) + bp_student_scores(d_scores) + if sgd is not None: + self.finish_update(sgd) + losses[self.name] += loss + return losses + def pipe(self, stream: Iterable[Doc], *, batch_size: int=128) -> Iterator[Doc]: """Apply the pipe to a stream of documents. This usually happens under the hood when the nlp object is called on a text and all components are @@ -169,6 +216,19 @@ cdef class TrainablePipe(Pipe): """ raise NotImplementedError(Errors.E931.format(parent="TrainablePipe", method="get_loss", name=self.name)) + def get_teacher_student_loss(self, teacher_scores, student_scores): + """Calculate the loss and its gradient for a batch of student + scores, relative to teacher scores. + + teacher_scores: Scores representing the teacher model's predictions. + student_scores: Scores representing the student model's predictions. + + RETURNS (Tuple[float, float]): The loss and the gradient. + + DOCS: https://spacy.io/api/pipe#get_teacher_student_loss + """ + raise NotImplementedError(Errors.E931.format(parent="TrainablePipe", method="get_teacher_student_loss", name=self.name)) + def create_optimizer(self) -> Optimizer: """Create an optimizer for the pipeline component. @@ -205,6 +265,14 @@ cdef class TrainablePipe(Pipe): """ raise NotImplementedError(Errors.E931.format(parent="Pipe", method="add_label", name=self.name)) + @property + def is_distillable(self) -> bool: + # Normally a pipe overrides `get_teacher_student_loss` to implement + # distillation. In more exceptional cases, a pipe can provide its + # own `distill` implementation. If neither of these methods is + # overridden, the pipe does not implement distillation. + return not (self.__class__.distill is TrainablePipe.distill and self.__class__.get_teacher_student_loss is TrainablePipe.get_teacher_student_loss) + @property def is_trainable(self) -> bool: return True diff --git a/spacy/pipeline/transition_parser.pyx b/spacy/pipeline/transition_parser.pyx index 9d7b258c6..b0b3a0b96 100644 --- a/spacy/pipeline/transition_parser.pyx +++ b/spacy/pipeline/transition_parser.pyx @@ -1,5 +1,6 @@ # cython: infer_types=True, cdivision=True, boundscheck=False, binding=True from __future__ import print_function +from typing import Dict, Iterable, List, Optional, Tuple from cymem.cymem cimport Pool cimport numpy as np from itertools import islice @@ -9,7 +10,10 @@ from libc.stdlib cimport calloc, free import random import srsly -from thinc.api import get_ops, set_dropout_rate, CupyOps, NumpyOps +from thinc.api import get_ops, set_dropout_rate, CupyOps, NumpyOps, Optimizer +from thinc.api import chain, softmax_activation, use_ops +from thinc.legacy import LegacySequenceCategoricalCrossentropy +from thinc.types import Floats2d import numpy.random import numpy import warnings @@ -26,6 +30,7 @@ from ._parser_internals cimport _beam_utils from ._parser_internals import _beam_utils from ..training import validate_examples, validate_get_examples +from ..training import validate_distillation_examples from ..errors import Errors, Warnings from .. import util @@ -203,6 +208,121 @@ cdef class Parser(TrainablePipe): # Defined in subclasses, to avoid circular import raise NotImplementedError + def distill(self, + teacher_pipe: Optional[TrainablePipe], + examples: Iterable["Example"], + *, + drop: float=0.0, + sgd: Optional[Optimizer]=None, + losses: Optional[Dict[str, float]]=None): + """Train a pipe (the student) on the predictions of another pipe + (the teacher). The student is trained on the transition probabilities + of the teacher. + + teacher_pipe (Optional[TrainablePipe]): The teacher pipe to learn + from. + examples (Iterable[Example]): Distillation examples. The reference + and predicted docs must have the same number of tokens and the + same orthography. + drop (float): dropout rate. + sgd (Optional[Optimizer]): An optimizer. Will be created via + create_optimizer if not set. + losses (Optional[Dict[str, float]]): Optional record of loss during + distillation. + RETURNS: The updated losses dictionary. + + DOCS: https://spacy.io/api/dependencyparser#distill + """ + if teacher_pipe is None: + raise ValueError(Errors.E4002.format(name=self.name)) + if losses is None: + losses = {} + losses.setdefault(self.name, 0.0) + + validate_distillation_examples(examples, "TransitionParser.distill") + + set_dropout_rate(self.model, drop) + + student_docs = [eg.predicted for eg in examples] + + teacher_step_model = teacher_pipe.model.predict([eg.reference for eg in examples]) + student_step_model, backprop_tok2vec = self.model.begin_update(student_docs) + + # Add softmax activation, so that we can compute student losses + # with cross-entropy loss. + with use_ops("numpy"): + teacher_model = chain(teacher_step_model, softmax_activation()) + student_model = chain(student_step_model, softmax_activation()) + + max_moves = self.cfg["update_with_oracle_cut_size"] + if max_moves >= 1: + # Chop sequences into lengths of this many words, to make the + # batch uniform length. Since we do not have a gold standard + # sequence, we use the teacher's predictions as the gold + # standard. + max_moves = int(random.uniform(max_moves // 2, max_moves * 2)) + states = self._init_batch(teacher_step_model, student_docs, max_moves) + else: + states = self.moves.init_batch(student_docs) + + loss = 0.0 + n_moves = 0 + while states: + # We do distillation as follows: (1) for every state, we compute the + # transition softmax distributions: (2) we backpropagate the error of + # the student (compared to the teacher) into the student model; (3) + # for all states, we move to the next state using the student's + # predictions. + teacher_scores = teacher_model.predict(states) + student_scores, backprop = student_model.begin_update(states) + state_loss, d_scores = self.get_teacher_student_loss(teacher_scores, student_scores) + backprop(d_scores) + loss += state_loss + self.transition_states(states, student_scores) + states = [state for state in states if not state.is_final()] + + # Stop when we reach the maximum number of moves, otherwise we start + # to process the remainder of cut sequences again. + if max_moves >= 1 and n_moves >= max_moves: + break + n_moves += 1 + + backprop_tok2vec(student_docs) + + if sgd is not None: + self.finish_update(sgd) + + losses[self.name] += loss + + del backprop + del backprop_tok2vec + teacher_step_model.clear_memory() + student_step_model.clear_memory() + del teacher_model + del student_model + + return losses + + + def get_teacher_student_loss( + self, teacher_scores: List[Floats2d], student_scores: List[Floats2d] + ) -> Tuple[float, List[Floats2d]]: + """Calculate the loss and its gradient for a batch of student + scores, relative to teacher scores. + + teacher_scores: Scores representing the teacher model's predictions. + student_scores: Scores representing the student model's predictions. + + RETURNS (Tuple[float, float]): The loss and the gradient. + + DOCS: https://spacy.io/api/dependencyparser#get_teacher_student_loss + """ + loss_func = LegacySequenceCategoricalCrossentropy(normalize=False) + d_scores, loss = loss_func(student_scores, teacher_scores) + if self.model.ops.xp.isnan(loss): + raise ValueError(Errors.E910.format(name=self.name)) + return float(loss), d_scores + def init_multitask_objectives(self, get_examples, pipeline, **cfg): """Setup models for secondary objectives, to benefit from multi-task learning. This method is intended to be overridden by subclasses. @@ -625,6 +745,40 @@ cdef class Parser(TrainablePipe): raise ValueError(Errors.E149) from None return self + def _init_batch(self, teacher_step_model, docs, max_length): + """Make a square batch of length equal to the shortest transition + sequence or a cap. A long + doc will get multiple states. Let's say we have a doc of length 2*N, + where N is the shortest doc. We'll make two states, one representing + long_doc[:N], and another representing long_doc[N:]. In contrast to + _init_gold_batch, this version uses a teacher model to generate the + cut sequences.""" + cdef: + StateClass start_state + StateClass state + Transition action + all_states = self.moves.init_batch(docs) + states = [] + to_cut = [] + for state, doc in zip(all_states, docs): + if not state.is_final(): + if len(doc) < max_length: + states.append(state) + else: + to_cut.append(state) + while to_cut: + states.extend(state.copy() for state in to_cut) + # Move states forward max_length actions. + length = 0 + while to_cut and length < max_length: + teacher_scores = teacher_step_model.predict(to_cut) + self.transition_states(to_cut, teacher_scores) + # States that are completed do not need further cutting. + to_cut = [state for state in to_cut if not state.is_final()] + length += 1 + return states + + def _init_gold_batch(self, examples, max_length): """Make a square batch, of length equal to the shortest transition sequence or a cap. A long diff --git a/spacy/tests/parser/test_ner.py b/spacy/tests/parser/test_ner.py index 00889efdc..7ef3ed869 100644 --- a/spacy/tests/parser/test_ner.py +++ b/spacy/tests/parser/test_ner.py @@ -617,6 +617,52 @@ def test_overfitting_IO(use_upper): assert ents[1].kb_id == 0 +def test_is_distillable(): + nlp = English() + ner = nlp.add_pipe("ner") + assert ner.is_distillable + + +def test_distill(): + teacher = English() + teacher_ner = teacher.add_pipe("ner") + train_examples = [] + for text, annotations in TRAIN_DATA: + train_examples.append(Example.from_dict(teacher.make_doc(text), annotations)) + for ent in annotations.get("entities"): + teacher_ner.add_label(ent[2]) + + optimizer = teacher.initialize(get_examples=lambda: train_examples) + + for i in range(50): + losses = {} + teacher.update(train_examples, sgd=optimizer, losses=losses) + assert losses["ner"] < 0.00001 + + student = English() + student_ner = student.add_pipe("ner") + student_ner.initialize( + get_examples=lambda: train_examples, labels=teacher_ner.label_data + ) + + distill_examples = [ + Example.from_dict(teacher.make_doc(t[0]), {}) for t in TRAIN_DATA + ] + + for i in range(100): + losses = {} + student_ner.distill(teacher_ner, distill_examples, sgd=optimizer, losses=losses) + assert losses["ner"] < 0.0001 + + # test the trained model + test_text = "I like London." + doc = student(test_text) + ents = doc.ents + assert len(ents) == 1 + assert ents[0].text == "London" + assert ents[0].label_ == "LOC" + + def test_beam_ner_scores(): # Test that we can get confidence values out of the beam_ner pipe beam_width = 16 diff --git a/spacy/tests/parser/test_parse.py b/spacy/tests/parser/test_parse.py index aaf31ed56..97d112a50 100644 --- a/spacy/tests/parser/test_parse.py +++ b/spacy/tests/parser/test_parse.py @@ -396,6 +396,55 @@ def test_overfitting_IO(pipe_name): assert_equal(batch_deps_1, no_batch_deps) +def test_is_distillable(): + nlp = English() + parser = nlp.add_pipe("parser") + assert parser.is_distillable + + +def test_distill(): + teacher = English() + teacher_parser = teacher.add_pipe("parser") + train_examples = [] + for text, annotations in TRAIN_DATA: + train_examples.append(Example.from_dict(teacher.make_doc(text), annotations)) + for dep in annotations.get("deps", []): + teacher_parser.add_label(dep) + + optimizer = teacher.initialize(get_examples=lambda: train_examples) + + for i in range(200): + losses = {} + teacher.update(train_examples, sgd=optimizer, losses=losses) + assert losses["parser"] < 0.0001 + + student = English() + student_parser = student.add_pipe("parser") + student_parser.initialize( + get_examples=lambda: train_examples, labels=teacher_parser.label_data + ) + + distill_examples = [ + Example.from_dict(teacher.make_doc(t[0]), {}) for t in TRAIN_DATA + ] + + for i in range(200): + losses = {} + student_parser.distill( + teacher_parser, distill_examples, sgd=optimizer, losses=losses + ) + assert losses["parser"] < 0.0001 + + test_text = "I like securities." + doc = student(test_text) + assert doc[0].dep_ == "nsubj" + assert doc[2].dep_ == "dobj" + assert doc[3].dep_ == "punct" + assert doc[0].head.i == 1 + assert doc[2].head.i == 1 + assert doc[3].head.i == 1 + + # fmt: off @pytest.mark.slow @pytest.mark.parametrize("pipe_name", ["parser", "beam_parser"]) diff --git a/spacy/tests/pipeline/test_edit_tree_lemmatizer.py b/spacy/tests/pipeline/test_edit_tree_lemmatizer.py index 5eeb55aa2..b855c7a26 100644 --- a/spacy/tests/pipeline/test_edit_tree_lemmatizer.py +++ b/spacy/tests/pipeline/test_edit_tree_lemmatizer.py @@ -195,6 +195,53 @@ def test_overfitting_IO(): assert doc4[3].lemma_ == "egg" +def test_is_distillable(): + nlp = English() + lemmatizer = nlp.add_pipe("trainable_lemmatizer") + assert lemmatizer.is_distillable + + +def test_distill(): + teacher = English() + teacher_lemmatizer = teacher.add_pipe("trainable_lemmatizer") + teacher_lemmatizer.min_tree_freq = 1 + train_examples = [] + for t in TRAIN_DATA: + train_examples.append(Example.from_dict(teacher.make_doc(t[0]), t[1])) + + optimizer = teacher.initialize(get_examples=lambda: train_examples) + + for i in range(50): + losses = {} + teacher.update(train_examples, sgd=optimizer, losses=losses) + assert losses["trainable_lemmatizer"] < 0.00001 + + student = English() + student_lemmatizer = student.add_pipe("trainable_lemmatizer") + student_lemmatizer.min_tree_freq = 1 + student_lemmatizer.initialize( + get_examples=lambda: train_examples, labels=teacher_lemmatizer.label_data + ) + + distill_examples = [ + Example.from_dict(teacher.make_doc(t[0]), {}) for t in TRAIN_DATA + ] + + for i in range(50): + losses = {} + student_lemmatizer.distill( + teacher_lemmatizer, distill_examples, sgd=optimizer, losses=losses + ) + assert losses["trainable_lemmatizer"] < 0.00001 + + test_text = "She likes blue eggs" + doc = student(test_text) + assert doc[0].lemma_ == "she" + assert doc[1].lemma_ == "like" + assert doc[2].lemma_ == "blue" + assert doc[3].lemma_ == "egg" + + def test_lemmatizer_requires_labels(): nlp = English() nlp.add_pipe("trainable_lemmatizer") diff --git a/spacy/tests/pipeline/test_morphologizer.py b/spacy/tests/pipeline/test_morphologizer.py index 70fc77304..5b9b17c01 100644 --- a/spacy/tests/pipeline/test_morphologizer.py +++ b/spacy/tests/pipeline/test_morphologizer.py @@ -50,6 +50,12 @@ def test_implicit_label(): nlp.initialize(get_examples=lambda: train_examples) +def test_is_distillable(): + nlp = English() + morphologizer = nlp.add_pipe("morphologizer") + assert morphologizer.is_distillable + + def test_no_resize(): nlp = Language() morphologizer = nlp.add_pipe("morphologizer") diff --git a/spacy/tests/pipeline/test_senter.py b/spacy/tests/pipeline/test_senter.py index 3deac9e9a..a771d62fa 100644 --- a/spacy/tests/pipeline/test_senter.py +++ b/spacy/tests/pipeline/test_senter.py @@ -11,6 +11,12 @@ from spacy.pipeline import TrainablePipe from spacy.tests.util import make_tempdir +def test_is_distillable(): + nlp = English() + senter = nlp.add_pipe("senter") + assert senter.is_distillable + + def test_label_types(): nlp = Language() senter = nlp.add_pipe("senter") diff --git a/spacy/tests/pipeline/test_tagger.py b/spacy/tests/pipeline/test_tagger.py index a0c71198e..344859f8d 100644 --- a/spacy/tests/pipeline/test_tagger.py +++ b/spacy/tests/pipeline/test_tagger.py @@ -213,6 +213,52 @@ def test_overfitting_IO(): assert doc3[0].tag_ != "N" +def test_is_distillable(): + nlp = English() + tagger = nlp.add_pipe("tagger") + assert tagger.is_distillable + + +def test_distill(): + teacher = English() + teacher_tagger = teacher.add_pipe("tagger") + train_examples = [] + for t in TRAIN_DATA: + train_examples.append(Example.from_dict(teacher.make_doc(t[0]), t[1])) + + optimizer = teacher.initialize(get_examples=lambda: train_examples) + + for i in range(50): + losses = {} + teacher.update(train_examples, sgd=optimizer, losses=losses) + assert losses["tagger"] < 0.00001 + + student = English() + student_tagger = student.add_pipe("tagger") + student_tagger.min_tree_freq = 1 + student_tagger.initialize( + get_examples=lambda: train_examples, labels=teacher_tagger.label_data + ) + + distill_examples = [ + Example.from_dict(teacher.make_doc(t[0]), {}) for t in TRAIN_DATA + ] + + for i in range(50): + losses = {} + student_tagger.distill( + teacher_tagger, distill_examples, sgd=optimizer, losses=losses + ) + assert losses["tagger"] < 0.00001 + + test_text = "I like blue eggs" + doc = student(test_text) + assert doc[0].tag_ == "N" + assert doc[1].tag_ == "V" + assert doc[2].tag_ == "J" + assert doc[3].tag_ == "N" + + def test_save_activations(): # Test if activations are correctly added to Doc when requested. nlp = English() diff --git a/spacy/tests/pipeline/test_textcat.py b/spacy/tests/pipeline/test_textcat.py index 304209933..9c0eeb171 100644 --- a/spacy/tests/pipeline/test_textcat.py +++ b/spacy/tests/pipeline/test_textcat.py @@ -565,6 +565,12 @@ def test_initialize_examples(name, get_examples, train_data): nlp.initialize(get_examples=get_examples()) +def test_is_distillable(): + nlp = English() + textcat = nlp.add_pipe("textcat") + assert not textcat.is_distillable + + def test_overfitting_IO(): # Simple test to try and quickly overfit the single-label textcat component - ensuring the ML models work correctly fix_random_seed(0) diff --git a/spacy/tests/training/test_training.py b/spacy/tests/training/test_training.py index 7933ea31f..9fdd416b1 100644 --- a/spacy/tests/training/test_training.py +++ b/spacy/tests/training/test_training.py @@ -8,7 +8,7 @@ from spacy.lang.en import English from spacy.tokens import Doc, DocBin from spacy.training import Alignment, Corpus, Example, biluo_tags_to_offsets from spacy.training import biluo_tags_to_spans, docs_to_json, iob_to_biluo -from spacy.training import offsets_to_biluo_tags +from spacy.training import offsets_to_biluo_tags, validate_distillation_examples from spacy.training.alignment_array import AlignmentArray from spacy.training.align import get_alignments from spacy.training.converters import json_to_docs @@ -365,6 +365,19 @@ def test_example_from_dict_some_ner(en_vocab): assert ner_tags == ["U-LOC", None, None, None] +def test_validate_distillation_examples(en_vocab): + words = ["a", "b", "c", "d"] + spaces = [True, True, False, True] + predicted = Doc(en_vocab, words=words, spaces=spaces) + + example = Example.from_dict(predicted, {}) + validate_distillation_examples([example], "test_validate_distillation_examples") + + example = Example.from_dict(predicted, {"words": words + ["e"]}) + with pytest.raises(ValueError, match=r"distillation"): + validate_distillation_examples([example], "test_validate_distillation_examples") + + @pytest.mark.filterwarnings("ignore::UserWarning") def test_json_to_docs_no_ner(en_vocab): data = [ diff --git a/spacy/training/__init__.py b/spacy/training/__init__.py index 71d1fa775..454437104 100644 --- a/spacy/training/__init__.py +++ b/spacy/training/__init__.py @@ -1,5 +1,6 @@ from .corpus import Corpus, JsonlCorpus # noqa: F401 from .example import Example, validate_examples, validate_get_examples # noqa: F401 +from .example import validate_distillation_examples # noqa: F401 from .alignment import Alignment # noqa: F401 from .augment import dont_augment, orth_variants_augmenter # noqa: F401 from .iob_utils import iob_to_biluo, biluo_to_iob # noqa: F401 diff --git a/spacy/training/example.pyx b/spacy/training/example.pyx index 95b0f0de9..d6f3a07fb 100644 --- a/spacy/training/example.pyx +++ b/spacy/training/example.pyx @@ -47,6 +47,13 @@ def validate_examples(examples, method): raise TypeError(err) +def validate_distillation_examples(examples, method): + validate_examples(examples, method) + for eg in examples: + if [token.text for token in eg.reference] != [token.text for token in eg.predicted]: + raise ValueError(Errors.E4003) + + def validate_get_examples(get_examples, method): """Check that a generator of a batch of examples received during processing is valid: the callable produces a non-empty list of Example objects. diff --git a/website/docs/api/dependencyparser.mdx b/website/docs/api/dependencyparser.mdx index 771a00aee..5179ce48b 100644 --- a/website/docs/api/dependencyparser.mdx +++ b/website/docs/api/dependencyparser.mdx @@ -131,6 +131,39 @@ and all pipeline components are applied to the `Doc` in order. Both | `doc` | The document to process. ~~Doc~~ | | **RETURNS** | The processed document. ~~Doc~~ | +## DependencyParser.distill {id="distill", tag="method,experimental", version="4"} + +Train a pipe (the student) on the predictions of another pipe (the teacher). The +student is typically trained on the probability distribution of the teacher, but +details may differ per pipe. The goal of distillation is to transfer knowledge +from the teacher to the student. + +The distillation is performed on ~~Example~~ objects. The `Example.reference` +and `Example.predicted` ~~Doc~~s must have the same number of tokens and the +same orthography. Even though the reference does not need have to have gold +annotations, the teacher could adds its own annotations when necessary. + +This feature is experimental. + +> #### Example +> +> ```python +> teacher_pipe = teacher.add_pipe("parser") +> student_pipe = student.add_pipe("parser") +> optimizer = nlp.resume_training() +> losses = student.distill(teacher_pipe, examples, sgd=optimizer) +> ``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `teacher_pipe` | The teacher pipe to learn from. ~~Optional[TrainablePipe]~~ | +| `examples` | Distillation examples. The reference and predicted docs must have the same number of tokens and the same orthography. ~~Iterable[Example]~~ | +| _keyword-only_ | | +| `drop` | Dropout rate. ~~float~~ | +| `sgd` | An optimizer. Will be created via [`create_optimizer`](#create_optimizer) if not set. ~~Optional[Optimizer]~~ | +| `losses` | Optional record of the loss during distillation. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | +| **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | + ## DependencyParser.pipe {id="pipe",tag="method"} Apply the pipe to a stream of documents. This usually happens under the hood @@ -268,6 +301,27 @@ predicted scores. | `scores` | Scores representing the model's predictions. ~~StateClass~~ | | **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | +## DependencyParser.get_teacher_student_loss {id="get_teacher_student_loss", tag="method", version="4"} + +Calculate the loss and its gradient for the batch of student scores relative to +the teacher scores. + +> #### Example +> +> ```python +> teacher_parser = teacher.get_pipe("parser") +> student_parser = student.add_pipe("parser") +> student_scores = student_parser.predict([eg.predicted for eg in examples]) +> teacher_scores = teacher_parser.predict([eg.predicted for eg in examples]) +> loss, d_loss = student_parser.get_teacher_student_loss(teacher_scores, student_scores) +> ``` + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `teacher_scores` | Scores representing the teacher model's predictions. | +| `student_scores` | Scores representing the student model's predictions. | +| **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | + ## DependencyParser.create_optimizer {id="create_optimizer",tag="method"} Create an [`Optimizer`](https://thinc.ai/docs/api-optimizers) for the pipeline diff --git a/website/docs/api/edittreelemmatizer.mdx b/website/docs/api/edittreelemmatizer.mdx index 17af19e8c..2e0993657 100644 --- a/website/docs/api/edittreelemmatizer.mdx +++ b/website/docs/api/edittreelemmatizer.mdx @@ -115,6 +115,39 @@ and all pipeline components are applied to the `Doc` in order. Both | `doc` | The document to process. ~~Doc~~ | | **RETURNS** | The processed document. ~~Doc~~ | +## EditTreeLemmatizer.distill {id="distill", tag="method,experimental", version="4"} + +Train a pipe (the student) on the predictions of another pipe (the teacher). The +student is typically trained on the probability distribution of the teacher, but +details may differ per pipe. The goal of distillation is to transfer knowledge +from the teacher to the student. + +The distillation is performed on ~~Example~~ objects. The `Example.reference` +and `Example.predicted` ~~Doc~~s must have the same number of tokens and the +same orthography. Even though the reference does not need have to have gold +annotations, the teacher could adds its own annotations when necessary. + +This feature is experimental. + +> #### Example +> +> ```python +> teacher_pipe = teacher.add_pipe("trainable_lemmatizer") +> student_pipe = student.add_pipe("trainable_lemmatizer") +> optimizer = nlp.resume_training() +> losses = student.distill(teacher_pipe, examples, sgd=optimizer) +> ``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `teacher_pipe` | The teacher pipe to learn from. ~~Optional[TrainablePipe]~~ | +| `examples` | Distillation examples. The reference and predicted docs must have the same number of tokens and the same orthography. ~~Iterable[Example]~~ | +| _keyword-only_ | | +| `drop` | Dropout rate. ~~float~~ | +| `sgd` | An optimizer. Will be created via [`create_optimizer`](#create_optimizer) if not set. ~~Optional[Optimizer]~~ | +| `losses` | Optional record of the loss during distillation. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | +| **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | + ## EditTreeLemmatizer.pipe {id="pipe",tag="method"} Apply the pipe to a stream of documents. This usually happens under the hood @@ -269,6 +302,27 @@ Create an optimizer for the pipeline component. | ----------- | ---------------------------- | | **RETURNS** | The optimizer. ~~Optimizer~~ | +## EditTreeLemmatizer.get_teacher_student_loss {id="get_teacher_student_loss", tag="method", version="4"} + +Calculate the loss and its gradient for the batch of student scores relative to +the teacher scores. + +> #### Example +> +> ```python +> teacher_lemmatizer = teacher.get_pipe("trainable_lemmatizer") +> student_lemmatizer = student.add_pipe("trainable_lemmatizer") +> student_scores = student_lemmatizer.predict([eg.predicted for eg in examples]) +> teacher_scores = teacher_lemmatizer.predict([eg.predicted for eg in examples]) +> loss, d_loss = student_lemmatizer.get_teacher_student_loss(teacher_scores, student_scores) +> ``` + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `teacher_scores` | Scores representing the teacher model's predictions. | +| `student_scores` | Scores representing the student model's predictions. | +| **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | + ## EditTreeLemmatizer.use_params {id="use_params",tag="method, contextmanager"} Modify the pipe's model, to use the given parameter values. At the end of the diff --git a/website/docs/api/entityrecognizer.mdx b/website/docs/api/entityrecognizer.mdx index 1f386bbb6..005d5d11d 100644 --- a/website/docs/api/entityrecognizer.mdx +++ b/website/docs/api/entityrecognizer.mdx @@ -127,6 +127,39 @@ and all pipeline components are applied to the `Doc` in order. Both | `doc` | The document to process. ~~Doc~~ | | **RETURNS** | The processed document. ~~Doc~~ | +## EntityRecognizer.distill {id="distill", tag="method,experimental", version="4"} + +Train a pipe (the student) on the predictions of another pipe (the teacher). The +student is typically trained on the probability distribution of the teacher, but +details may differ per pipe. The goal of distillation is to transfer knowledge +from the teacher to the student. + +The distillation is performed on ~~Example~~ objects. The `Example.reference` +and `Example.predicted` ~~Doc~~s must have the same number of tokens and the +same orthography. Even though the reference does not need have to have gold +annotations, the teacher could adds its own annotations when necessary. + +This feature is experimental. + +> #### Example +> +> ```python +> teacher_pipe = teacher.add_pipe("ner") +> student_pipe = student.add_pipe("ner") +> optimizer = nlp.resume_training() +> losses = student.distill(teacher_pipe, examples, sgd=optimizer) +> ``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `teacher_pipe` | The teacher pipe to learn from. ~~Optional[TrainablePipe]~~ | +| `examples` | Distillation examples. The reference and predicted docs must have the same number of tokens and the same orthography. ~~Iterable[Example]~~ | +| _keyword-only_ | | +| `drop` | Dropout rate. ~~float~~ | +| `sgd` | An optimizer. Will be created via [`create_optimizer`](#create_optimizer) if not set. ~~Optional[Optimizer]~~ | +| `losses` | Optional record of the loss during distillation. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | +| **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | + ## EntityRecognizer.pipe {id="pipe",tag="method"} Apply the pipe to a stream of documents. This usually happens under the hood @@ -264,6 +297,27 @@ predicted scores. | `scores` | Scores representing the model's predictions. ~~StateClass~~ | | **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | +## EntityRecognizer.get_teacher_student_loss {id="get_teacher_student_loss", tag="method", version="4"} + +Calculate the loss and its gradient for the batch of student scores relative to +the teacher scores. + +> #### Example +> +> ```python +> teacher_ner = teacher.get_pipe("ner") +> student_ner = student.add_pipe("ner") +> student_scores = student_ner.predict([eg.predicted for eg in examples]) +> teacher_scores = teacher_ner.predict([eg.predicted for eg in examples]) +> loss, d_loss = student_ner.get_teacher_student_loss(teacher_scores, student_scores) +> ``` + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `teacher_scores` | Scores representing the teacher model's predictions. | +| `student_scores` | Scores representing the student model's predictions. | +| **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | + ## EntityRecognizer.create_optimizer {id="create_optimizer",tag="method"} Create an optimizer for the pipeline component. diff --git a/website/docs/api/morphologizer.mdx b/website/docs/api/morphologizer.mdx index 1fda807cb..4f79458d3 100644 --- a/website/docs/api/morphologizer.mdx +++ b/website/docs/api/morphologizer.mdx @@ -121,6 +121,39 @@ delegate to the [`predict`](/api/morphologizer#predict) and | `doc` | The document to process. ~~Doc~~ | | **RETURNS** | The processed document. ~~Doc~~ | +## Morphologizer.distill {id="distill", tag="method,experimental", version="4"} + +Train a pipe (the student) on the predictions of another pipe (the teacher). The +student is typically trained on the probability distribution of the teacher, but +details may differ per pipe. The goal of distillation is to transfer knowledge +from the teacher to the student. + +The distillation is performed on ~~Example~~ objects. The `Example.reference` +and `Example.predicted` ~~Doc~~s must have the same number of tokens and the +same orthography. Even though the reference does not need have to have gold +annotations, the teacher could adds its own annotations when necessary. + +This feature is experimental. + +> #### Example +> +> ```python +> teacher_pipe = teacher.add_pipe("morphologizer") +> student_pipe = student.add_pipe("morphologizer") +> optimizer = nlp.resume_training() +> losses = student.distill(teacher_pipe, examples, sgd=optimizer) +> ``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `teacher_pipe` | The teacher pipe to learn from. ~~Optional[TrainablePipe]~~ | +| `examples` | Distillation examples. The reference and predicted docs must have the same number of tokens and the same orthography. ~~Iterable[Example]~~ | +| _keyword-only_ | | +| `drop` | Dropout rate. ~~float~~ | +| `sgd` | An optimizer. Will be created via [`create_optimizer`](#create_optimizer) if not set. ~~Optional[Optimizer]~~ | +| `losses` | Optional record of the loss during distillation. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | +| **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | + ## Morphologizer.pipe {id="pipe",tag="method"} Apply the pipe to a stream of documents. This usually happens under the hood @@ -259,6 +292,27 @@ predicted scores. | `scores` | Scores representing the model's predictions. | | **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | +## Morphologizer.get_teacher_student_loss {id="get_teacher_student_loss", tag="method", version="4"} + +Calculate the loss and its gradient for the batch of student scores relative to +the teacher scores. + +> #### Example +> +> ```python +> teacher_morphologizer = teacher.get_pipe("morphologizer") +> student_morphologizer = student.add_pipe("morphologizer") +> student_scores = student_morphologizer.predict([eg.predicted for eg in examples]) +> teacher_scores = teacher_morphologizer.predict([eg.predicted for eg in examples]) +> loss, d_loss = student_morphologizer.get_teacher_student_loss(teacher_scores, student_scores) +> ``` + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `teacher_scores` | Scores representing the teacher model's predictions. | +| `student_scores` | Scores representing the student model's predictions. | +| **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | + ## Morphologizer.create_optimizer {id="create_optimizer",tag="method"} Create an optimizer for the pipeline component. diff --git a/website/docs/api/pipe.mdx b/website/docs/api/pipe.mdx index b387ea586..120c8f690 100644 --- a/website/docs/api/pipe.mdx +++ b/website/docs/api/pipe.mdx @@ -234,6 +234,39 @@ predictions and gold-standard annotations, and update the component's model. | `losses` | Optional record of the loss during training. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | | **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | +## TrainablePipe.distill {id="distill", tag="method,experimental", version="4"} + +Train a pipe (the student) on the predictions of another pipe (the teacher). The +student is typically trained on the probability distribution of the teacher, but +details may differ per pipe. The goal of distillation is to transfer knowledge +from the teacher to the student. + +The distillation is performed on ~~Example~~ objects. The `Example.reference` +and `Example.predicted` ~~Doc~~s must have the same number of tokens and the +same orthography. Even though the reference does not need have to have gold +annotations, the teacher could adds its own annotations when necessary. + +This feature is experimental. + +> #### Example +> +> ```python +> teacher_pipe = teacher.add_pipe("your_custom_pipe") +> student_pipe = student.add_pipe("your_custom_pipe") +> optimizer = nlp.resume_training() +> losses = student.distill(teacher_pipe, examples, sgd=optimizer) +> ``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `teacher_pipe` | The teacher pipe to learn from. ~~Optional[TrainablePipe]~~ | +| `examples` | Distillation examples. The reference and predicted docs must have the same number of tokens and the same orthography. ~~Iterable[Example]~~ | +| _keyword-only_ | | +| `drop` | Dropout rate. ~~float~~ | +| `sgd` | An optimizer. Will be created via [`create_optimizer`](#create_optimizer) if not set. ~~Optional[Optimizer]~~ | +| `losses` | Optional record of the loss during distillation. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | +| **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | + ## TrainablePipe.rehearse {id="rehearse",tag="method,experimental",version="3"} Perform a "rehearsal" update from a batch of data. Rehearsal updates teach the @@ -281,6 +314,34 @@ This method needs to be overwritten with your own custom `get_loss` method. | `scores` | Scores representing the model's predictions. | | **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | +## TrainablePipe.get_teacher_student_loss {id="get_teacher_student_loss", tag="method", version="4"} + +Calculate the loss and its gradient for the batch of student scores relative to +the teacher scores. + + + +This method needs to be overwritten with your own custom +`get_teacher_student_loss` method. + + + +> #### Example +> +> ```python +> teacher_pipe = teacher.get_pipe("your_custom_pipe") +> student_pipe = student.add_pipe("your_custom_pipe") +> student_scores = student_pipe.predict([eg.predicted for eg in examples]) +> teacher_scores = teacher_pipe.predict([eg.predicted for eg in examples]) +> loss, d_loss = student_pipe.get_teacher_student_loss(teacher_scores, student_scores) +> ``` + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `teacher_scores` | Scores representing the teacher model's predictions. | +| `student_scores` | Scores representing the student model's predictions. | +| **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | + ## TrainablePipe.score {id="score",tag="method",version="3"} Score a batch of examples. diff --git a/website/docs/api/sentencerecognizer.mdx b/website/docs/api/sentencerecognizer.mdx index d5d096d76..02fd57102 100644 --- a/website/docs/api/sentencerecognizer.mdx +++ b/website/docs/api/sentencerecognizer.mdx @@ -106,6 +106,39 @@ and all pipeline components are applied to the `Doc` in order. Both | `doc` | The document to process. ~~Doc~~ | | **RETURNS** | The processed document. ~~Doc~~ | +## SentenceRecognizer.distill {id="distill", tag="method,experimental", version="4"} + +Train a pipe (the student) on the predictions of another pipe (the teacher). The +student is typically trained on the probability distribution of the teacher, but +details may differ per pipe. The goal of distillation is to transfer knowledge +from the teacher to the student. + +The distillation is performed on ~~Example~~ objects. The `Example.reference` +and `Example.predicted` ~~Doc~~s must have the same number of tokens and the +same orthography. Even though the reference does not need have to have gold +annotations, the teacher could adds its own annotations when necessary. + +This feature is experimental. + +> #### Example +> +> ```python +> teacher_pipe = teacher.add_pipe("senter") +> student_pipe = student.add_pipe("senter") +> optimizer = nlp.resume_training() +> losses = student.distill(teacher_pipe, examples, sgd=optimizer) +> ``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `teacher_pipe` | The teacher pipe to learn from. ~~Optional[TrainablePipe]~~ | +| `examples` | Distillation examples. The reference and predicted docs must have the same number of tokens and the same orthography. ~~Iterable[Example]~~ | +| _keyword-only_ | | +| `drop` | Dropout rate. ~~float~~ | +| `sgd` | An optimizer. Will be created via [`create_optimizer`](#create_optimizer) if not set. ~~Optional[Optimizer]~~ | +| `losses` | Optional record of the loss during distillation. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | +| **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | + ## SentenceRecognizer.pipe {id="pipe",tag="method"} Apply the pipe to a stream of documents. This usually happens under the hood @@ -254,6 +287,27 @@ predicted scores. | `scores` | Scores representing the model's predictions. | | **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | +## SentenceRecognizer.get_teacher_student_loss {id="get_teacher_student_loss", tag="method", version="4"} + +Calculate the loss and its gradient for the batch of student scores relative to +the teacher scores. + +> #### Example +> +> ```python +> teacher_senter = teacher.get_pipe("senter") +> student_senter = student.add_pipe("senter") +> student_scores = student_senter.predict([eg.predicted for eg in examples]) +> teacher_scores = teacher_senter.predict([eg.predicted for eg in examples]) +> loss, d_loss = student_senter.get_teacher_student_loss(teacher_scores, student_scores) +> ``` + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `teacher_scores` | Scores representing the teacher model's predictions. | +| `student_scores` | Scores representing the student model's predictions. | +| **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | + ## SentenceRecognizer.create_optimizer {id="create_optimizer",tag="method"} Create an optimizer for the pipeline component. diff --git a/website/docs/api/tagger.mdx b/website/docs/api/tagger.mdx index ae14df212..664fd7940 100644 --- a/website/docs/api/tagger.mdx +++ b/website/docs/api/tagger.mdx @@ -105,6 +105,39 @@ and all pipeline components are applied to the `Doc` in order. Both | `doc` | The document to process. ~~Doc~~ | | **RETURNS** | The processed document. ~~Doc~~ | +## Tagger.distill {id="distill", tag="method,experimental", version="4"} + +Train a pipe (the student) on the predictions of another pipe (the teacher). The +student is typically trained on the probability distribution of the teacher, but +details may differ per pipe. The goal of distillation is to transfer knowledge +from the teacher to the student. + +The distillation is performed on ~~Example~~ objects. The `Example.reference` +and `Example.predicted` ~~Doc~~s must have the same number of tokens and the +same orthography. Even though the reference does not need have to have gold +annotations, the teacher could adds its own annotations when necessary. + +This feature is experimental. + +> #### Example +> +> ```python +> teacher_pipe = teacher.add_pipe("tagger") +> student_pipe = student.add_pipe("tagger") +> optimizer = nlp.resume_training() +> losses = student.distill(teacher_pipe, examples, sgd=optimizer) +> ``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `teacher_pipe` | The teacher pipe to learn from. ~~Optional[TrainablePipe]~~ | +| `examples` | Distillation examples. The reference and predicted docs must have the same number of tokens and the same orthography. ~~Iterable[Example]~~ | +| _keyword-only_ | | +| `drop` | Dropout rate. ~~float~~ | +| `sgd` | An optimizer. Will be created via [`create_optimizer`](#create_optimizer) if not set. ~~Optional[Optimizer]~~ | +| `losses` | Optional record of the loss during distillation. Updated using the component name as the key. ~~Optional[Dict[str, float]]~~ | +| **RETURNS** | The updated `losses` dictionary. ~~Dict[str, float]~~ | + ## Tagger.pipe {id="pipe",tag="method"} Apply the pipe to a stream of documents. This usually happens under the hood @@ -265,6 +298,27 @@ predicted scores. | `scores` | Scores representing the model's predictions. | | **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | +## Tagger.get_teacher_student_loss {id="get_teacher_student_loss", tag="method", version="4"} + +Calculate the loss and its gradient for the batch of student scores relative to +the teacher scores. + +> #### Example +> +> ```python +> teacher_tagger = teacher.get_pipe("tagger") +> student_tagger = student.add_pipe("tagger") +> student_scores = student_tagger.predict([eg.predicted for eg in examples]) +> teacher_scores = teacher_tagger.predict([eg.predicted for eg in examples]) +> loss, d_loss = student_tagger.get_teacher_student_loss(teacher_scores, student_scores) +> ``` + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `teacher_scores` | Scores representing the teacher model's predictions. | +| `student_scores` | Scores representing the student model's predictions. | +| **RETURNS** | The loss and the gradient, i.e. `(loss, gradient)`. ~~Tuple[float, float]~~ | + ## Tagger.create_optimizer {id="create_optimizer",tag="method"} Create an optimizer for the pipeline component. diff --git a/website/docs/api/top-level.mdx b/website/docs/api/top-level.mdx index a222cfa8f..7e47d324a 100644 --- a/website/docs/api/top-level.mdx +++ b/website/docs/api/top-level.mdx @@ -921,7 +921,8 @@ backprop passes. Recursively wrap both the models and methods of each pipe using [NVTX](https://nvidia.github.io/NVTX/) range markers. By default, the following methods are wrapped: `pipe`, `predict`, `set_annotations`, `update`, `rehearse`, -`get_loss`, `initialize`, `begin_update`, `finish_update`, `update`. +`get_loss`, `get_teacher_student_loss`, `initialize`, `begin_update`, +`finish_update`, `update`. | Name | Description | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/website/docs/usage/processing-pipelines.mdx b/website/docs/usage/processing-pipelines.mdx index 11e1cb620..08cd64aa7 100644 --- a/website/docs/usage/processing-pipelines.mdx +++ b/website/docs/usage/processing-pipelines.mdx @@ -1354,12 +1354,14 @@ For some use cases, it makes sense to also overwrite additional methods to customize how the model is updated from examples, how it's initialized, how the loss is calculated and to add evaluation scores to the training output. -| Name | Description | -| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`update`](/api/pipe#update) | Learn from a batch of [`Example`](/api/example) objects containing the predictions and gold-standard annotations, and update the component's model. | -| [`initialize`](/api/pipe#initialize) | Initialize the model. Typically calls into [`Model.initialize`](https://thinc.ai/docs/api-model#initialize) and can be passed custom arguments via the [`[initialize]`](/api/data-formats#config-initialize) config block that are only loaded during training or when you call [`nlp.initialize`](/api/language#initialize), not at runtime. | -| [`get_loss`](/api/pipe#get_loss) | Return a tuple of the loss and the gradient for a batch of [`Example`](/api/example) objects. | -| [`score`](/api/pipe#score) | Score a batch of [`Example`](/api/example) objects and return a dictionary of scores. The [`@Language.factory`](/api/language#factory) decorator can define the `default_score_weights` of the component to decide which keys of the scores to display during training and how they count towards the final score. | +| Name | Description | +| ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`update`](/api/pipe#update) | Learn from a batch of [`Example`](/api/example) objects containing the predictions and gold-standard annotations, and update the component's model. | +| [`distill`](/api/pipe#distill) | Learn from a teacher pipeline using a batch of [`Doc`](/api/doc) objects and update the component's model. | +| [`initialize`](/api/pipe#initialize) | Initialize the model. Typically calls into [`Model.initialize`](https://thinc.ai/docs/api-model#initialize) and can be passed custom arguments via the [`[initialize]`](/api/data-formats#config-initialize) config block that are only loaded during training or when you call [`nlp.initialize`](/api/language#initialize), not at runtime. | +| [`get_loss`](/api/pipe#get_loss) | Return a tuple of the loss and the gradient for a batch of [`Example`](/api/example) objects. | +| [`get_teacher_student_loss`](/api/pipe#get_teacher_student_loss) | Return a tuple of the loss and the gradient for the student scores relative to the teacher scores. | +| [`score`](/api/pipe#score) | Score a batch of [`Example`](/api/example) objects and return a dictionary of scores. The [`@Language.factory`](/api/language#factory) decorator can define the `default_score_weights` of the component to decide which keys of the scores to display during training and how they count towards the final score. | From a183db3cefe0713e828868b43daf61c464cae05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Wed, 18 Jan 2023 11:27:45 +0100 Subject: [PATCH 037/123] Merge the parser refactor into `v4` (#10940) * Try to fix doc.copy * Set dev version * Make vocab always own lexemes * Change version * Add SpanGroups.copy method * Fix set_annotations during Parser.update * Fix dict proxy copy * Upd version * Fix copying SpanGroups * Fix set_annotations in parser.update * Fix parser set_annotations during update * Revert "Fix parser set_annotations during update" This reverts commit eb138c89edb306608826dca50619ea8a60de2b14. * Revert "Fix set_annotations in parser.update" This reverts commit c6df0eafd0046179c1c9fb7840074edf04e4721d. * Fix set_annotations during parser update * Inc version * Handle final states in get_oracle_sequence * Inc version * Try to fix parser training * Inc version * Fix * Inc version * Fix parser oracle * Inc version * Inc version * Fix transition has_gold * Inc version * Try to use real histories, not oracle * Inc version * Upd parser * Inc version * WIP on rewrite parser * WIP refactor parser * New progress on parser model refactor * Prepare to remove parser_model.pyx * Convert parser from cdef class * Delete spacy.ml.parser_model * Delete _precomputable_affine module * Wire up tb_framework to new parser model * Wire up parser model * Uncython ner.pyx and dep_parser.pyx * Uncython * Work on parser model * Support unseen_classes in parser model * Support unseen classes in parser * Cleaner handling of unseen classes * Work through tests * Keep working through errors * Keep working through errors * Work on parser. 15 tests failing * Xfail beam stuff. 9 failures * More xfail. 7 failures * Xfail. 6 failures * cleanup * formatting * fixes * pass nO through * Fix empty doc in update * Hackishly fix resizing. 3 failures * Fix redundant test. 2 failures * Add reference version * black formatting * Get tests passing with reference implementation * Fix missing prints * Add missing file * Improve indexing on reference implementation * Get non-reference forward func working * Start rigging beam back up * removing redundant tests, cf #8106 * black formatting * temporarily xfailing issue 4314 * make flake8 happy again * mypy fixes * ensure labels are added upon predict * cleanup remnants from merge conflicts * Improve unseen label masking Two changes to speed up masking by ~10%: - Use a bool array rather than an array of float32. - Let the mask indicate whether a label was seen, rather than unseen. The mask is most frequently used to index scores for seen labels. However, since the mask marked unseen labels, this required computing an intermittent flipped mask. * Write moves costs directly into numpy array (#10163) This avoids elementwise indexing and the allocation of an additional array. Gives a ~15% speed improvement when using batch_by_sequence with size 32. * Temporarily disable ner and rehearse tests Until rehearse is implemented again in the refactored parser. * Fix loss serialization issue (#10600) * Fix loss serialization issue Serialization of a model fails with: TypeError: array(738.3855, dtype=float32) is not JSON serializable Fix this using float conversion. * Disable CI steps that require spacy.TransitionBasedParser.v2 After finishing the refactor, TransitionBasedParser.v2 should be provided for backwards compat. * Add back support for beam parsing to the refactored parser (#10633) * Add back support for beam parsing Beam parsing was already implemented as part of the `BeamBatch` class. This change makes its counterpart `GreedyBatch`. Both classes are hooked up in `TransitionModel`, selecting `GreedyBatch` when the beam size is one, or `BeamBatch` otherwise. * Use kwarg for beam width Co-authored-by: Sofie Van Landeghem * Avoid implicit default for beam_width and beam_density * Parser.{beam,greedy}_parse: ensure labels are added * Remove 'deprecated' comments Co-authored-by: Sofie Van Landeghem Co-authored-by: Sofie Van Landeghem * Parser `StateC` optimizations (#10746) * `StateC`: Optimizations Avoid GIL acquisition in `__init__` Increase default buffer capacities on init Reduce C++ exception overhead * Fix typo * Replace `set::count` with `set::find` * Add exception attribute to c'tor * Remove unused import * Use a power-of-two value for initial capacity Use default-insert to init `_heads` and `_unshiftable` * Merge `cdef` variable declarations and assignments * Vectorize `example.get_aligned_parses` (#10789) * `example`: Vectorize `get_aligned_parse` Rename `numpy` import * Convert aligned array to lists before returning * Revert import renaming * Elide slice arguments when selecting the entire range * Tagger/morphologizer alignment performance optimizations (#10798) * `example`: Unwrap `numpy` scalar arrays before passing them to `StringStore.__getitem__` * `AlignmentArray`: Use native list as staging buffer for offset calculation * `example`: Vectorize `get_aligned` * Hoist inner functions out of `get_aligned` * Replace inline `if..else` clause in assignment statement * `AlignmentArray`: Use raw indexing into offset and data `numpy` arrays * `example`: Replace array unique value check with `groupby` * `example`: Correctly exclude tokens with no alignment in `_get_aligned_vectorized` Simplify `_get_aligned_non_vectorized` * `util`: Update `all_equal` docstring * Explicitly use `int32_t*` * Restore C CPU inference in the refactored parser (#10747) * Bring back the C parsing model The C parsing model is used for CPU inference and is still faster for CPU inference than the forward pass of the Thinc model. * Use C sgemm provided by the Ops implementation * Make tb_framework module Cython, merge in C forward implementation * TransitionModel: raise in backprop returned from forward_cpu * Re-enable greedy parse test * Return transition scores when forward_cpu is used * Apply suggestions from code review Import `Model` from `thinc.api` Co-authored-by: Sofie Van Landeghem * Use relative imports in tb_framework * Don't assume a default for beam_width * We don't have a direct dependency on BLIS anymore * Rename forwards to _forward_{fallback,greedy_cpu} * Require thinc >=8.1.0,<8.2.0 * tb_framework: clean up imports * Fix return type of _get_seen_mask * Move up _forward_greedy_cpu * Style fixes. * Lower thinc lowerbound to 8.1.0.dev0 * Formatting fix Co-authored-by: Adriane Boyd Co-authored-by: Sofie Van Landeghem Co-authored-by: Adriane Boyd * Reimplement parser rehearsal function (#10878) * Reimplement parser rehearsal function Before the parser refactor, rehearsal was driven by a loop in the `rehearse` method itself. For each parsing step, the loops would: 1. Get the predictions of the teacher. 2. Get the predictions and backprop function of the student. 3. Compute the loss and backprop into the student. 4. Move the teacher and student forward with the predictions of the student. In the refactored parser, we cannot perform search stepwise rehearsal anymore, since the model now predicts all parsing steps at once. Therefore, rehearsal is performed in the following steps: 1. Get the predictions of all parsing steps from the student, along with its backprop function. 2. Get the predictions from the teacher, but use the predictions of the student to advance the parser while doing so. 3. Compute the loss and backprop into the student. To support the second step a new method, `advance_with_actions` is added to `GreedyBatch`, which performs the provided parsing steps. * tb_framework: wrap upper_W and upper_b in Linear Thinc's Optimizer cannot handle resizing of existing parameters. Until it does, we work around this by wrapping the weights/biases of the upper layer of the parser model in Linear. When the upper layer is resized, we copy over the existing parameters into a new Linear instance. This does not trigger an error in Optimizer, because it sees the resized layer as a new set of parameters. * Add test for TransitionSystem.apply_actions * Better FIXME marker Co-authored-by: Madeesh Kannan * Fixes from Madeesh * Apply suggestions from Sofie Co-authored-by: Sofie Van Landeghem * Remove useless assignment Co-authored-by: Madeesh Kannan Co-authored-by: Sofie Van Landeghem * Rename some identifiers in the parser refactor (#10935) * Rename _parseC to _parse_batch * tb_framework: prefix many auxiliary functions with underscore To clearly state the intent that they are private. * Rename `lower` to `hidden`, `upper` to `output` * Parser slow test fixup We don't have TransitionBasedParser.{v1,v2} until we bring it back as a legacy option. * Remove last vestiges of PrecomputableAffine This does not exist anymore as a separate layer. * ner: re-enable sentence boundary checks * Re-enable test that works now. * test_ner: make loss test more strict again * Remove commented line * Re-enable some more beam parser tests * Remove unused _forward_reference function * Update for CBlas changes in Thinc 8.1.0.dev2 Bump thinc dependency to 8.1.0.dev3. * Remove references to spacy.TransitionBasedParser.{v1,v2} Since they will not be offered starting with spaCy v4. * `tb_framework`: Replace references to `thinc.backends.linalg` with `CBlas` * dont use get_array_module (#11056) (#11293) Co-authored-by: kadarakos * Move `thinc.extra.search` to `spacy.pipeline._parser_internals` (#11317) * `search`: Move from `thinc.extra.search` Fix NPE in `Beam.__dealloc__` * `pytest`: Add support for executing Cython tests Move `search` tests from thinc and patch them to run with `pytest` * `mypy` fix * Update comment * `conftest`: Expose `register_cython_tests` * Remove unused import * Move `argmax` impls to new `_parser_utils` Cython module (#11410) * Parser does not have to be a cdef class anymore This also fixes validation of the initialization schema. * Add back spacy.TransitionBasedParser.v2 * Fix a rename that was missed in #10878. So that rehearsal tests pass. * Remove module from setup.py that got added during the merge * Bring back support for `update_with_oracle_cut_size` (#12086) * Bring back support for `update_with_oracle_cut_size` This option was available in the pre-refactor parser, but was never implemented in the refactored parser. This option cuts transition sequences that are longer than `update_with_oracle_cut` size into separate sequences that have at most `update_with_oracle_cut` transitions. The oracle (gold standard) transition sequence is used to determine the cuts and the initial states for the additional sequences. Applying this cut makes the batches more homogeneous in the transition sequence lengths, making forward passes (and as a consequence training) much faster. Training time 1000 steps on de_core_news_lg: - Before this change: 149s - After this change: 68s - Pre-refactor parser: 81s * Fix a rename that was missed in #10878. So that rehearsal tests pass. * Apply suggestions from @shadeMe * Use chained conditional * Test with update_with_oracle_cut_size={0, 1, 5, 100} And fix a git that occurs with a cut size of 1. * Fix up some merge fall out * Update parser distillation for the refactor In the old parser, we'd iterate over the transitions in the distill function and compute the loss/gradients on the go. In the refactored parser, we first let the student model parse the inputs. Then we'll let the teacher compute the transition probabilities of the states in the student's transition sequence. We can then compute the gradients of the student given the teacher. * Add back spacy.TransitionBasedParser.v1 references - Accordion in the architecture docs. - Test in test_parse, but disabled until we have a spacy-legacy release. Co-authored-by: Matthew Honnibal Co-authored-by: svlandeg Co-authored-by: Sofie Van Landeghem Co-authored-by: Madeesh Kannan Co-authored-by: Adriane Boyd Co-authored-by: kadarakos --- setup.py | 6 +- spacy/cli/templates/quickstart_training.jinja | 12 +- spacy/errors.py | 3 + spacy/ml/_precomputable_affine.py | 164 ----- spacy/ml/models/parser.py | 175 ++--- spacy/ml/parser_model.pxd | 49 -- spacy/ml/parser_model.pyx | 500 -------------- spacy/ml/tb_framework.pxd | 28 + spacy/ml/tb_framework.py | 50 -- spacy/ml/tb_framework.pyx | 621 ++++++++++++++++++ .../_parser_internals/_beam_utils.pyx | 3 +- .../_parser_internals/_parser_utils.pxd | 2 + .../_parser_internals/_parser_utils.pyx | 22 + spacy/pipeline/_parser_internals/_state.pxd | 59 +- .../pipeline/_parser_internals/arc_eager.pyx | 3 + spacy/pipeline/_parser_internals/batch.pxd | 2 + spacy/pipeline/_parser_internals/batch.pyx | 52 ++ spacy/pipeline/_parser_internals/ner.pyx | 6 +- .../pipeline/_parser_internals/stateclass.pyx | 7 + .../_parser_internals/transition_system.pxd | 7 + .../_parser_internals/transition_system.pyx | 71 ++ .../{dep_parser.pyx => dep_parser.py} | 20 +- spacy/pipeline/{ner.pyx => ner.py} | 32 +- spacy/pipeline/transition_parser.pxd | 21 - spacy/pipeline/transition_parser.pyx | 487 ++++++-------- spacy/tests/parser/test_ner.py | 10 +- spacy/tests/parser/test_parse.py | 77 ++- spacy/tests/pipeline/test_tok2vec.py | 2 +- .../tests/serialize/test_serialize_config.py | 56 +- spacy/tests/test_misc.py | 34 +- spacy/training/example.pyx | 1 - website/docs/api/architectures.mdx | 26 +- website/docs/api/cli.mdx | 8 +- website/docs/api/legacy.mdx | 2 +- .../docs/usage/embeddings-transformers.mdx | 6 +- 35 files changed, 1282 insertions(+), 1342 deletions(-) delete mode 100644 spacy/ml/_precomputable_affine.py delete mode 100644 spacy/ml/parser_model.pxd delete mode 100644 spacy/ml/parser_model.pyx create mode 100644 spacy/ml/tb_framework.pxd delete mode 100644 spacy/ml/tb_framework.py create mode 100644 spacy/ml/tb_framework.pyx create mode 100644 spacy/pipeline/_parser_internals/_parser_utils.pxd create mode 100644 spacy/pipeline/_parser_internals/_parser_utils.pyx create mode 100644 spacy/pipeline/_parser_internals/batch.pxd create mode 100644 spacy/pipeline/_parser_internals/batch.pyx rename spacy/pipeline/{dep_parser.pyx => dep_parser.py} (97%) rename spacy/pipeline/{ner.pyx => ner.py} (94%) delete mode 100644 spacy/pipeline/transition_parser.pxd diff --git a/setup.py b/setup.py index 77a4cf283..d5b82ec68 100755 --- a/setup.py +++ b/setup.py @@ -33,12 +33,10 @@ MOD_NAMES = [ "spacy.kb.candidate", "spacy.kb.kb", "spacy.kb.kb_in_memory", - "spacy.ml.parser_model", + "spacy.ml.tb_framework", "spacy.morphology", - "spacy.pipeline.dep_parser", "spacy.pipeline._edit_tree_internals.edit_trees", "spacy.pipeline.morphologizer", - "spacy.pipeline.ner", "spacy.pipeline.pipe", "spacy.pipeline.trainable_pipe", "spacy.pipeline.sentencizer", @@ -46,6 +44,7 @@ MOD_NAMES = [ "spacy.pipeline.tagger", "spacy.pipeline.transition_parser", "spacy.pipeline._parser_internals.arc_eager", + "spacy.pipeline._parser_internals.batch", "spacy.pipeline._parser_internals.ner", "spacy.pipeline._parser_internals.nonproj", "spacy.pipeline._parser_internals.search", @@ -53,6 +52,7 @@ MOD_NAMES = [ "spacy.pipeline._parser_internals.stateclass", "spacy.pipeline._parser_internals.transition_system", "spacy.pipeline._parser_internals._beam_utils", + "spacy.pipeline._parser_internals._parser_utils", "spacy.tokenizer", "spacy.training.align", "spacy.training.gold_io", diff --git a/spacy/cli/templates/quickstart_training.jinja b/spacy/cli/templates/quickstart_training.jinja index b961ac892..eb48d1de5 100644 --- a/spacy/cli/templates/quickstart_training.jinja +++ b/spacy/cli/templates/quickstart_training.jinja @@ -87,12 +87,11 @@ grad_factor = 1.0 factory = "parser" [components.parser.model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "parser" extra_state_tokens = false hidden_width = 128 maxout_pieces = 3 -use_upper = false nO = null [components.parser.model.tok2vec] @@ -108,12 +107,11 @@ grad_factor = 1.0 factory = "ner" [components.ner.model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "ner" extra_state_tokens = false hidden_width = 64 maxout_pieces = 2 -use_upper = false nO = null [components.ner.model.tok2vec] @@ -314,12 +312,11 @@ width = ${components.tok2vec.model.encode.width} factory = "parser" [components.parser.model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "parser" extra_state_tokens = false hidden_width = 128 maxout_pieces = 3 -use_upper = true nO = null [components.parser.model.tok2vec] @@ -332,12 +329,11 @@ width = ${components.tok2vec.model.encode.width} factory = "ner" [components.ner.model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "ner" extra_state_tokens = false hidden_width = 64 maxout_pieces = 2 -use_upper = true nO = null [components.ner.model.tok2vec] diff --git a/spacy/errors.py b/spacy/errors.py index 91e7a6006..a6ec4f6a0 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -209,6 +209,8 @@ class Warnings(metaclass=ErrorsWithCodes): "`enabled` ({enabled}). Be aware that this might affect other components in your pipeline.") W124 = ("{host}:{port} is already in use, using the nearest available port {serve_port} as an alternative.") + W400 = ("`use_upper=False` is ignored, the upper layer is always enabled") + class Errors(metaclass=ErrorsWithCodes): E001 = ("No component '{name}' found in pipeline. Available names: {opts}") @@ -958,6 +960,7 @@ class Errors(metaclass=ErrorsWithCodes): E4002 = ("Pipe '{name}' requires a teacher pipe for distillation.") E4003 = ("Training examples for distillation must have the exact same tokens in the " "reference and predicted docs.") + E4004 = ("Backprop is not supported when is_train is not set.") # fmt: on diff --git a/spacy/ml/_precomputable_affine.py b/spacy/ml/_precomputable_affine.py deleted file mode 100644 index 1c20c622b..000000000 --- a/spacy/ml/_precomputable_affine.py +++ /dev/null @@ -1,164 +0,0 @@ -from thinc.api import Model, normal_init - -from ..util import registry - - -@registry.layers("spacy.PrecomputableAffine.v1") -def PrecomputableAffine(nO, nI, nF, nP, dropout=0.1): - model = Model( - "precomputable_affine", - forward, - init=init, - dims={"nO": nO, "nI": nI, "nF": nF, "nP": nP}, - params={"W": None, "b": None, "pad": None}, - attrs={"dropout_rate": dropout}, - ) - return model - - -def forward(model, X, is_train): - nF = model.get_dim("nF") - nO = model.get_dim("nO") - nP = model.get_dim("nP") - nI = model.get_dim("nI") - W = model.get_param("W") - # Preallocate array for layer output, including padding. - Yf = model.ops.alloc2f(X.shape[0] + 1, nF * nO * nP, zeros=False) - model.ops.gemm(X, W.reshape((nF * nO * nP, nI)), trans2=True, out=Yf[1:]) - Yf = Yf.reshape((Yf.shape[0], nF, nO, nP)) - - # Set padding. Padding has shape (1, nF, nO, nP). Unfortunately, we cannot - # change its shape to (nF, nO, nP) without breaking existing models. So - # we'll squeeze the first dimension here. - Yf[0] = model.ops.xp.squeeze(model.get_param("pad"), 0) - - def backward(dY_ids): - # This backprop is particularly tricky, because we get back a different - # thing from what we put out. We put out an array of shape: - # (nB, nF, nO, nP), and get back: - # (nB, nO, nP) and ids (nB, nF) - # The ids tell us the values of nF, so we would have: - # - # dYf = zeros((nB, nF, nO, nP)) - # for b in range(nB): - # for f in range(nF): - # dYf[b, ids[b, f]] += dY[b] - # - # However, we avoid building that array for efficiency -- and just pass - # in the indices. - dY, ids = dY_ids - assert dY.ndim == 3 - assert dY.shape[1] == nO, dY.shape - assert dY.shape[2] == nP, dY.shape - # nB = dY.shape[0] - model.inc_grad("pad", _backprop_precomputable_affine_padding(model, dY, ids)) - Xf = X[ids] - Xf = Xf.reshape((Xf.shape[0], nF * nI)) - - model.inc_grad("b", dY.sum(axis=0)) - dY = dY.reshape((dY.shape[0], nO * nP)) - - Wopfi = W.transpose((1, 2, 0, 3)) - Wopfi = Wopfi.reshape((nO * nP, nF * nI)) - dXf = model.ops.gemm(dY.reshape((dY.shape[0], nO * nP)), Wopfi) - - dWopfi = model.ops.gemm(dY, Xf, trans1=True) - dWopfi = dWopfi.reshape((nO, nP, nF, nI)) - # (o, p, f, i) --> (f, o, p, i) - dWopfi = dWopfi.transpose((2, 0, 1, 3)) - model.inc_grad("W", dWopfi) - return dXf.reshape((dXf.shape[0], nF, nI)) - - return Yf, backward - - -def _backprop_precomputable_affine_padding(model, dY, ids): - nB = dY.shape[0] - nF = model.get_dim("nF") - nP = model.get_dim("nP") - nO = model.get_dim("nO") - # Backprop the "padding", used as a filler for missing values. - # Values that are missing are set to -1, and each state vector could - # have multiple missing values. The padding has different values for - # different missing features. The gradient of the padding vector is: - # - # for b in range(nB): - # for f in range(nF): - # if ids[b, f] < 0: - # d_pad[f] += dY[b] - # - # Which can be rewritten as: - # - # (ids < 0).T @ dY - mask = model.ops.asarray(ids < 0, dtype="f") - d_pad = model.ops.gemm(mask, dY.reshape(nB, nO * nP), trans1=True) - return d_pad.reshape((1, nF, nO, nP)) - - -def init(model, X=None, Y=None): - """This is like the 'layer sequential unit variance', but instead - of taking the actual inputs, we randomly generate whitened data. - - Why's this all so complicated? We have a huge number of inputs, - and the maxout unit makes guessing the dynamics tricky. Instead - we set the maxout weights to values that empirically result in - whitened outputs given whitened inputs. - """ - if model.has_param("W") and model.get_param("W").any(): - return - - nF = model.get_dim("nF") - nO = model.get_dim("nO") - nP = model.get_dim("nP") - nI = model.get_dim("nI") - W = model.ops.alloc4f(nF, nO, nP, nI) - b = model.ops.alloc2f(nO, nP) - pad = model.ops.alloc4f(1, nF, nO, nP) - - ops = model.ops - W = normal_init(ops, W.shape, mean=float(ops.xp.sqrt(1.0 / nF * nI))) - pad = normal_init(ops, pad.shape, mean=1.0) - model.set_param("W", W) - model.set_param("b", b) - model.set_param("pad", pad) - - ids = ops.alloc((5000, nF), dtype="f") - ids += ops.xp.random.uniform(0, 1000, ids.shape) - ids = ops.asarray(ids, dtype="i") - tokvecs = ops.alloc((5000, nI), dtype="f") - tokvecs += ops.xp.random.normal(loc=0.0, scale=1.0, size=tokvecs.size).reshape( - tokvecs.shape - ) - - def predict(ids, tokvecs): - # nS ids. nW tokvecs. Exclude the padding array. - hiddens = model.predict(tokvecs[:-1]) # (nW, f, o, p) - vectors = model.ops.alloc((ids.shape[0], nO * nP), dtype="f") - # need nS vectors - hiddens = hiddens.reshape((hiddens.shape[0] * nF, nO * nP)) - model.ops.scatter_add(vectors, ids.flatten(), hiddens) - vectors = vectors.reshape((vectors.shape[0], nO, nP)) - vectors += b - vectors = model.ops.asarray(vectors) - if nP >= 2: - return model.ops.maxout(vectors)[0] - else: - return vectors * (vectors >= 0) - - tol_var = 0.01 - tol_mean = 0.01 - t_max = 10 - W = model.get_param("W").copy() - b = model.get_param("b").copy() - for t_i in range(t_max): - acts1 = predict(ids, tokvecs) - var = model.ops.xp.var(acts1) - mean = model.ops.xp.mean(acts1) - if abs(var - 1.0) >= tol_var: - W /= model.ops.xp.sqrt(var) - model.set_param("W", W) - elif abs(mean) >= tol_mean: - b -= mean - model.set_param("b", b) - else: - break diff --git a/spacy/ml/models/parser.py b/spacy/ml/models/parser.py index a70d84dea..e2ee87d82 100644 --- a/spacy/ml/models/parser.py +++ b/spacy/ml/models/parser.py @@ -1,17 +1,20 @@ -from typing import Optional, List, cast -from thinc.api import Model, chain, list2array, Linear, zero_init, use_ops +from typing import Optional, List, Tuple, Any from thinc.types import Floats2d +from thinc.api import Model +import warnings -from ...errors import Errors +from ...errors import Errors, Warnings from ...compat import Literal from ...util import registry -from .._precomputable_affine import PrecomputableAffine from ..tb_framework import TransitionModel -from ...tokens import Doc +from ...tokens.doc import Doc + +TransitionSystem = Any # TODO +State = Any # TODO -@registry.architectures("spacy.TransitionBasedParser.v2") -def build_tb_parser_model( +@registry.architectures.register("spacy.TransitionBasedParser.v2") +def transition_parser_v2( tok2vec: Model[List[Doc], List[Floats2d]], state_type: Literal["parser", "ner"], extra_state_tokens: bool, @@ -19,6 +22,46 @@ def build_tb_parser_model( maxout_pieces: int, use_upper: bool, nO: Optional[int] = None, +) -> Model: + if not use_upper: + warnings.warn(Warnings.W400) + + return build_tb_parser_model( + tok2vec, + state_type, + extra_state_tokens, + hidden_width, + maxout_pieces, + nO=nO, + ) + + +@registry.architectures.register("spacy.TransitionBasedParser.v3") +def transition_parser_v3( + tok2vec: Model[List[Doc], List[Floats2d]], + state_type: Literal["parser", "ner"], + extra_state_tokens: bool, + hidden_width: int, + maxout_pieces: int, + nO: Optional[int] = None, +) -> Model: + return build_tb_parser_model( + tok2vec, + state_type, + extra_state_tokens, + hidden_width, + maxout_pieces, + nO=nO, + ) + + +def build_tb_parser_model( + tok2vec: Model[List[Doc], List[Floats2d]], + state_type: Literal["parser", "ner"], + extra_state_tokens: bool, + hidden_width: int, + maxout_pieces: int, + nO: Optional[int] = None, ) -> Model: """ Build a transition-based parser model. Can apply to NER or dependency-parsing. @@ -51,14 +94,7 @@ def build_tb_parser_model( feature sets (for the NER) or 13 (for the parser). hidden_width (int): The width of the hidden layer. maxout_pieces (int): How many pieces to use in the state prediction layer. - Recommended values are 1, 2 or 3. If 1, the maxout non-linearity - is replaced with a ReLu non-linearity if use_upper=True, and no - non-linearity if use_upper=False. - use_upper (bool): Whether to use an additional hidden layer after the state - vector in order to predict the action scores. It is recommended to set - this to False for large pretrained models such as transformers, and True - for smaller networks. The upper layer is computed on CPU, which becomes - a bottleneck on larger GPU-based models, where it's also less necessary. + Recommended values are 1, 2 or 3. nO (int or None): The number of actions the model will predict between. Usually inferred from data at the beginning of training, or loaded from disk. @@ -69,106 +105,11 @@ def build_tb_parser_model( nr_feature_tokens = 6 if extra_state_tokens else 3 else: raise ValueError(Errors.E917.format(value=state_type)) - t2v_width = tok2vec.get_dim("nO") if tok2vec.has_dim("nO") else None - tok2vec = chain( - tok2vec, - list2array(), - Linear(hidden_width, t2v_width), + return TransitionModel( + tok2vec=tok2vec, + state_tokens=nr_feature_tokens, + hidden_width=hidden_width, + maxout_pieces=maxout_pieces, + nO=nO, + unseen_classes=set(), ) - tok2vec.set_dim("nO", hidden_width) - lower = _define_lower( - nO=hidden_width if use_upper else nO, - nF=nr_feature_tokens, - nI=tok2vec.get_dim("nO"), - nP=maxout_pieces, - ) - upper = None - if use_upper: - with use_ops("cpu"): - # Initialize weights at zero, as it's a classification layer. - upper = _define_upper(nO=nO, nI=None) - return TransitionModel(tok2vec, lower, upper, resize_output) - - -def _define_upper(nO, nI): - return Linear(nO=nO, nI=nI, init_W=zero_init) - - -def _define_lower(nO, nF, nI, nP): - return PrecomputableAffine(nO=nO, nF=nF, nI=nI, nP=nP) - - -def resize_output(model, new_nO): - if model.attrs["has_upper"]: - return _resize_upper(model, new_nO) - return _resize_lower(model, new_nO) - - -def _resize_upper(model, new_nO): - upper = model.get_ref("upper") - if upper.has_dim("nO") is None: - upper.set_dim("nO", new_nO) - return model - elif new_nO == upper.get_dim("nO"): - return model - - smaller = upper - nI = smaller.maybe_get_dim("nI") - with use_ops("cpu"): - larger = _define_upper(nO=new_nO, nI=nI) - # it could be that the model is not initialized yet, then skip this bit - if smaller.has_param("W"): - larger_W = larger.ops.alloc2f(new_nO, nI) - larger_b = larger.ops.alloc1f(new_nO) - smaller_W = smaller.get_param("W") - smaller_b = smaller.get_param("b") - # Weights are stored in (nr_out, nr_in) format, so we're basically - # just adding rows here. - if smaller.has_dim("nO"): - old_nO = smaller.get_dim("nO") - larger_W[:old_nO] = smaller_W - larger_b[:old_nO] = smaller_b - for i in range(old_nO, new_nO): - model.attrs["unseen_classes"].add(i) - - larger.set_param("W", larger_W) - larger.set_param("b", larger_b) - model._layers[-1] = larger - model.set_ref("upper", larger) - return model - - -def _resize_lower(model, new_nO): - lower = model.get_ref("lower") - if lower.has_dim("nO") is None: - lower.set_dim("nO", new_nO) - return model - - smaller = lower - nI = smaller.maybe_get_dim("nI") - nF = smaller.maybe_get_dim("nF") - nP = smaller.maybe_get_dim("nP") - larger = _define_lower(nO=new_nO, nI=nI, nF=nF, nP=nP) - # it could be that the model is not initialized yet, then skip this bit - if smaller.has_param("W"): - larger_W = larger.ops.alloc4f(nF, new_nO, nP, nI) - larger_b = larger.ops.alloc2f(new_nO, nP) - larger_pad = larger.ops.alloc4f(1, nF, new_nO, nP) - smaller_W = smaller.get_param("W") - smaller_b = smaller.get_param("b") - smaller_pad = smaller.get_param("pad") - # Copy the old weights and padding into the new layer - if smaller.has_dim("nO"): - old_nO = smaller.get_dim("nO") - larger_W[:, 0:old_nO, :, :] = smaller_W - larger_pad[:, :, 0:old_nO, :] = smaller_pad - larger_b[0:old_nO, :] = smaller_b - for i in range(old_nO, new_nO): - model.attrs["unseen_classes"].add(i) - - larger.set_param("W", larger_W) - larger.set_param("b", larger_b) - larger.set_param("pad", larger_pad) - model._layers[1] = larger - model.set_ref("lower", larger) - return model diff --git a/spacy/ml/parser_model.pxd b/spacy/ml/parser_model.pxd deleted file mode 100644 index 8def6cea5..000000000 --- a/spacy/ml/parser_model.pxd +++ /dev/null @@ -1,49 +0,0 @@ -from libc.string cimport memset, memcpy -from thinc.backends.cblas cimport CBlas -from ..typedefs cimport weight_t, hash_t -from ..pipeline._parser_internals._state cimport StateC - - -cdef struct SizesC: - int states - int classes - int hiddens - int pieces - int feats - int embed_width - - -cdef struct WeightsC: - const float* feat_weights - const float* feat_bias - const float* hidden_bias - const float* hidden_weights - const float* seen_classes - - -cdef struct ActivationsC: - int* token_ids - float* unmaxed - float* scores - float* hiddens - int* is_valid - int _curr_size - int _max_size - - -cdef WeightsC get_c_weights(model) except * - -cdef SizesC get_c_sizes(model, int batch_size) except * - -cdef ActivationsC alloc_activations(SizesC n) nogil - -cdef void free_activations(const ActivationsC* A) nogil - -cdef void predict_states(CBlas cblas, ActivationsC* A, StateC** states, - const WeightsC* W, SizesC n) nogil - -cdef int arg_max_if_valid(const weight_t* scores, const int* is_valid, int n) nogil - -cdef void cpu_log_loss(float* d_scores, - const float* costs, const int* is_valid, const float* scores, int O) nogil - diff --git a/spacy/ml/parser_model.pyx b/spacy/ml/parser_model.pyx deleted file mode 100644 index 91558683b..000000000 --- a/spacy/ml/parser_model.pyx +++ /dev/null @@ -1,500 +0,0 @@ -# cython: infer_types=True, cdivision=True, boundscheck=False -cimport numpy as np -from libc.math cimport exp -from libc.string cimport memset, memcpy -from libc.stdlib cimport calloc, free, realloc -from thinc.backends.cblas cimport saxpy, sgemm - -import numpy -import numpy.random -from thinc.api import Model, CupyOps, NumpyOps, get_ops - -from .. import util -from ..errors import Errors -from ..typedefs cimport weight_t, class_t, hash_t -from ..pipeline._parser_internals.stateclass cimport StateClass - - -cdef WeightsC get_c_weights(model) except *: - cdef WeightsC output - cdef precompute_hiddens state2vec = model.state2vec - output.feat_weights = state2vec.get_feat_weights() - output.feat_bias = state2vec.bias.data - cdef np.ndarray vec2scores_W - cdef np.ndarray vec2scores_b - if model.vec2scores is None: - output.hidden_weights = NULL - output.hidden_bias = NULL - else: - vec2scores_W = model.vec2scores.get_param("W") - vec2scores_b = model.vec2scores.get_param("b") - output.hidden_weights = vec2scores_W.data - output.hidden_bias = vec2scores_b.data - cdef np.ndarray class_mask = model._class_mask - output.seen_classes = class_mask.data - return output - - -cdef SizesC get_c_sizes(model, int batch_size) except *: - cdef SizesC output - output.states = batch_size - if model.vec2scores is None: - output.classes = model.state2vec.get_dim("nO") - else: - output.classes = model.vec2scores.get_dim("nO") - output.hiddens = model.state2vec.get_dim("nO") - output.pieces = model.state2vec.get_dim("nP") - output.feats = model.state2vec.get_dim("nF") - output.embed_width = model.tokvecs.shape[1] - return output - - -cdef ActivationsC alloc_activations(SizesC n) nogil: - cdef ActivationsC A - memset(&A, 0, sizeof(A)) - resize_activations(&A, n) - return A - - -cdef void free_activations(const ActivationsC* A) nogil: - free(A.token_ids) - free(A.scores) - free(A.unmaxed) - free(A.hiddens) - free(A.is_valid) - - -cdef void resize_activations(ActivationsC* A, SizesC n) nogil: - if n.states <= A._max_size: - A._curr_size = n.states - return - if A._max_size == 0: - A.token_ids = calloc(n.states * n.feats, sizeof(A.token_ids[0])) - A.scores = calloc(n.states * n.classes, sizeof(A.scores[0])) - A.unmaxed = calloc(n.states * n.hiddens * n.pieces, sizeof(A.unmaxed[0])) - A.hiddens = calloc(n.states * n.hiddens, sizeof(A.hiddens[0])) - A.is_valid = calloc(n.states * n.classes, sizeof(A.is_valid[0])) - A._max_size = n.states - else: - A.token_ids = realloc(A.token_ids, - n.states * n.feats * sizeof(A.token_ids[0])) - A.scores = realloc(A.scores, - n.states * n.classes * sizeof(A.scores[0])) - A.unmaxed = realloc(A.unmaxed, - n.states * n.hiddens * n.pieces * sizeof(A.unmaxed[0])) - A.hiddens = realloc(A.hiddens, - n.states * n.hiddens * sizeof(A.hiddens[0])) - A.is_valid = realloc(A.is_valid, - n.states * n.classes * sizeof(A.is_valid[0])) - A._max_size = n.states - A._curr_size = n.states - - -cdef void predict_states(CBlas cblas, ActivationsC* A, StateC** states, - const WeightsC* W, SizesC n) nogil: - cdef double one = 1.0 - resize_activations(A, n) - for i in range(n.states): - states[i].set_context_tokens(&A.token_ids[i*n.feats], n.feats) - memset(A.unmaxed, 0, n.states * n.hiddens * n.pieces * sizeof(float)) - memset(A.hiddens, 0, n.states * n.hiddens * sizeof(float)) - sum_state_features(cblas, A.unmaxed, - W.feat_weights, A.token_ids, n.states, n.feats, n.hiddens * n.pieces) - for i in range(n.states): - saxpy(cblas)(n.hiddens * n.pieces, 1., W.feat_bias, 1, &A.unmaxed[i*n.hiddens*n.pieces], 1) - for j in range(n.hiddens): - index = i * n.hiddens * n.pieces + j * n.pieces - which = _arg_max(&A.unmaxed[index], n.pieces) - A.hiddens[i*n.hiddens + j] = A.unmaxed[index + which] - memset(A.scores, 0, n.states * n.classes * sizeof(float)) - if W.hidden_weights == NULL: - memcpy(A.scores, A.hiddens, n.states * n.classes * sizeof(float)) - else: - # Compute hidden-to-output - sgemm(cblas)(False, True, n.states, n.classes, n.hiddens, - 1.0, A.hiddens, n.hiddens, - W.hidden_weights, n.hiddens, - 0.0, A.scores, n.classes) - # Add bias - for i in range(n.states): - saxpy(cblas)(n.classes, 1., W.hidden_bias, 1, &A.scores[i*n.classes], 1) - # Set unseen classes to minimum value - i = 0 - min_ = A.scores[0] - for i in range(1, n.states * n.classes): - if A.scores[i] < min_: - min_ = A.scores[i] - for i in range(n.states): - for j in range(n.classes): - if not W.seen_classes[j]: - A.scores[i*n.classes+j] = min_ - - -cdef void sum_state_features(CBlas cblas, float* output, - const float* cached, const int* token_ids, int B, int F, int O) nogil: - cdef int idx, b, f, i - cdef const float* feature - padding = cached - cached += F * O - cdef int id_stride = F*O - cdef float one = 1. - for b in range(B): - for f in range(F): - if token_ids[f] < 0: - feature = &padding[f*O] - else: - idx = token_ids[f] * id_stride + f*O - feature = &cached[idx] - saxpy(cblas)(O, one, feature, 1, &output[b*O], 1) - token_ids += F - - -cdef void cpu_log_loss(float* d_scores, - const float* costs, const int* is_valid, const float* scores, - int O) nogil: - """Do multi-label log loss""" - cdef double max_, gmax, Z, gZ - best = arg_max_if_gold(scores, costs, is_valid, O) - guess = _arg_max(scores, O) - - if best == -1 or guess == -1: - # These shouldn't happen, but if they do, we want to make sure we don't - # cause an OOB access. - return - Z = 1e-10 - gZ = 1e-10 - max_ = scores[guess] - gmax = scores[best] - for i in range(O): - Z += exp(scores[i] - max_) - if costs[i] <= costs[best]: - gZ += exp(scores[i] - gmax) - for i in range(O): - if costs[i] <= costs[best]: - d_scores[i] = (exp(scores[i]-max_) / Z) - (exp(scores[i]-gmax)/gZ) - else: - d_scores[i] = exp(scores[i]-max_) / Z - - -cdef int arg_max_if_gold(const weight_t* scores, const weight_t* costs, - const int* is_valid, int n) nogil: - # Find minimum cost - cdef float cost = 1 - for i in range(n): - if is_valid[i] and costs[i] < cost: - cost = costs[i] - # Now find best-scoring with that cost - cdef int best = -1 - for i in range(n): - if costs[i] <= cost and is_valid[i]: - if best == -1 or scores[i] > scores[best]: - best = i - return best - - -cdef int arg_max_if_valid(const weight_t* scores, const int* is_valid, int n) nogil: - cdef int best = -1 - for i in range(n): - if is_valid[i] >= 1: - if best == -1 or scores[i] > scores[best]: - best = i - return best - - - -class ParserStepModel(Model): - def __init__(self, docs, layers, *, has_upper, unseen_classes=None, train=True, - dropout=0.1): - Model.__init__(self, name="parser_step_model", forward=step_forward) - self.attrs["has_upper"] = has_upper - self.attrs["dropout_rate"] = dropout - self.tokvecs, self.bp_tokvecs = layers[0](docs, is_train=train) - if layers[1].get_dim("nP") >= 2: - activation = "maxout" - elif has_upper: - activation = None - else: - activation = "relu" - self.state2vec = precompute_hiddens(len(docs), self.tokvecs, layers[1], - activation=activation, train=train) - if has_upper: - self.vec2scores = layers[-1] - else: - self.vec2scores = None - self.cuda_stream = util.get_cuda_stream(non_blocking=True) - self.backprops = [] - self._class_mask = numpy.zeros((self.nO,), dtype='f') - self._class_mask.fill(1) - if unseen_classes is not None: - for class_ in unseen_classes: - self._class_mask[class_] = 0. - - def clear_memory(self): - del self.tokvecs - del self.bp_tokvecs - del self.state2vec - del self.backprops - del self._class_mask - - @property - def nO(self): - if self.attrs["has_upper"]: - return self.vec2scores.get_dim("nO") - else: - return self.state2vec.get_dim("nO") - - def class_is_unseen(self, class_): - return self._class_mask[class_] - - def mark_class_unseen(self, class_): - self._class_mask[class_] = 0 - - def mark_class_seen(self, class_): - self._class_mask[class_] = 1 - - def get_token_ids(self, states): - cdef StateClass state - states = [state for state in states if not state.is_final()] - cdef np.ndarray ids = numpy.zeros((len(states), self.state2vec.nF), - dtype='i', order='C') - ids.fill(-1) - c_ids = ids.data - for state in states: - state.c.set_context_tokens(c_ids, ids.shape[1]) - c_ids += ids.shape[1] - return ids - - def backprop_step(self, token_ids, d_vector, get_d_tokvecs): - if isinstance(self.state2vec.ops, CupyOps) \ - and not isinstance(token_ids, self.state2vec.ops.xp.ndarray): - # Move token_ids and d_vector to GPU, asynchronously - self.backprops.append(( - util.get_async(self.cuda_stream, token_ids), - util.get_async(self.cuda_stream, d_vector), - get_d_tokvecs - )) - else: - self.backprops.append((token_ids, d_vector, get_d_tokvecs)) - - - def finish_steps(self, golds): - # Add a padding vector to the d_tokvecs gradient, so that missing - # values don't affect the real gradient. - d_tokvecs = self.ops.alloc((self.tokvecs.shape[0]+1, self.tokvecs.shape[1])) - # Tells CUDA to block, so our async copies complete. - if self.cuda_stream is not None: - self.cuda_stream.synchronize() - for ids, d_vector, bp_vector in self.backprops: - d_state_features = bp_vector((d_vector, ids)) - ids = ids.flatten() - d_state_features = d_state_features.reshape( - (ids.size, d_state_features.shape[2])) - self.ops.scatter_add(d_tokvecs, ids, - d_state_features) - # Padded -- see update() - self.bp_tokvecs(d_tokvecs[:-1]) - return d_tokvecs - -NUMPY_OPS = NumpyOps() - -def step_forward(model: ParserStepModel, states, is_train): - token_ids = model.get_token_ids(states) - vector, get_d_tokvecs = model.state2vec(token_ids, is_train) - mask = None - if model.attrs["has_upper"]: - dropout_rate = model.attrs["dropout_rate"] - if is_train and dropout_rate > 0: - mask = NUMPY_OPS.get_dropout_mask(vector.shape, 0.1) - vector *= mask - scores, get_d_vector = model.vec2scores(vector, is_train) - else: - scores = NumpyOps().asarray(vector) - get_d_vector = lambda d_scores: d_scores - # If the class is unseen, make sure its score is minimum - scores[:, model._class_mask == 0] = numpy.nanmin(scores) - - def backprop_parser_step(d_scores): - # Zero vectors for unseen classes - d_scores *= model._class_mask - d_vector = get_d_vector(d_scores) - if mask is not None: - d_vector *= mask - model.backprop_step(token_ids, d_vector, get_d_tokvecs) - return None - return scores, backprop_parser_step - - -cdef class precompute_hiddens: - """Allow a model to be "primed" by pre-computing input features in bulk. - - This is used for the parser, where we want to take a batch of documents, - and compute vectors for each (token, position) pair. These vectors can then - be reused, especially for beam-search. - - Let's say we're using 12 features for each state, e.g. word at start of - buffer, three words on stack, their children, etc. In the normal arc-eager - system, a document of length N is processed in 2*N states. This means we'll - create 2*N*12 feature vectors --- but if we pre-compute, we only need - N*12 vector computations. The saving for beam-search is much better: - if we have a beam of k, we'll normally make 2*N*12*K computations -- - so we can save the factor k. This also gives a nice CPU/GPU division: - we can do all our hard maths up front, packed into large multiplications, - and do the hard-to-program parsing on the CPU. - """ - cdef readonly int nF, nO, nP - cdef bint _is_synchronized - cdef public object ops - cdef public object numpy_ops - cdef public object _cpu_ops - cdef np.ndarray _features - cdef np.ndarray _cached - cdef np.ndarray bias - cdef object _cuda_stream - cdef object _bp_hiddens - cdef object activation - - def __init__(self, batch_size, tokvecs, lower_model, cuda_stream=None, - activation="maxout", train=False): - gpu_cached, bp_features = lower_model(tokvecs, train) - cdef np.ndarray cached - if not isinstance(gpu_cached, numpy.ndarray): - # Note the passing of cuda_stream here: it lets - # cupy make the copy asynchronously. - # We then have to block before first use. - cached = gpu_cached.get(stream=cuda_stream) - else: - cached = gpu_cached - if not isinstance(lower_model.get_param("b"), numpy.ndarray): - self.bias = lower_model.get_param("b").get(stream=cuda_stream) - else: - self.bias = lower_model.get_param("b") - self.nF = cached.shape[1] - if lower_model.has_dim("nP"): - self.nP = lower_model.get_dim("nP") - else: - self.nP = 1 - self.nO = cached.shape[2] - self.ops = lower_model.ops - self.numpy_ops = NumpyOps() - self._cpu_ops = get_ops("cpu") if isinstance(self.ops, CupyOps) else self.ops - assert activation in (None, "relu", "maxout") - self.activation = activation - self._is_synchronized = False - self._cuda_stream = cuda_stream - self._cached = cached - self._bp_hiddens = bp_features - - cdef const float* get_feat_weights(self) except NULL: - if not self._is_synchronized and self._cuda_stream is not None: - self._cuda_stream.synchronize() - self._is_synchronized = True - return self._cached.data - - def has_dim(self, name): - if name == "nF": - return self.nF if self.nF is not None else True - elif name == "nP": - return self.nP if self.nP is not None else True - elif name == "nO": - return self.nO if self.nO is not None else True - else: - return False - - def get_dim(self, name): - if name == "nF": - return self.nF - elif name == "nP": - return self.nP - elif name == "nO": - return self.nO - else: - raise ValueError(Errors.E1033.format(name=name)) - - def set_dim(self, name, value): - if name == "nF": - self.nF = value - elif name == "nP": - self.nP = value - elif name == "nO": - self.nO = value - else: - raise ValueError(Errors.E1033.format(name=name)) - - def __call__(self, X, bint is_train): - if is_train: - return self.begin_update(X) - else: - return self.predict(X), lambda X: X - - def predict(self, X): - return self.begin_update(X)[0] - - def begin_update(self, token_ids): - cdef np.ndarray state_vector = numpy.zeros( - (token_ids.shape[0], self.nO, self.nP), dtype='f') - # This is tricky, but (assuming GPU available); - # - Input to forward on CPU - # - Output from forward on CPU - # - Input to backward on GPU! - # - Output from backward on GPU - bp_hiddens = self._bp_hiddens - - cdef CBlas cblas = self._cpu_ops.cblas() - - feat_weights = self.get_feat_weights() - cdef int[:, ::1] ids = token_ids - sum_state_features(cblas, state_vector.data, - feat_weights, &ids[0,0], - token_ids.shape[0], self.nF, self.nO*self.nP) - state_vector += self.bias - state_vector, bp_nonlinearity = self._nonlinearity(state_vector) - - def backward(d_state_vector_ids): - d_state_vector, token_ids = d_state_vector_ids - d_state_vector = bp_nonlinearity(d_state_vector) - d_tokens = bp_hiddens((d_state_vector, token_ids)) - return d_tokens - return state_vector, backward - - def _nonlinearity(self, state_vector): - if self.activation == "maxout": - return self._maxout_nonlinearity(state_vector) - else: - return self._relu_nonlinearity(state_vector) - - def _maxout_nonlinearity(self, state_vector): - state_vector, mask = self.numpy_ops.maxout(state_vector) - # We're outputting to CPU, but we need this variable on GPU for the - # backward pass. - mask = self.ops.asarray(mask) - - def backprop_maxout(d_best): - return self.ops.backprop_maxout(d_best, mask, self.nP) - - return state_vector, backprop_maxout - - def _relu_nonlinearity(self, state_vector): - state_vector = state_vector.reshape((state_vector.shape[0], -1)) - mask = state_vector >= 0. - state_vector *= mask - # We're outputting to CPU, but we need this variable on GPU for the - # backward pass. - mask = self.ops.asarray(mask) - - def backprop_relu(d_best): - d_best *= mask - return d_best.reshape((d_best.shape + (1,))) - - return state_vector, backprop_relu - -cdef inline int _arg_max(const float* scores, const int n_classes) nogil: - if n_classes == 2: - return 0 if scores[0] > scores[1] else 1 - cdef int i - cdef int best = 0 - cdef float mode = scores[0] - for i in range(1, n_classes): - if scores[i] > mode: - mode = scores[i] - best = i - return best diff --git a/spacy/ml/tb_framework.pxd b/spacy/ml/tb_framework.pxd new file mode 100644 index 000000000..965508519 --- /dev/null +++ b/spacy/ml/tb_framework.pxd @@ -0,0 +1,28 @@ +from libc.stdint cimport int8_t + + +cdef struct SizesC: + int states + int classes + int hiddens + int pieces + int feats + int embed_width + int tokens + + +cdef struct WeightsC: + const float* feat_weights + const float* feat_bias + const float* hidden_bias + const float* hidden_weights + const int8_t* seen_mask + + +cdef struct ActivationsC: + int* token_ids + float* unmaxed + float* hiddens + int* is_valid + int _curr_size + int _max_size diff --git a/spacy/ml/tb_framework.py b/spacy/ml/tb_framework.py deleted file mode 100644 index ab4a969e2..000000000 --- a/spacy/ml/tb_framework.py +++ /dev/null @@ -1,50 +0,0 @@ -from thinc.api import Model, noop -from .parser_model import ParserStepModel -from ..util import registry - - -@registry.layers("spacy.TransitionModel.v1") -def TransitionModel( - tok2vec, lower, upper, resize_output, dropout=0.2, unseen_classes=set() -): - """Set up a stepwise transition-based model""" - if upper is None: - has_upper = False - upper = noop() - else: - has_upper = True - # don't define nO for this object, because we can't dynamically change it - return Model( - name="parser_model", - forward=forward, - dims={"nI": tok2vec.maybe_get_dim("nI")}, - layers=[tok2vec, lower, upper], - refs={"tok2vec": tok2vec, "lower": lower, "upper": upper}, - init=init, - attrs={ - "has_upper": has_upper, - "unseen_classes": set(unseen_classes), - "resize_output": resize_output, - }, - ) - - -def forward(model, X, is_train): - step_model = ParserStepModel( - X, - model.layers, - unseen_classes=model.attrs["unseen_classes"], - train=is_train, - has_upper=model.attrs["has_upper"], - ) - - return step_model, step_model.finish_steps - - -def init(model, X=None, Y=None): - model.get_ref("tok2vec").initialize(X=X) - lower = model.get_ref("lower") - lower.initialize() - if model.attrs["has_upper"]: - statevecs = model.ops.alloc2f(2, lower.get_dim("nO")) - model.get_ref("upper").initialize(X=statevecs) diff --git a/spacy/ml/tb_framework.pyx b/spacy/ml/tb_framework.pyx new file mode 100644 index 000000000..79be13b00 --- /dev/null +++ b/spacy/ml/tb_framework.pyx @@ -0,0 +1,621 @@ +# cython: infer_types=True, cdivision=True, boundscheck=False +from typing import List, Tuple, Any, Optional, TypeVar, cast +from libc.string cimport memset, memcpy +from libc.stdlib cimport calloc, free, realloc +from libcpp.vector cimport vector +import numpy +cimport numpy as np +from thinc.api import Model, normal_init, chain, list2array, Linear +from thinc.api import uniform_init, glorot_uniform_init, zero_init +from thinc.api import NumpyOps +from thinc.backends.cblas cimport CBlas, saxpy, sgemm +from thinc.types import Floats1d, Floats2d, Floats3d, Floats4d +from thinc.types import Ints1d, Ints2d + +from ..errors import Errors +from ..pipeline._parser_internals import _beam_utils +from ..pipeline._parser_internals.batch import GreedyBatch +from ..pipeline._parser_internals._parser_utils cimport arg_max +from ..pipeline._parser_internals.transition_system cimport c_transition_batch, c_apply_actions +from ..pipeline._parser_internals.transition_system cimport TransitionSystem +from ..pipeline._parser_internals.stateclass cimport StateC, StateClass +from ..tokens.doc import Doc +from ..util import registry + + +State = Any # TODO + + +@registry.layers("spacy.TransitionModel.v2") +def TransitionModel( + *, + tok2vec: Model[List[Doc], List[Floats2d]], + beam_width: int = 1, + beam_density: float = 0.0, + state_tokens: int, + hidden_width: int, + maxout_pieces: int, + nO: Optional[int] = None, + unseen_classes=set(), +) -> Model[Tuple[List[Doc], TransitionSystem], List[Tuple[State, List[Floats2d]]]]: + """Set up a transition-based parsing model, using a maxout hidden + layer and a linear output layer. + """ + t2v_width = tok2vec.get_dim("nO") if tok2vec.has_dim("nO") else None + tok2vec_projected = chain(tok2vec, list2array(), Linear(hidden_width, t2v_width)) # type: ignore + tok2vec_projected.set_dim("nO", hidden_width) + + # FIXME: we use `output` as a container for the output layer's + # weights and biases. Thinc optimizers cannot handle resizing + # of parameters. So, when the parser model is resized, we + # construct a new `output` layer, which has a different key in + # the optimizer. Once the optimizer supports parameter resizing, + # we can replace the `output` layer by `output_W` and `output_b` + # parameters in this model. + output = Linear(nO=None, nI=hidden_width, init_W=zero_init) + + return Model( + name="parser_model", + forward=forward, + init=init, + layers=[tok2vec_projected, output], + refs={ + "tok2vec": tok2vec_projected, + "output": output, + }, + params={ + "hidden_W": None, # Floats2d W for the hidden layer + "hidden_b": None, # Floats1d bias for the hidden layer + "hidden_pad": None, # Floats1d padding for the hidden layer + }, + dims={ + "nO": None, # Output size + "nP": maxout_pieces, + "nH": hidden_width, + "nI": tok2vec_projected.maybe_get_dim("nO"), + "nF": state_tokens, + }, + attrs={ + "beam_width": beam_width, + "beam_density": beam_density, + "unseen_classes": set(unseen_classes), + "resize_output": resize_output, + }, + ) + + +def resize_output(model: Model, new_nO: int) -> Model: + old_nO = model.maybe_get_dim("nO") + output = model.get_ref("output") + if old_nO is None: + model.set_dim("nO", new_nO) + output.set_dim("nO", new_nO) + output.initialize() + return model + elif new_nO <= old_nO: + return model + elif output.has_param("W"): + nH = model.get_dim("nH") + new_output = Linear(nO=new_nO, nI=nH, init_W=zero_init) + new_output.initialize() + new_W = new_output.get_param("W") + new_b = new_output.get_param("b") + old_W = output.get_param("W") + old_b = output.get_param("b") + new_W[:old_nO] = old_W # type: ignore + new_b[:old_nO] = old_b # type: ignore + for i in range(old_nO, new_nO): + model.attrs["unseen_classes"].add(i) + model.layers[-1] = new_output + model.set_ref("output", new_output) + # TODO: Avoid this private intrusion + model._dims["nO"] = new_nO + return model + + +def init( + model, + X: Optional[Tuple[List[Doc], TransitionSystem]] = None, + Y: Optional[Tuple[List[State], List[Floats2d]]] = None, +): + if X is not None: + docs, moves = X + model.get_ref("tok2vec").initialize(X=docs) + else: + model.get_ref("tok2vec").initialize() + inferred_nO = _infer_nO(Y) + if inferred_nO is not None: + current_nO = model.maybe_get_dim("nO") + if current_nO is None or current_nO != inferred_nO: + model.attrs["resize_output"](model, inferred_nO) + nO = model.get_dim("nO") + nP = model.get_dim("nP") + nH = model.get_dim("nH") + nI = model.get_dim("nI") + nF = model.get_dim("nF") + ops = model.ops + + Wl = ops.alloc2f(nH * nP, nF * nI) + bl = ops.alloc1f(nH * nP) + padl = ops.alloc1f(nI) + # Wl = zero_init(ops, Wl.shape) + Wl = glorot_uniform_init(ops, Wl.shape) + padl = uniform_init(ops, padl.shape) # type: ignore + # TODO: Experiment with whether better to initialize output_W + model.set_param("hidden_W", Wl) + model.set_param("hidden_b", bl) + model.set_param("hidden_pad", padl) + # model = _lsuv_init(model) + return model + + +class TransitionModelInputs: + """ + Input to transition model. + """ + + # dataclass annotation is not yet supported in Cython 0.29.x, + # so, we'll do something close to it. + + actions: Optional[List[Ints1d]] + docs: List[Doc] + max_moves: int + moves: TransitionSystem + states: Optional[List[State]] + + __slots__ = [ + "actions", + "docs", + "max_moves", + "moves", + "states", + ] + + def __init__( + self, + docs: List[Doc], + moves: TransitionSystem, + actions: Optional[List[Ints1d]]=None, + max_moves: int=0, + states: Optional[List[State]]=None): + """ + actions (Optional[List[Ints1d]]): actions to apply for each Doc. + docs (List[Doc]): Docs to predict transition sequences for. + max_moves: (int): the maximum number of moves to apply, values less + than 1 will apply moves to states until they are final states. + moves (TransitionSystem): the transition system to use when predicting + the transition sequences. + states (Optional[List[States]]): the initial states to predict the + transition sequences for. When absent, the initial states are + initialized from the provided Docs. + """ + self.actions = actions + self.docs = docs + self.moves = moves + self.max_moves = max_moves + self.states = states + + +def forward(model, inputs: TransitionModelInputs, is_train: bool): + docs = inputs.docs + moves = inputs.moves + actions = inputs.actions + + beam_width = model.attrs["beam_width"] + hidden_pad = model.get_param("hidden_pad") + tok2vec = model.get_ref("tok2vec") + + states = moves.init_batch(docs) if inputs.states is None else inputs.states + tokvecs, backprop_tok2vec = tok2vec(docs, is_train) + tokvecs = model.ops.xp.vstack((tokvecs, hidden_pad)) + feats, backprop_feats = _forward_precomputable_affine(model, tokvecs, is_train) + seen_mask = _get_seen_mask(model) + + if not is_train and beam_width == 1 and isinstance(model.ops, NumpyOps): + # Note: max_moves is only used during training, so we don't need to + # pass it to the greedy inference path. + return _forward_greedy_cpu(model, moves, states, feats, seen_mask, actions=actions) + else: + return _forward_fallback(model, moves, states, tokvecs, backprop_tok2vec, + feats, backprop_feats, seen_mask, is_train, actions=actions, + max_moves=inputs.max_moves) + + +def _forward_greedy_cpu(model: Model, TransitionSystem moves, states: List[StateClass], np.ndarray feats, + np.ndarray[np.npy_bool, ndim=1] seen_mask, actions: Optional[List[Ints1d]]=None): + cdef vector[StateC*] c_states + cdef StateClass state + for state in states: + if not state.is_final(): + c_states.push_back(state.c) + weights = _get_c_weights(model, feats.data, seen_mask) + # Precomputed features have rows for each token, plus one for padding. + cdef int n_tokens = feats.shape[0] - 1 + sizes = _get_c_sizes(model, c_states.size(), n_tokens) + cdef CBlas cblas = model.ops.cblas() + scores = _parse_batch(cblas, moves, &c_states[0], weights, sizes, actions=actions) + + def backprop(dY): + raise ValueError(Errors.E4004) + + return (states, scores), backprop + +cdef list _parse_batch(CBlas cblas, TransitionSystem moves, StateC** states, + WeightsC weights, SizesC sizes, actions: Optional[List[Ints1d]]=None): + cdef int i, j + cdef vector[StateC *] unfinished + cdef ActivationsC activations = _alloc_activations(sizes) + cdef np.ndarray step_scores + cdef np.ndarray step_actions + + scores = [] + while sizes.states >= 1: + step_scores = numpy.empty((sizes.states, sizes.classes), dtype="f") + step_actions = actions[0] if actions is not None else None + with nogil: + _predict_states(cblas, &activations, step_scores.data, states, &weights, sizes) + if actions is None: + # Validate actions, argmax, take action. + c_transition_batch(moves, states, step_scores.data, sizes.classes, + sizes.states) + else: + c_apply_actions(moves, states, step_actions.data, sizes.states) + for i in range(sizes.states): + if not states[i].is_final(): + unfinished.push_back(states[i]) + for i in range(unfinished.size()): + states[i] = unfinished[i] + sizes.states = unfinished.size() + scores.append(step_scores) + unfinished.clear() + actions = actions[1:] if actions is not None else None + _free_activations(&activations) + + return scores + + +def _forward_fallback( + model: Model, + moves: TransitionSystem, + states: List[StateClass], + tokvecs, backprop_tok2vec, + feats, + backprop_feats, + seen_mask, + is_train: bool, + actions: Optional[List[Ints1d]]=None, + max_moves: int=0): + nF = model.get_dim("nF") + output = model.get_ref("output") + hidden_b = model.get_param("hidden_b") + nH = model.get_dim("nH") + nP = model.get_dim("nP") + + beam_width = model.attrs["beam_width"] + beam_density = model.attrs["beam_density"] + + ops = model.ops + + all_ids = [] + all_which = [] + all_statevecs = [] + all_scores = [] + if beam_width == 1: + batch = GreedyBatch(moves, states, None) + else: + batch = _beam_utils.BeamBatch( + moves, states, None, width=beam_width, density=beam_density + ) + arange = ops.xp.arange(nF) + n_moves = 0 + while not batch.is_done: + ids = numpy.zeros((len(batch.get_unfinished_states()), nF), dtype="i") + for i, state in enumerate(batch.get_unfinished_states()): + state.set_context_tokens(ids, i, nF) + # Sum the state features, add the bias and apply the activation (maxout) + # to create the state vectors. + preacts2f = feats[ids, arange].sum(axis=1) # type: ignore + preacts2f += hidden_b + preacts = ops.reshape3f(preacts2f, preacts2f.shape[0], nH, nP) + assert preacts.shape[0] == len(batch.get_unfinished_states()), preacts.shape + statevecs, which = ops.maxout(preacts) + # We don't use output's backprop, since we want to backprop for + # all states at once, rather than a single state. + scores = output.predict(statevecs) + scores[:, seen_mask] = ops.xp.nanmin(scores) + # Transition the states, filtering out any that are finished. + cpu_scores = ops.to_numpy(scores) + if actions is None: + batch.advance(cpu_scores) + else: + batch.advance_with_actions(actions[0]) + actions = actions[1:] + all_scores.append(scores) + if is_train: + # Remember intermediate results for the backprop. + all_ids.append(ids) + all_statevecs.append(statevecs) + all_which.append(which) + if n_moves >= max_moves >= 1: + break + n_moves += 1 + + def backprop_parser(d_states_d_scores): + ids = ops.xp.vstack(all_ids) + which = ops.xp.vstack(all_which) + statevecs = ops.xp.vstack(all_statevecs) + _, d_scores = d_states_d_scores + if model.attrs.get("unseen_classes"): + # If we have a negative gradient (i.e. the probability should + # increase) on any classes we filtered out as unseen, mark + # them as seen. + for clas in set(model.attrs["unseen_classes"]): + if (d_scores[:, clas] < 0).any(): + model.attrs["unseen_classes"].remove(clas) + d_scores *= seen_mask == False + # Calculate the gradients for the parameters of the output layer. + # The weight gemm is (nS, nO) @ (nS, nH).T + output.inc_grad("b", d_scores.sum(axis=0)) + output.inc_grad("W", ops.gemm(d_scores, statevecs, trans1=True)) + # Now calculate d_statevecs, by backproping through the output linear layer. + # This gemm is (nS, nO) @ (nO, nH) + output_W = output.get_param("W") + d_statevecs = ops.gemm(d_scores, output_W) + # Backprop through the maxout activation + d_preacts = ops.backprop_maxout(d_statevecs, which, nP) + d_preacts2f = ops.reshape2f(d_preacts, d_preacts.shape[0], nH * nP) + model.inc_grad("hidden_b", d_preacts2f.sum(axis=0)) + # We don't need to backprop the summation, because we pass back the IDs instead + d_state_features = backprop_feats((d_preacts2f, ids)) + d_tokvecs = ops.alloc2f(tokvecs.shape[0], tokvecs.shape[1]) + ops.scatter_add(d_tokvecs, ids, d_state_features) + model.inc_grad("hidden_pad", d_tokvecs[-1]) + return (backprop_tok2vec(d_tokvecs[:-1]), None) + + return (list(batch), all_scores), backprop_parser + + +def _get_seen_mask(model: Model) -> numpy.array[bool, 1]: + mask = model.ops.xp.zeros(model.get_dim("nO"), dtype="bool") + for class_ in model.attrs.get("unseen_classes", set()): + mask[class_] = True + return mask + + +def _forward_precomputable_affine(model, X: Floats2d, is_train: bool): + W: Floats2d = model.get_param("hidden_W") + nF = model.get_dim("nF") + nH = model.get_dim("nH") + nP = model.get_dim("nP") + nI = model.get_dim("nI") + # The weights start out (nH * nP, nF * nI). Transpose and reshape to (nF * nH *nP, nI) + W3f = model.ops.reshape3f(W, nH * nP, nF, nI) + W3f = W3f.transpose((1, 0, 2)) + W2f = model.ops.reshape2f(W3f, nF * nH * nP, nI) + assert X.shape == (X.shape[0], nI), X.shape + Yf_ = model.ops.gemm(X, W2f, trans2=True) + Yf = model.ops.reshape3f(Yf_, Yf_.shape[0], nF, nH * nP) + + def backward(dY_ids: Tuple[Floats3d, Ints2d]): + # This backprop is particularly tricky, because we get back a different + # thing from what we put out. We put out an array of shape: + # (nB, nF, nH, nP), and get back: + # (nB, nH, nP) and ids (nB, nF) + # The ids tell us the values of nF, so we would have: + # + # dYf = zeros((nB, nF, nH, nP)) + # for b in range(nB): + # for f in range(nF): + # dYf[b, ids[b, f]] += dY[b] + # + # However, we avoid building that array for efficiency -- and just pass + # in the indices. + dY, ids = dY_ids + dXf = model.ops.gemm(dY, W) + Xf = X[ids].reshape((ids.shape[0], -1)) + dW = model.ops.gemm(dY, Xf, trans1=True) + model.inc_grad("hidden_W", dW) + return model.ops.reshape3f(dXf, dXf.shape[0], nF, nI) + + return Yf, backward + + +def _infer_nO(Y: Optional[Tuple[List[State], List[Floats2d]]]) -> Optional[int]: + if Y is None: + return None + _, scores = Y + if len(scores) == 0: + return None + assert scores[0].shape[0] >= 1 + assert len(scores[0].shape) == 2 + return scores[0].shape[1] + + +def _lsuv_init(model: Model): + """This is like the 'layer sequential unit variance', but instead + of taking the actual inputs, we randomly generate whitened data. + + Why's this all so complicated? We have a huge number of inputs, + and the maxout unit makes guessing the dynamics tricky. Instead + we set the maxout weights to values that empirically result in + whitened outputs given whitened inputs. + """ + W = model.maybe_get_param("hidden_W") + if W is not None and W.any(): + return + + nF = model.get_dim("nF") + nH = model.get_dim("nH") + nP = model.get_dim("nP") + nI = model.get_dim("nI") + W = model.ops.alloc4f(nF, nH, nP, nI) + b = model.ops.alloc2f(nH, nP) + pad = model.ops.alloc4f(1, nF, nH, nP) + + ops = model.ops + W = normal_init(ops, W.shape, mean=float(ops.xp.sqrt(1.0 / nF * nI))) + pad = normal_init(ops, pad.shape, mean=1.0) + model.set_param("W", W) + model.set_param("b", b) + model.set_param("pad", pad) + + ids = ops.alloc_f((5000, nF), dtype="f") + ids += ops.xp.random.uniform(0, 1000, ids.shape) + ids = ops.asarray(ids, dtype="i") + tokvecs = ops.alloc_f((5000, nI), dtype="f") + tokvecs += ops.xp.random.normal(loc=0.0, scale=1.0, size=tokvecs.size).reshape( + tokvecs.shape + ) + + def predict(ids, tokvecs): + # nS ids. nW tokvecs. Exclude the padding array. + hiddens, _ = _forward_precomputable_affine(model, tokvecs[:-1], False) + vectors = model.ops.alloc2f(ids.shape[0], nH * nP) + # need nS vectors + hiddens = hiddens.reshape((hiddens.shape[0] * nF, nH * nP)) + model.ops.scatter_add(vectors, ids.flatten(), hiddens) + vectors3f = model.ops.reshape3f(vectors, vectors.shape[0], nH, nP) + vectors3f += b + return model.ops.maxout(vectors3f)[0] + + tol_var = 0.01 + tol_mean = 0.01 + t_max = 10 + W = cast(Floats4d, model.get_param("hidden_W").copy()) + b = cast(Floats2d, model.get_param("hidden_b").copy()) + for t_i in range(t_max): + acts1 = predict(ids, tokvecs) + var = model.ops.xp.var(acts1) + mean = model.ops.xp.mean(acts1) + if abs(var - 1.0) >= tol_var: + W /= model.ops.xp.sqrt(var) + model.set_param("hidden_W", W) + elif abs(mean) >= tol_mean: + b -= mean + model.set_param("hidden_b", b) + else: + break + return model + + +cdef WeightsC _get_c_weights(model, const float* feats, np.ndarray[np.npy_bool, ndim=1] seen_mask) except *: + output = model.get_ref("output") + cdef np.ndarray hidden_b = model.get_param("hidden_b") + cdef np.ndarray output_W = output.get_param("W") + cdef np.ndarray output_b = output.get_param("b") + + cdef WeightsC weights + weights.feat_weights = feats + weights.feat_bias = hidden_b.data + weights.hidden_weights = output_W.data + weights.hidden_bias = output_b.data + weights.seen_mask = seen_mask.data + + return weights + + +cdef SizesC _get_c_sizes(model, int batch_size, int tokens) except *: + cdef SizesC sizes + sizes.states = batch_size + sizes.classes = model.get_dim("nO") + sizes.hiddens = model.get_dim("nH") + sizes.pieces = model.get_dim("nP") + sizes.feats = model.get_dim("nF") + sizes.embed_width = model.get_dim("nI") + sizes.tokens = tokens + return sizes + + +cdef ActivationsC _alloc_activations(SizesC n) nogil: + cdef ActivationsC A + memset(&A, 0, sizeof(A)) + _resize_activations(&A, n) + return A + + +cdef void _free_activations(const ActivationsC* A) nogil: + free(A.token_ids) + free(A.unmaxed) + free(A.hiddens) + free(A.is_valid) + + +cdef void _resize_activations(ActivationsC* A, SizesC n) nogil: + if n.states <= A._max_size: + A._curr_size = n.states + return + if A._max_size == 0: + A.token_ids = calloc(n.states * n.feats, sizeof(A.token_ids[0])) + A.unmaxed = calloc(n.states * n.hiddens * n.pieces, sizeof(A.unmaxed[0])) + A.hiddens = calloc(n.states * n.hiddens, sizeof(A.hiddens[0])) + A.is_valid = calloc(n.states * n.classes, sizeof(A.is_valid[0])) + A._max_size = n.states + else: + A.token_ids = realloc(A.token_ids, + n.states * n.feats * sizeof(A.token_ids[0])) + A.unmaxed = realloc(A.unmaxed, + n.states * n.hiddens * n.pieces * sizeof(A.unmaxed[0])) + A.hiddens = realloc(A.hiddens, + n.states * n.hiddens * sizeof(A.hiddens[0])) + A.is_valid = realloc(A.is_valid, + n.states * n.classes * sizeof(A.is_valid[0])) + A._max_size = n.states + A._curr_size = n.states + + +cdef void _predict_states(CBlas cblas, ActivationsC* A, float* scores, StateC** states, const WeightsC* W, SizesC n) nogil: + _resize_activations(A, n) + for i in range(n.states): + states[i].set_context_tokens(&A.token_ids[i*n.feats], n.feats) + memset(A.unmaxed, 0, n.states * n.hiddens * n.pieces * sizeof(float)) + _sum_state_features(cblas, A.unmaxed, W.feat_weights, A.token_ids, n) + for i in range(n.states): + saxpy(cblas)(n.hiddens * n.pieces, 1., W.feat_bias, 1, &A.unmaxed[i*n.hiddens*n.pieces], 1) + for j in range(n.hiddens): + index = i * n.hiddens * n.pieces + j * n.pieces + which = arg_max(&A.unmaxed[index], n.pieces) + A.hiddens[i*n.hiddens + j] = A.unmaxed[index + which] + if W.hidden_weights == NULL: + memcpy(scores, A.hiddens, n.states * n.classes * sizeof(float)) + else: + # Compute hidden-to-output + sgemm(cblas)(False, True, n.states, n.classes, n.hiddens, + 1.0, A.hiddens, n.hiddens, + W.hidden_weights, n.hiddens, + 0.0, scores, n.classes) + # Add bias + for i in range(n.states): + saxpy(cblas)(n.classes, 1., W.hidden_bias, 1, &scores[i*n.classes], 1) + # Set unseen classes to minimum value + i = 0 + min_ = scores[0] + for i in range(1, n.states * n.classes): + if scores[i] < min_: + min_ = scores[i] + for i in range(n.states): + for j in range(n.classes): + if W.seen_mask[j]: + scores[i*n.classes+j] = min_ + + +cdef void _sum_state_features(CBlas cblas, float* output, + const float* cached, const int* token_ids, SizesC n) nogil: + cdef int idx, b, f, i + cdef const float* feature + cdef int B = n.states + cdef int O = n.hiddens * n.pieces + cdef int F = n.feats + cdef int T = n.tokens + padding = cached + (T * F * O) + cdef int id_stride = F*O + cdef float one = 1. + for b in range(B): + for f in range(F): + if token_ids[f] < 0: + feature = &padding[f*O] + else: + idx = token_ids[f] * id_stride + f*O + feature = &cached[idx] + saxpy(cblas)(O, one, feature, 1, &output[b*O], 1) + token_ids += F + diff --git a/spacy/pipeline/_parser_internals/_beam_utils.pyx b/spacy/pipeline/_parser_internals/_beam_utils.pyx index 610c8ddee..d07c13aeb 100644 --- a/spacy/pipeline/_parser_internals/_beam_utils.pyx +++ b/spacy/pipeline/_parser_internals/_beam_utils.pyx @@ -7,6 +7,7 @@ from cpython.ref cimport PyObject, Py_XDECREF from ...typedefs cimport hash_t, class_t from .transition_system cimport TransitionSystem, Transition from ...errors import Errors +from .batch cimport Batch from .search cimport Beam, MaxViolation from .search import MaxViolation from .stateclass cimport StateC, StateClass @@ -26,7 +27,7 @@ cdef int check_final_state(void* _state, void* extra_args) except -1: return state.is_final() -cdef class BeamBatch(object): +cdef class BeamBatch(Batch): cdef public TransitionSystem moves cdef public object states cdef public object docs diff --git a/spacy/pipeline/_parser_internals/_parser_utils.pxd b/spacy/pipeline/_parser_internals/_parser_utils.pxd new file mode 100644 index 000000000..7fee05bad --- /dev/null +++ b/spacy/pipeline/_parser_internals/_parser_utils.pxd @@ -0,0 +1,2 @@ +cdef int arg_max(const float* scores, const int n_classes) nogil +cdef int arg_max_if_valid(const float* scores, const int* is_valid, int n) nogil diff --git a/spacy/pipeline/_parser_internals/_parser_utils.pyx b/spacy/pipeline/_parser_internals/_parser_utils.pyx new file mode 100644 index 000000000..582756bf5 --- /dev/null +++ b/spacy/pipeline/_parser_internals/_parser_utils.pyx @@ -0,0 +1,22 @@ +# cython: infer_types=True + +cdef inline int arg_max(const float* scores, const int n_classes) nogil: + if n_classes == 2: + return 0 if scores[0] > scores[1] else 1 + cdef int i + cdef int best = 0 + cdef float mode = scores[0] + for i in range(1, n_classes): + if scores[i] > mode: + mode = scores[i] + best = i + return best + + +cdef inline int arg_max_if_valid(const float* scores, const int* is_valid, int n) nogil: + cdef int best = -1 + for i in range(n): + if is_valid[i] >= 1: + if best == -1 or scores[i] > scores[best]: + best = i + return best diff --git a/spacy/pipeline/_parser_internals/_state.pxd b/spacy/pipeline/_parser_internals/_state.pxd index a1262bb61..bd5d5208c 100644 --- a/spacy/pipeline/_parser_internals/_state.pxd +++ b/spacy/pipeline/_parser_internals/_state.pxd @@ -6,7 +6,6 @@ cimport libcpp from libcpp.unordered_map cimport unordered_map from libcpp.vector cimport vector from libcpp.set cimport set -from cpython.exc cimport PyErr_CheckSignals, PyErr_SetFromErrno from murmurhash.mrmr cimport hash64 from ...vocab cimport EMPTY_LEXEME @@ -26,7 +25,7 @@ cdef struct ArcC: cdef cppclass StateC: - int* _heads + vector[int] _heads const TokenC* _sent vector[int] _stack vector[int] _rebuffer @@ -34,31 +33,34 @@ cdef cppclass StateC: unordered_map[int, vector[ArcC]] _left_arcs unordered_map[int, vector[ArcC]] _right_arcs vector[libcpp.bool] _unshiftable + vector[int] history set[int] _sent_starts TokenC _empty_token int length int offset int _b_i - __init__(const TokenC* sent, int length) nogil: + __init__(const TokenC* sent, int length) nogil except +: + this._heads.resize(length, -1) + this._unshiftable.resize(length, False) + + # Reserve memory ahead of time to minimize allocations during parsing. + # The initial capacity set here ideally reflects the expected average-case/majority usage. + cdef int init_capacity = 32 + this._stack.reserve(init_capacity) + this._rebuffer.reserve(init_capacity) + this._ents.reserve(init_capacity) + this._left_arcs.reserve(init_capacity) + this._right_arcs.reserve(init_capacity) + this.history.reserve(init_capacity) + this._sent = sent - this._heads = calloc(length, sizeof(int)) - if not (this._sent and this._heads): - with gil: - PyErr_SetFromErrno(MemoryError) - PyErr_CheckSignals() this.offset = 0 this.length = length this._b_i = 0 - for i in range(length): - this._heads[i] = -1 - this._unshiftable.push_back(0) memset(&this._empty_token, 0, sizeof(TokenC)) this._empty_token.lex = &EMPTY_LEXEME - __dealloc__(): - free(this._heads) - void set_context_tokens(int* ids, int n) nogil: cdef int i, j if n == 1: @@ -131,19 +133,20 @@ cdef cppclass StateC: ids[i] = -1 int S(int i) nogil const: - if i >= this._stack.size(): + cdef int stack_size = this._stack.size() + if i >= stack_size or i < 0: return -1 - elif i < 0: - return -1 - return this._stack.at(this._stack.size() - (i+1)) + else: + return this._stack[stack_size - (i+1)] int B(int i) nogil const: + cdef int buf_size = this._rebuffer.size() if i < 0: return -1 - elif i < this._rebuffer.size(): - return this._rebuffer.at(this._rebuffer.size() - (i+1)) + elif i < buf_size: + return this._rebuffer[buf_size - (i+1)] else: - b_i = this._b_i + (i - this._rebuffer.size()) + b_i = this._b_i + (i - buf_size) if b_i >= this.length: return -1 else: @@ -242,7 +245,7 @@ cdef cppclass StateC: return 0 elif this._sent[word].sent_start == 1: return 1 - elif this._sent_starts.count(word) >= 1: + elif this._sent_starts.const_find(word) != this._sent_starts.const_end(): return 1 else: return 0 @@ -327,7 +330,7 @@ cdef cppclass StateC: if item >= this._unshiftable.size(): return 0 else: - return this._unshiftable.at(item) + return this._unshiftable[item] void set_reshiftable(int item) nogil: if item < this._unshiftable.size(): @@ -347,6 +350,9 @@ cdef cppclass StateC: this._heads[child] = head void map_del_arc(unordered_map[int, vector[ArcC]]* heads_arcs, int h_i, int c_i) nogil: + cdef vector[ArcC]* arcs + cdef ArcC* arc + arcs_it = heads_arcs.find(h_i) if arcs_it == heads_arcs.end(): return @@ -355,12 +361,12 @@ cdef cppclass StateC: if arcs.size() == 0: return - arc = arcs.back() + arc = &arcs.back() if arc.head == h_i and arc.child == c_i: arcs.pop_back() else: for i in range(arcs.size()-1): - arc = arcs.at(i) + arc = &deref(arcs)[i] if arc.head == h_i and arc.child == c_i: arc.head = -1 arc.child = -1 @@ -400,10 +406,11 @@ cdef cppclass StateC: this._rebuffer = src._rebuffer this._sent_starts = src._sent_starts this._unshiftable = src._unshiftable - memcpy(this._heads, src._heads, this.length * sizeof(this._heads[0])) + this._heads = src._heads this._ents = src._ents this._left_arcs = src._left_arcs this._right_arcs = src._right_arcs this._b_i = src._b_i this.offset = src.offset this._empty_token = src._empty_token + this.history = src.history diff --git a/spacy/pipeline/_parser_internals/arc_eager.pyx b/spacy/pipeline/_parser_internals/arc_eager.pyx index a79aef64a..9c358475a 100644 --- a/spacy/pipeline/_parser_internals/arc_eager.pyx +++ b/spacy/pipeline/_parser_internals/arc_eager.pyx @@ -773,6 +773,8 @@ cdef class ArcEager(TransitionSystem): return list(arcs) def has_gold(self, Example eg, start=0, end=None): + if end is not None and end < 0: + end = None for word in eg.y[start:end]: if word.dep != 0: return True @@ -858,6 +860,7 @@ cdef class ArcEager(TransitionSystem): state.print_state() ))) action.do(state.c, action.label) + state.c.history.push_back(i) break else: failed = False diff --git a/spacy/pipeline/_parser_internals/batch.pxd b/spacy/pipeline/_parser_internals/batch.pxd new file mode 100644 index 000000000..60734e549 --- /dev/null +++ b/spacy/pipeline/_parser_internals/batch.pxd @@ -0,0 +1,2 @@ +cdef class Batch: + pass diff --git a/spacy/pipeline/_parser_internals/batch.pyx b/spacy/pipeline/_parser_internals/batch.pyx new file mode 100644 index 000000000..91073b52e --- /dev/null +++ b/spacy/pipeline/_parser_internals/batch.pyx @@ -0,0 +1,52 @@ +from typing import Any + +TransitionSystem = Any # TODO + +cdef class Batch: + def advance(self, scores): + raise NotImplementedError + + def get_states(self): + raise NotImplementedError + + @property + def is_done(self): + raise NotImplementedError + + def get_unfinished_states(self): + raise NotImplementedError + + def __getitem__(self, i): + raise NotImplementedError + + def __len__(self): + raise NotImplementedError + + +class GreedyBatch(Batch): + def __init__(self, moves: TransitionSystem, states, golds): + self._moves = moves + self._states = states + self._next_states = [s for s in states if not s.is_final()] + + def advance(self, scores): + self._next_states = self._moves.transition_states(self._next_states, scores) + + def advance_with_actions(self, actions): + self._next_states = self._moves.apply_actions(self._next_states, actions) + + def get_states(self): + return self._states + + @property + def is_done(self): + return all(s.is_final() for s in self._states) + + def get_unfinished_states(self): + return [st for st in self._states if not st.is_final()] + + def __getitem__(self, i): + return self._states[i] + + def __len__(self): + return len(self._states) diff --git a/spacy/pipeline/_parser_internals/ner.pyx b/spacy/pipeline/_parser_internals/ner.pyx index 53ed03523..d4d564dc7 100644 --- a/spacy/pipeline/_parser_internals/ner.pyx +++ b/spacy/pipeline/_parser_internals/ner.pyx @@ -156,7 +156,7 @@ cdef class BiluoPushDown(TransitionSystem): if token.ent_type: labels.add(token.ent_type_) return labels - + def move_name(self, int move, attr_t label): if move == OUT: return 'O' @@ -306,6 +306,8 @@ cdef class BiluoPushDown(TransitionSystem): for span in eg.y.spans.get(neg_key, []): if span.start >= start and span.end <= end: return True + if end is not None and end < 0: + end = None for word in eg.y[start:end]: if word.ent_iob != 0: return True @@ -646,7 +648,7 @@ cdef class Unit: cost += 1 break return cost - + cdef class Out: diff --git a/spacy/pipeline/_parser_internals/stateclass.pyx b/spacy/pipeline/_parser_internals/stateclass.pyx index 4eaddd997..dbd22117e 100644 --- a/spacy/pipeline/_parser_internals/stateclass.pyx +++ b/spacy/pipeline/_parser_internals/stateclass.pyx @@ -20,6 +20,10 @@ cdef class StateClass: if self._borrowed != 1: del self.c + @property + def history(self): + return list(self.c.history) + @property def stack(self): return [self.S(i) for i in range(self.c.stack_depth())] @@ -176,3 +180,6 @@ cdef class StateClass: def clone(self, StateClass src): self.c.clone(src.c) + + def set_context_tokens(self, int[:, :] output, int row, int n_feats): + self.c.set_context_tokens(&output[row, 0], n_feats) diff --git a/spacy/pipeline/_parser_internals/transition_system.pxd b/spacy/pipeline/_parser_internals/transition_system.pxd index 52ebd2b8e..c8ebd8b27 100644 --- a/spacy/pipeline/_parser_internals/transition_system.pxd +++ b/spacy/pipeline/_parser_internals/transition_system.pxd @@ -53,3 +53,10 @@ cdef class TransitionSystem: cdef int set_costs(self, int* is_valid, weight_t* costs, const StateC* state, gold) except -1 + + +cdef void c_apply_actions(TransitionSystem moves, StateC** states, const int* actions, + int batch_size) nogil + +cdef void c_transition_batch(TransitionSystem moves, StateC** states, const float* scores, + int nr_class, int batch_size) nogil diff --git a/spacy/pipeline/_parser_internals/transition_system.pyx b/spacy/pipeline/_parser_internals/transition_system.pyx index 18eb745a9..89f9e8ae8 100644 --- a/spacy/pipeline/_parser_internals/transition_system.pyx +++ b/spacy/pipeline/_parser_internals/transition_system.pyx @@ -1,6 +1,8 @@ # cython: infer_types=True from __future__ import print_function from cymem.cymem cimport Pool +from libc.stdlib cimport calloc, free +from libcpp.vector cimport vector from collections import Counter import srsly @@ -10,6 +12,7 @@ from ...typedefs cimport weight_t, attr_t from ...tokens.doc cimport Doc from ...structs cimport TokenC from .stateclass cimport StateClass +from ._parser_utils cimport arg_max_if_valid from ...errors import Errors from ... import util @@ -73,7 +76,18 @@ cdef class TransitionSystem: offset += len(doc) return states + def follow_history(self, doc, history): + cdef int clas + cdef StateClass state = StateClass(doc) + for clas in history: + action = self.c[clas] + action.do(state.c, action.label) + state.c.history.push_back(clas) + return state + def get_oracle_sequence(self, Example example, _debug=False): + if not self.has_gold(example): + return [] states, golds, _ = self.init_gold_batch([example]) if not states: return [] @@ -85,6 +99,8 @@ cdef class TransitionSystem: return self.get_oracle_sequence_from_state(state, gold) def get_oracle_sequence_from_state(self, StateClass state, gold, _debug=None): + if state.is_final(): + return [] cdef Pool mem = Pool() # n_moves should not be zero at this point, but make sure to avoid zero-length mem alloc assert self.n_moves > 0 @@ -110,6 +126,7 @@ cdef class TransitionSystem: "S0 head?", str(state.has_head(state.S(0))), ))) action.do(state.c, action.label) + state.c.history.push_back(i) break else: if _debug: @@ -137,6 +154,28 @@ cdef class TransitionSystem: raise ValueError(Errors.E170.format(name=name)) action = self.lookup_transition(name) action.do(state.c, action.label) + state.c.history.push_back(action.clas) + + def apply_actions(self, states, const int[::1] actions): + assert len(states) == actions.shape[0] + cdef StateClass state + cdef vector[StateC*] c_states + c_states.resize(len(states)) + cdef int i + for (i, state) in enumerate(states): + c_states[i] = state.c + c_apply_actions(self, &c_states[0], &actions[0], actions.shape[0]) + return [state for state in states if not state.c.is_final()] + + def transition_states(self, states, float[:, ::1] scores): + assert len(states) == scores.shape[0] + cdef StateClass state + cdef float* c_scores = &scores[0, 0] + cdef vector[StateC*] c_states + for state in states: + c_states.push_back(state.c) + c_transition_batch(self, &c_states[0], c_scores, scores.shape[1], scores.shape[0]) + return [state for state in states if not state.c.is_final()] cdef Transition lookup_transition(self, object name) except *: raise NotImplementedError @@ -250,3 +289,35 @@ cdef class TransitionSystem: self.cfg.update(msg['cfg']) self.initialize_actions(labels) return self + + +cdef void c_apply_actions(TransitionSystem moves, StateC** states, const int* actions, + int batch_size) nogil: + cdef int i + cdef Transition action + cdef StateC* state + for i in range(batch_size): + state = states[i] + action = moves.c[actions[i]] + action.do(state, action.label) + state.history.push_back(action.clas) + + +cdef void c_transition_batch(TransitionSystem moves, StateC** states, const float* scores, + int nr_class, int batch_size) nogil: + is_valid = calloc(moves.n_moves, sizeof(int)) + cdef int i, guess + cdef Transition action + for i in range(batch_size): + moves.set_valid(is_valid, states[i]) + guess = arg_max_if_valid(&scores[i*nr_class], is_valid, nr_class) + if guess == -1: + # This shouldn't happen, but it's hard to raise an error here, + # and we don't want to infinite loop. So, force to end state. + states[i].force_final() + else: + action = moves.c[guess] + action.do(states[i], action.label) + states[i].history.push_back(guess) + free(is_valid) + diff --git a/spacy/pipeline/dep_parser.pyx b/spacy/pipeline/dep_parser.py similarity index 97% rename from spacy/pipeline/dep_parser.pyx rename to spacy/pipeline/dep_parser.py index e5f686158..f6689e017 100644 --- a/spacy/pipeline/dep_parser.pyx +++ b/spacy/pipeline/dep_parser.py @@ -4,8 +4,8 @@ from typing import Optional, Iterable, Callable from thinc.api import Model, Config from ._parser_internals.transition_system import TransitionSystem -from .transition_parser cimport Parser -from ._parser_internals.arc_eager cimport ArcEager +from .transition_parser import Parser +from ._parser_internals.arc_eager import ArcEager from .functions import merge_subtokens from ..language import Language @@ -18,12 +18,11 @@ from ..util import registry default_model_config = """ [model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "parser" extra_state_tokens = false hidden_width = 64 maxout_pieces = 2 -use_upper = true [model.tok2vec] @architectures = "spacy.HashEmbedCNN.v2" @@ -123,6 +122,7 @@ def make_parser( scorer=scorer, ) + @Language.factory( "beam_parser", assigns=["token.dep", "token.head", "token.is_sent_start", "doc.sents"], @@ -228,6 +228,7 @@ def parser_score(examples, **kwargs): DOCS: https://spacy.io/api/dependencyparser#score """ + def has_sents(doc): return doc.has_annotation("SENT_START") @@ -235,8 +236,11 @@ def parser_score(examples, **kwargs): dep = getattr(token, attr) dep = token.vocab.strings.as_string(dep).lower() return dep + results = {} - results.update(Scorer.score_spans(examples, "sents", has_annotation=has_sents, **kwargs)) + results.update( + Scorer.score_spans(examples, "sents", has_annotation=has_sents, **kwargs) + ) kwargs.setdefault("getter", dep_getter) kwargs.setdefault("ignore_labels", ("p", "punct")) results.update(Scorer.score_deps(examples, "dep", **kwargs)) @@ -249,11 +253,12 @@ def make_parser_scorer(): return parser_score -cdef class DependencyParser(Parser): +class DependencyParser(Parser): """Pipeline component for dependency parsing. DOCS: https://spacy.io/api/dependencyparser """ + TransitionSystem = ArcEager def __init__( @@ -273,8 +278,7 @@ cdef class DependencyParser(Parser): incorrect_spans_key=None, scorer=parser_score, ): - """Create a DependencyParser. - """ + """Create a DependencyParser.""" super().__init__( vocab, model, diff --git a/spacy/pipeline/ner.pyx b/spacy/pipeline/ner.py similarity index 94% rename from spacy/pipeline/ner.pyx rename to spacy/pipeline/ner.py index 25f48c9f8..651a0b3e3 100644 --- a/spacy/pipeline/ner.pyx +++ b/spacy/pipeline/ner.py @@ -4,22 +4,22 @@ from typing import Optional, Iterable, Callable from thinc.api import Model, Config from ._parser_internals.transition_system import TransitionSystem -from .transition_parser cimport Parser -from ._parser_internals.ner cimport BiluoPushDown +from .transition_parser import Parser +from ._parser_internals.ner import BiluoPushDown from ..language import Language from ..scorer import get_ner_prf, PRFScore +from ..training import validate_examples from ..util import registry from ..training import remove_bilu_prefix default_model_config = """ [model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "ner" extra_state_tokens = false hidden_width = 64 maxout_pieces = 2 -use_upper = true [model.tok2vec] @architectures = "spacy.HashEmbedCNN.v2" @@ -44,8 +44,12 @@ DEFAULT_NER_MODEL = Config().from_str(default_model_config)["model"] "incorrect_spans_key": None, "scorer": {"@scorers": "spacy.ner_scorer.v1"}, }, - default_score_weights={"ents_f": 1.0, "ents_p": 0.0, "ents_r": 0.0, "ents_per_type": None}, - + default_score_weights={ + "ents_f": 1.0, + "ents_p": 0.0, + "ents_r": 0.0, + "ents_per_type": None, + }, ) def make_ner( nlp: Language, @@ -98,6 +102,7 @@ def make_ner( scorer=scorer, ) + @Language.factory( "beam_ner", assigns=["doc.ents", "token.ent_iob", "token.ent_type"], @@ -111,7 +116,12 @@ def make_ner( "incorrect_spans_key": None, "scorer": None, }, - default_score_weights={"ents_f": 1.0, "ents_p": 0.0, "ents_r": 0.0, "ents_per_type": None}, + default_score_weights={ + "ents_f": 1.0, + "ents_p": 0.0, + "ents_r": 0.0, + "ents_per_type": None, + }, ) def make_beam_ner( nlp: Language, @@ -185,11 +195,12 @@ def make_ner_scorer(): return ner_score -cdef class EntityRecognizer(Parser): +class EntityRecognizer(Parser): """Pipeline component for named entity recognition. DOCS: https://spacy.io/api/entityrecognizer """ + TransitionSystem = BiluoPushDown def __init__( @@ -207,15 +218,14 @@ cdef class EntityRecognizer(Parser): incorrect_spans_key=None, scorer=ner_score, ): - """Create an EntityRecognizer. - """ + """Create an EntityRecognizer.""" super().__init__( vocab, model, name, moves, update_with_oracle_cut_size=update_with_oracle_cut_size, - min_action_freq=1, # not relevant for NER + min_action_freq=1, # not relevant for NER learn_tokens=False, # not relevant for NER beam_width=beam_width, beam_density=beam_density, diff --git a/spacy/pipeline/transition_parser.pxd b/spacy/pipeline/transition_parser.pxd deleted file mode 100644 index f20e69a6e..000000000 --- a/spacy/pipeline/transition_parser.pxd +++ /dev/null @@ -1,21 +0,0 @@ -from cymem.cymem cimport Pool -from thinc.backends.cblas cimport CBlas - -from ..vocab cimport Vocab -from .trainable_pipe cimport TrainablePipe -from ._parser_internals.transition_system cimport Transition, TransitionSystem -from ._parser_internals._state cimport StateC -from ..ml.parser_model cimport WeightsC, ActivationsC, SizesC - - -cdef class Parser(TrainablePipe): - cdef public object _rehearsal_model - cdef readonly TransitionSystem moves - cdef public object _multitasks - cdef object _cpu_ops - - cdef void _parseC(self, CBlas cblas, StateC** states, - WeightsC weights, SizesC sizes) nogil - - cdef void c_transition_batch(self, StateC** states, const float* scores, - int nr_class, int batch_size) nogil diff --git a/spacy/pipeline/transition_parser.pyx b/spacy/pipeline/transition_parser.pyx index b0b3a0b96..a2b6c167f 100644 --- a/spacy/pipeline/transition_parser.pyx +++ b/spacy/pipeline/transition_parser.pyx @@ -8,26 +8,27 @@ from libcpp.vector cimport vector from libc.string cimport memset, memcpy from libc.stdlib cimport calloc, free import random +import contextlib import srsly from thinc.api import get_ops, set_dropout_rate, CupyOps, NumpyOps, Optimizer -from thinc.api import chain, softmax_activation, use_ops +from thinc.api import chain, softmax_activation, use_ops, get_array_module from thinc.legacy import LegacySequenceCategoricalCrossentropy -from thinc.types import Floats2d +from thinc.types import Floats2d, Ints1d import numpy.random import numpy import warnings -from ._parser_internals.stateclass cimport StateClass +from ..ml.tb_framework import TransitionModelInputs +from ._parser_internals.stateclass cimport StateC, StateClass from ._parser_internals.search cimport Beam -from ..ml.parser_model cimport alloc_activations, free_activations -from ..ml.parser_model cimport predict_states, arg_max_if_valid -from ..ml.parser_model cimport WeightsC, ActivationsC, SizesC, cpu_log_loss -from ..ml.parser_model cimport get_c_weights, get_c_sizes from ..tokens.doc cimport Doc -from .trainable_pipe import TrainablePipe +from .trainable_pipe cimport TrainablePipe from ._parser_internals cimport _beam_utils from ._parser_internals import _beam_utils +from ..vocab cimport Vocab +from ._parser_internals.transition_system cimport Transition, TransitionSystem +from ..typedefs cimport weight_t from ..training import validate_examples, validate_get_examples from ..training import validate_distillation_examples @@ -38,7 +39,7 @@ from .. import util NUMPY_OPS = NumpyOps() -cdef class Parser(TrainablePipe): +class Parser(TrainablePipe): """ Base class of the DependencyParser and EntityRecognizer. """ @@ -138,8 +139,9 @@ cdef class Parser(TrainablePipe): @property def move_names(self): names = [] + cdef TransitionSystem moves = self.moves for i in range(self.moves.n_moves): - name = self.moves.move_name(self.moves.c[i].move, self.moves.c[i].label) + name = self.moves.move_name(moves.c[i].move, moves.c[i].label) # Explicitly removing the internal "U-" token used for blocking entities if name != "U-": names.append(name) @@ -245,15 +247,6 @@ cdef class Parser(TrainablePipe): student_docs = [eg.predicted for eg in examples] - teacher_step_model = teacher_pipe.model.predict([eg.reference for eg in examples]) - student_step_model, backprop_tok2vec = self.model.begin_update(student_docs) - - # Add softmax activation, so that we can compute student losses - # with cross-entropy loss. - with use_ops("numpy"): - teacher_model = chain(teacher_step_model, softmax_activation()) - student_model = chain(student_step_model, softmax_activation()) - max_moves = self.cfg["update_with_oracle_cut_size"] if max_moves >= 1: # Chop sequences into lengths of this many words, to make the @@ -261,51 +254,39 @@ cdef class Parser(TrainablePipe): # sequence, we use the teacher's predictions as the gold # standard. max_moves = int(random.uniform(max_moves // 2, max_moves * 2)) - states = self._init_batch(teacher_step_model, student_docs, max_moves) + states = self._init_batch(teacher_pipe, student_docs, max_moves) else: states = self.moves.init_batch(student_docs) - loss = 0.0 - n_moves = 0 - while states: - # We do distillation as follows: (1) for every state, we compute the - # transition softmax distributions: (2) we backpropagate the error of - # the student (compared to the teacher) into the student model; (3) - # for all states, we move to the next state using the student's - # predictions. - teacher_scores = teacher_model.predict(states) - student_scores, backprop = student_model.begin_update(states) - state_loss, d_scores = self.get_teacher_student_loss(teacher_scores, student_scores) - backprop(d_scores) - loss += state_loss - self.transition_states(states, student_scores) - states = [state for state in states if not state.is_final()] + # We distill as follows: 1. we first let the student predict transition + # sequences (and the corresponding transition probabilities); (2) we + # let the teacher follow the student's predicted transition sequences + # to obtain the teacher's transition probabilities; (3) we compute the + # gradients of the student's transition distributions relative to the + # teacher's distributions. - # Stop when we reach the maximum number of moves, otherwise we start - # to process the remainder of cut sequences again. - if max_moves >= 1 and n_moves >= max_moves: - break - n_moves += 1 + student_inputs = TransitionModelInputs(docs=student_docs, moves=self.moves, + max_moves=max_moves) + (student_states, student_scores), backprop_scores = self.model.begin_update(student_inputs) + actions = states2actions(student_states) + teacher_inputs = TransitionModelInputs(docs=[eg.reference for eg in examples], + moves=self.moves, actions=actions) + (_, teacher_scores) = teacher_pipe.model.predict(teacher_inputs) - backprop_tok2vec(student_docs) + loss, d_scores = self.get_teacher_student_loss(teacher_scores, student_scores) + backprop_scores((student_states, d_scores)) if sgd is not None: self.finish_update(sgd) losses[self.name] += loss - del backprop - del backprop_tok2vec - teacher_step_model.clear_memory() - student_step_model.clear_memory() - del teacher_model - del student_model - return losses def get_teacher_student_loss( - self, teacher_scores: List[Floats2d], student_scores: List[Floats2d] + self, teacher_scores: List[Floats2d], student_scores: List[Floats2d], + normalize: bool=False, ) -> Tuple[float, List[Floats2d]]: """Calculate the loss and its gradient for a batch of student scores, relative to teacher scores. @@ -317,10 +298,28 @@ cdef class Parser(TrainablePipe): DOCS: https://spacy.io/api/dependencyparser#get_teacher_student_loss """ - loss_func = LegacySequenceCategoricalCrossentropy(normalize=False) - d_scores, loss = loss_func(student_scores, teacher_scores) - if self.model.ops.xp.isnan(loss): - raise ValueError(Errors.E910.format(name=self.name)) + + # We can't easily hook up a softmax layer in the parsing model, since + # the get_loss does additional masking. So, we could apply softmax + # manually here and use Thinc's cross-entropy loss. But it's a bit + # suboptimal, since we can have a lot of states that would result in + # many kernel launches. Futhermore the parsing model's backprop expects + # a XP array, so we'd have to concat the softmaxes anyway. So, like + # the get_loss implementation, we'll compute the loss and gradients + # ourselves. + + teacher_scores = self.model.ops.softmax(self.model.ops.xp.vstack(teacher_scores), + axis=-1, inplace=True) + student_scores = self.model.ops.softmax(self.model.ops.xp.vstack(student_scores), + axis=-1, inplace=True) + + assert teacher_scores.shape == student_scores.shape + + d_scores = student_scores - teacher_scores + if normalize: + d_scores /= d_scores.shape[0] + loss = (d_scores**2).sum() / d_scores.size + return float(loss), d_scores def init_multitask_objectives(self, get_examples, pipeline, **cfg): @@ -343,9 +342,6 @@ cdef class Parser(TrainablePipe): stream: The sequence of documents to process. batch_size (int): Number of documents to accumulate into a working set. - error_handler (Callable[[str, List[Doc], Exception], Any]): Function that - deals with a failing batch of documents. The default function just reraises - the exception. YIELDS (Doc): Documents, in order. """ @@ -367,78 +363,29 @@ cdef class Parser(TrainablePipe): def predict(self, docs): if isinstance(docs, Doc): docs = [docs] + self._ensure_labels_are_added(docs) if not any(len(doc) for doc in docs): result = self.moves.init_batch(docs) return result - if self.cfg["beam_width"] == 1: - return self.greedy_parse(docs, drop=0.0) - else: - return self.beam_parse( - docs, - drop=0.0, - beam_width=self.cfg["beam_width"], - beam_density=self.cfg["beam_density"] - ) + with _change_attrs(self.model, beam_width=self.cfg["beam_width"], beam_density=self.cfg["beam_density"]): + inputs = TransitionModelInputs(docs=docs, moves=self.moves) + states_or_beams, _ = self.model.predict(inputs) + return states_or_beams def greedy_parse(self, docs, drop=0.): - cdef vector[StateC*] states - cdef StateClass state - cdef CBlas cblas = self._cpu_ops.cblas() + self._resize() self._ensure_labels_are_added(docs) - set_dropout_rate(self.model, drop) - batch = self.moves.init_batch(docs) - model = self.model.predict(docs) - weights = get_c_weights(model) - for state in batch: - if not state.is_final(): - states.push_back(state.c) - sizes = get_c_sizes(model, states.size()) - with nogil: - self._parseC(cblas, &states[0], weights, sizes) - model.clear_memory() - del model - return batch + with _change_attrs(self.model, beam_width=1): + inputs = TransitionModelInputs(docs=docs, moves=self.moves) + states, _ = self.model.predict(inputs) + return states def beam_parse(self, docs, int beam_width, float drop=0., beam_density=0.): - cdef Beam beam - cdef Doc doc self._ensure_labels_are_added(docs) - batch = _beam_utils.BeamBatch( - self.moves, - self.moves.init_batch(docs), - None, - beam_width, - density=beam_density - ) - model = self.model.predict(docs) - while not batch.is_done: - states = batch.get_unfinished_states() - if not states: - break - scores = model.predict(states) - batch.advance(scores) - model.clear_memory() - del model - return list(batch) - - cdef void _parseC(self, CBlas cblas, StateC** states, - WeightsC weights, SizesC sizes) nogil: - cdef int i, j - cdef vector[StateC*] unfinished - cdef ActivationsC activations = alloc_activations(sizes) - while sizes.states >= 1: - predict_states(cblas, &activations, states, &weights, sizes) - # Validate actions, argmax, take action. - self.c_transition_batch(states, - activations.scores, sizes.classes, sizes.states) - for i in range(sizes.states): - if not states[i].is_final(): - unfinished.push_back(states[i]) - for i in range(unfinished.size()): - states[i] = unfinished[i] - sizes.states = unfinished.size() - unfinished.clear() - free_activations(&activations) + with _change_attrs(self.model, beam_width=self.cfg["beam_width"], beam_density=self.cfg["beam_density"]): + inputs = TransitionModelInputs(docs=docs, moves=self.moves) + beams, _ = self.model.predict(inputs) + return beams def set_annotations(self, docs, states_or_beams): cdef StateClass state @@ -450,35 +397,6 @@ cdef class Parser(TrainablePipe): for hook in self.postprocesses: hook(doc) - def transition_states(self, states, float[:, ::1] scores): - cdef StateClass state - cdef float* c_scores = &scores[0, 0] - cdef vector[StateC*] c_states - for state in states: - c_states.push_back(state.c) - self.c_transition_batch(&c_states[0], c_scores, scores.shape[1], scores.shape[0]) - return [state for state in states if not state.c.is_final()] - - cdef void c_transition_batch(self, StateC** states, const float* scores, - int nr_class, int batch_size) nogil: - # n_moves should not be zero at this point, but make sure to avoid zero-length mem alloc - with gil: - assert self.moves.n_moves > 0, Errors.E924.format(name=self.name) - is_valid = calloc(self.moves.n_moves, sizeof(int)) - cdef int i, guess - cdef Transition action - for i in range(batch_size): - self.moves.set_valid(is_valid, states[i]) - guess = arg_max_if_valid(&scores[i*nr_class], is_valid, nr_class) - if guess == -1: - # This shouldn't happen, but it's hard to raise an error here, - # and we don't want to infinite loop. So, force to end state. - states[i].force_final() - else: - action = self.moves.c[guess] - action.do(states[i], action.label) - free(is_valid) - def update(self, examples, *, drop=0., sgd=None, losses=None): cdef StateClass state if losses is None: @@ -490,67 +408,99 @@ cdef class Parser(TrainablePipe): ) for multitask in self._multitasks: multitask.update(examples, drop=drop, sgd=sgd) + # We need to take care to act on the whole batch, because we might be + # getting vectors via a listener. n_examples = len([eg for eg in examples if self.moves.has_gold(eg)]) if n_examples == 0: return losses set_dropout_rate(self.model, drop) - # The probability we use beam update, instead of falling back to - # a greedy update - beam_update_prob = self.cfg["beam_update_prob"] - if self.cfg['beam_width'] >= 2 and numpy.random.random() < beam_update_prob: - return self.update_beam( - examples, - beam_width=self.cfg["beam_width"], - sgd=sgd, - losses=losses, - beam_density=self.cfg["beam_density"] - ) + docs = [eg.x for eg in examples if len(eg.x)] + max_moves = self.cfg["update_with_oracle_cut_size"] if max_moves >= 1: # Chop sequences into lengths of this many words, to make the # batch uniform length. - max_moves = int(random.uniform(max_moves // 2, max_moves * 2)) - states, golds, _ = self._init_gold_batch( + max_moves = int(random.uniform(max(max_moves // 2, 1), max_moves * 2)) + init_states, gold_states, _ = self._init_gold_batch( examples, max_length=max_moves ) else: - states, golds, _ = self.moves.init_gold_batch(examples) - if not states: - return losses - model, backprop_tok2vec = self.model.begin_update([eg.x for eg in examples]) - - all_states = list(states) - states_golds = list(zip(states, golds)) - n_moves = 0 - while states_golds: - states, golds = zip(*states_golds) - scores, backprop = model.begin_update(states) - d_scores = self.get_batch_loss(states, golds, scores, losses) - # Note that the gradient isn't normalized by the batch size - # here, because our "samples" are really the states...But we - # can't normalize by the number of states either, as then we'd - # be getting smaller gradients for states in long sequences. - backprop(d_scores) - # Follow the predicted action - self.transition_states(states, scores) - states_golds = [(s, g) for (s, g) in zip(states, golds) if not s.is_final()] - if max_moves >= 1 and n_moves >= max_moves: - break - n_moves += 1 + init_states, gold_states, _ = self.moves.init_gold_batch(examples) - backprop_tok2vec(golds) + inputs = TransitionModelInputs(docs=docs, moves=self.moves, + max_moves=max_moves, states=[state.copy() for state in init_states]) + (pred_states, scores), backprop_scores = self.model.begin_update(inputs) + if sum(s.shape[0] for s in scores) == 0: + return losses + d_scores = self.get_loss((gold_states, init_states, pred_states, scores), + examples, max_moves) + backprop_scores((pred_states, d_scores)) if sgd not in (None, False): self.finish_update(sgd) + losses[self.name] += float((d_scores**2).sum()) # Ugh, this is annoying. If we're working on GPU, we want to free the # memory ASAP. It seems that Python doesn't necessarily get around to # removing these in time if we don't explicitly delete? It's confusing. - del backprop - del backprop_tok2vec - model.clear_memory() - del model + del backprop_scores return losses + def get_loss(self, states_scores, examples, max_moves): + gold_states, init_states, pred_states, scores = states_scores + scores = self.model.ops.xp.vstack(scores) + costs = self._get_costs_from_histories( + examples, + gold_states, + init_states, + [list(state.history) for state in pred_states], + max_moves + ) + xp = get_array_module(scores) + best_costs = costs.min(axis=1, keepdims=True) + gscores = scores.copy() + min_score = scores.min() - 1000 + assert costs.shape == scores.shape, (costs.shape, scores.shape) + gscores[costs > best_costs] = min_score + max_ = scores.max(axis=1, keepdims=True) + gmax = gscores.max(axis=1, keepdims=True) + exp_scores = xp.exp(scores - max_) + exp_gscores = xp.exp(gscores - gmax) + Z = exp_scores.sum(axis=1, keepdims=True) + gZ = exp_gscores.sum(axis=1, keepdims=True) + d_scores = exp_scores / Z + d_scores -= (costs <= best_costs) * (exp_gscores / gZ) + return d_scores + + def _get_costs_from_histories(self, examples, gold_states, init_states, histories, max_moves): + cdef TransitionSystem moves = self.moves + cdef StateClass state + cdef int clas + cdef int nF = self.model.get_dim("nF") + cdef int nO = moves.n_moves + cdef int nS = sum([len(history) for history in histories]) + cdef Pool mem = Pool() + cdef np.ndarray costs_i + is_valid = mem.alloc(nO, sizeof(int)) + batch = list(zip(init_states, histories, gold_states)) + n_moves = 0 + output = [] + while batch: + costs = numpy.zeros((len(batch), nO), dtype="f") + for i, (state, history, gold) in enumerate(batch): + costs_i = costs[i] + clas = history.pop(0) + moves.set_costs(is_valid, costs_i.data, state.c, gold) + action = moves.c[clas] + action.do(state.c, action.label) + state.c.history.push_back(clas) + output.append(costs) + batch = [(s, h, g) for s, h, g in batch if len(h) != 0] + if n_moves >= max_moves >= 1: + break + n_moves += 1 + + return self.model.ops.xp.vstack(output) + def rehearse(self, examples, sgd=None, losses=None, **cfg): """Perform a "rehearsal" update, to prevent catastrophic forgetting.""" if losses is None: @@ -560,10 +510,9 @@ cdef class Parser(TrainablePipe): multitask.rehearse(examples, losses=losses, sgd=sgd) if self._rehearsal_model is None: return None - losses.setdefault(self.name, 0.) + losses.setdefault(self.name, 0.0) validate_examples(examples, "Parser.rehearse") docs = [eg.predicted for eg in examples] - states = self.moves.init_batch(docs) # This is pretty dirty, but the NER can resize itself in init_batch, # if labels are missing. We therefore have to check whether we need to # expand our model output. @@ -571,85 +520,33 @@ cdef class Parser(TrainablePipe): # Prepare the stepwise model, and get the callback for finishing the batch set_dropout_rate(self._rehearsal_model, 0.0) set_dropout_rate(self.model, 0.0) - tutor, _ = self._rehearsal_model.begin_update(docs) - model, backprop_tok2vec = self.model.begin_update(docs) - n_scores = 0. - loss = 0. - while states: - targets, _ = tutor.begin_update(states) - guesses, backprop = model.begin_update(states) - d_scores = (guesses - targets) / targets.shape[0] - # If all weights for an output are 0 in the original model, don't - # supervise that output. This allows us to add classes. - loss += (d_scores**2).sum() - backprop(d_scores) - # Follow the predicted action - self.transition_states(states, guesses) - states = [state for state in states if not state.is_final()] - n_scores += d_scores.size - # Do the backprop - backprop_tok2vec(docs) + student_inputs = TransitionModelInputs(docs=docs, moves=self.moves) + (student_states, student_scores), backprop_scores = self.model.begin_update(student_inputs) + actions = states2actions(student_states) + teacher_inputs = TransitionModelInputs(docs=docs, moves=self.moves, actions=actions) + _, teacher_scores = self._rehearsal_model.predict(teacher_inputs) + + loss, d_scores = self.get_teacher_student_loss(teacher_scores, student_scores, normalize=True) + + teacher_scores = self.model.ops.xp.vstack(teacher_scores) + student_scores = self.model.ops.xp.vstack(student_scores) + assert teacher_scores.shape == student_scores.shape + + d_scores = (student_scores - teacher_scores) / teacher_scores.shape[0] + # If all weights for an output are 0 in the original model, don't + # supervise that output. This allows us to add classes. + loss = (d_scores**2).sum() / d_scores.size + backprop_scores((student_states, d_scores)) + if sgd is not None: self.finish_update(sgd) - losses[self.name] += loss / n_scores - del backprop - del backprop_tok2vec - model.clear_memory() - tutor.clear_memory() - del model - del tutor + losses[self.name] += loss + return losses def update_beam(self, examples, *, beam_width, drop=0., sgd=None, losses=None, beam_density=0.0): - states, golds, _ = self.moves.init_gold_batch(examples) - if not states: - return losses - # Prepare the stepwise model, and get the callback for finishing the batch - model, backprop_tok2vec = self.model.begin_update( - [eg.predicted for eg in examples]) - loss = _beam_utils.update_beam( - self.moves, - states, - golds, - model, - beam_width, - beam_density=beam_density, - ) - losses[self.name] += loss - backprop_tok2vec(golds) - if sgd is not None: - self.finish_update(sgd) - - def get_batch_loss(self, states, golds, float[:, ::1] scores, losses): - cdef StateClass state - cdef Pool mem = Pool() - cdef int i - - # n_moves should not be zero at this point, but make sure to avoid zero-length mem alloc - assert self.moves.n_moves > 0, Errors.E924.format(name=self.name) - - is_valid = mem.alloc(self.moves.n_moves, sizeof(int)) - costs = mem.alloc(self.moves.n_moves, sizeof(float)) - cdef np.ndarray d_scores = numpy.zeros((len(states), self.moves.n_moves), - dtype='f', order='C') - c_d_scores = d_scores.data - unseen_classes = self.model.attrs["unseen_classes"] - for i, (state, gold) in enumerate(zip(states, golds)): - memset(is_valid, 0, self.moves.n_moves * sizeof(int)) - memset(costs, 0, self.moves.n_moves * sizeof(float)) - self.moves.set_costs(is_valid, costs, state.c, gold) - for j in range(self.moves.n_moves): - if costs[j] <= 0.0 and j in unseen_classes: - unseen_classes.remove(j) - cpu_log_loss(c_d_scores, - costs, is_valid, &scores[i, 0], d_scores.shape[1]) - c_d_scores += d_scores.shape[1] - # Note that we don't normalize this. See comment in update() for why. - if losses is not None: - losses.setdefault(self.name, 0.) - losses[self.name] += (d_scores**2).sum() - return d_scores + raise NotImplementedError def set_output(self, nO): self.model.attrs["resize_output"](self.model, nO) @@ -688,7 +585,7 @@ cdef class Parser(TrainablePipe): for example in islice(get_examples(), 10): doc_sample.append(example.predicted) assert len(doc_sample) > 0, Errors.E923.format(name=self.name) - self.model.initialize(doc_sample) + self.model.initialize((doc_sample, self.moves)) if nlp is not None: self.init_multitask_objectives(get_examples, nlp.pipeline) @@ -781,26 +678,27 @@ cdef class Parser(TrainablePipe): def _init_gold_batch(self, examples, max_length): """Make a square batch, of length equal to the shortest transition - sequence or a cap. A long - doc will get multiple states. Let's say we have a doc of length 2*N, - where N is the shortest doc. We'll make two states, one representing - long_doc[:N], and another representing long_doc[N:].""" + sequence or a cap. A long doc will get multiple states. Let's say we + have a doc of length 2*N, where N is the shortest doc. We'll make + two states, one representing long_doc[:N], and another representing + long_doc[N:].""" cdef: StateClass start_state StateClass state Transition action - all_states = self.moves.init_batch([eg.predicted for eg in examples]) + TransitionSystem moves = self.moves + all_states = moves.init_batch([eg.predicted for eg in examples]) states = [] golds = [] to_cut = [] for state, eg in zip(all_states, examples): - if self.moves.has_gold(eg) and not state.is_final(): - gold = self.moves.init_gold(state, eg) + if moves.has_gold(eg) and not state.is_final(): + gold = moves.init_gold(state, eg) if len(eg.x) < max_length: states.append(state) golds.append(gold) else: - oracle_actions = self.moves.get_oracle_sequence_from_state( + oracle_actions = moves.get_oracle_sequence_from_state( state.copy(), gold) to_cut.append((eg, state, gold, oracle_actions)) if not to_cut: @@ -810,13 +708,52 @@ cdef class Parser(TrainablePipe): for i in range(0, len(oracle_actions), max_length): start_state = state.copy() for clas in oracle_actions[i:i+max_length]: - action = self.moves.c[clas] + action = moves.c[clas] action.do(state.c, action.label) if state.is_final(): break - if self.moves.has_gold(eg, start_state.B(0), state.B(0)): + if moves.has_gold(eg, start_state.B(0), state.B(0)): states.append(start_state) golds.append(gold) if state.is_final(): break return states, golds, max_length + + +@contextlib.contextmanager +def _change_attrs(model, **kwargs): + """Temporarily modify a thinc model's attributes.""" + unset = object() + old_attrs = {} + for key, value in kwargs.items(): + old_attrs[key] = model.attrs.get(key, unset) + model.attrs[key] = value + yield model + for key, value in old_attrs.items(): + if value is unset: + model.attrs.pop(key) + else: + model.attrs[key] = value + + +def states2actions(states: List[StateClass]) -> List[Ints1d]: + cdef int step + cdef StateClass state + cdef StateC* c_state + actions = [] + while True: + step = len(actions) + + step_actions = [] + for state in states: + c_state = state.c + if step < c_state.history.size(): + step_actions.append(c_state.history[step]) + + # We are done if we have exhausted all histories. + if len(step_actions) == 0: + break + + actions.append(numpy.array(step_actions, dtype="i")) + + return actions diff --git a/spacy/tests/parser/test_ner.py b/spacy/tests/parser/test_ner.py index 7ef3ed869..d6cd11e55 100644 --- a/spacy/tests/parser/test_ner.py +++ b/spacy/tests/parser/test_ner.py @@ -13,6 +13,7 @@ from spacy.pipeline._parser_internals.ner import BiluoPushDown from spacy.training import Example, iob_to_biluo, split_bilu_label from spacy.tokens import Doc, Span from spacy.vocab import Vocab +from thinc.api import fix_random_seed import logging from ..util import make_tempdir @@ -412,7 +413,7 @@ def test_train_empty(): train_examples.append(Example.from_dict(nlp.make_doc(t[0]), t[1])) ner = nlp.add_pipe("ner", last=True) ner.add_label("PERSON") - nlp.initialize() + nlp.initialize(get_examples=lambda: train_examples) for itn in range(2): losses = {} batches = util.minibatch(train_examples, size=8) @@ -539,11 +540,11 @@ def test_block_ner(): assert [token.ent_type_ for token in doc] == expected_types -@pytest.mark.parametrize("use_upper", [True, False]) -def test_overfitting_IO(use_upper): +def test_overfitting_IO(): + fix_random_seed(1) # Simple test to try and quickly overfit the NER component nlp = English() - ner = nlp.add_pipe("ner", config={"model": {"use_upper": use_upper}}) + ner = nlp.add_pipe("ner", config={"model": {}}) train_examples = [] for text, annotations in TRAIN_DATA: train_examples.append(Example.from_dict(nlp.make_doc(text), annotations)) @@ -575,7 +576,6 @@ def test_overfitting_IO(use_upper): assert ents2[0].label_ == "LOC" # Ensure that the predictions are still the same, even after adding a new label ner2 = nlp2.get_pipe("ner") - assert ner2.model.attrs["has_upper"] == use_upper ner2.add_label("RANDOM_NEW_LABEL") doc3 = nlp2(test_text) ents3 = doc3.ents diff --git a/spacy/tests/parser/test_parse.py b/spacy/tests/parser/test_parse.py index 97d112a50..57b6e188b 100644 --- a/spacy/tests/parser/test_parse.py +++ b/spacy/tests/parser/test_parse.py @@ -1,13 +1,17 @@ +import itertools import pytest +import numpy from numpy.testing import assert_equal from thinc.api import Adam from spacy import registry, util from spacy.attrs import DEP, NORM from spacy.lang.en import English -from spacy.tokens import Doc from spacy.training import Example +from spacy.tokens import Doc from spacy.vocab import Vocab +from spacy import util, registry +from thinc.api import fix_random_seed from ...pipeline import DependencyParser from ...pipeline.dep_parser import DEFAULT_PARSER_MODEL @@ -59,6 +63,8 @@ PARTIAL_DATA = [ ), ] +PARSERS = ["parser"] # TODO: Test beam_parser when ready + eps = 0.1 @@ -171,6 +177,57 @@ def test_parser_parse_one_word_sentence(en_vocab, en_parser, words): assert doc[0].dep != 0 +def test_parser_apply_actions(en_vocab, en_parser): + words = ["I", "ate", "pizza"] + words2 = ["Eat", "more", "pizza", "!"] + doc1 = Doc(en_vocab, words=words) + doc2 = Doc(en_vocab, words=words2) + docs = [doc1, doc2] + + moves = en_parser.moves + moves.add_action(0, "") + moves.add_action(1, "") + moves.add_action(2, "nsubj") + moves.add_action(3, "obj") + moves.add_action(2, "amod") + + actions = [ + numpy.array([0, 0], dtype="i"), + numpy.array([2, 0], dtype="i"), + numpy.array([0, 4], dtype="i"), + numpy.array([3, 3], dtype="i"), + numpy.array([1, 1], dtype="i"), + numpy.array([1, 1], dtype="i"), + numpy.array([0], dtype="i"), + numpy.array([1], dtype="i"), + ] + + states = moves.init_batch(docs) + active_states = states + + for step_actions in actions: + active_states = moves.apply_actions(active_states, step_actions) + + assert len(active_states) == 0 + + for (state, doc) in zip(states, docs): + moves.set_annotations(state, doc) + + assert docs[0][0].head.i == 1 + assert docs[0][0].dep_ == "nsubj" + assert docs[0][1].head.i == 1 + assert docs[0][1].dep_ == "ROOT" + assert docs[0][2].head.i == 1 + assert docs[0][2].dep_ == "obj" + + assert docs[1][0].head.i == 0 + assert docs[1][0].dep_ == "ROOT" + assert docs[1][1].head.i == 2 + assert docs[1][1].dep_ == "amod" + assert docs[1][2].head.i == 0 + assert docs[1][2].dep_ == "obj" + + @pytest.mark.skip( reason="The step_through API was removed (but should be brought back)" ) @@ -319,7 +376,7 @@ def test_parser_constructor(en_vocab): DependencyParser(en_vocab, model) -@pytest.mark.parametrize("pipe_name", ["parser", "beam_parser"]) +@pytest.mark.parametrize("pipe_name", PARSERS) def test_incomplete_data(pipe_name): # Test that the parser works with incomplete information nlp = English() @@ -345,11 +402,15 @@ def test_incomplete_data(pipe_name): assert doc[2].head.i == 1 -@pytest.mark.parametrize("pipe_name", ["parser", "beam_parser"]) -def test_overfitting_IO(pipe_name): +@pytest.mark.parametrize( + "pipe_name,max_moves", itertools.product(PARSERS, [0, 1, 5, 100]) +) +def test_overfitting_IO(pipe_name, max_moves): + fix_random_seed(0) # Simple test to try and quickly overfit the dependency parser (normal or beam) nlp = English() parser = nlp.add_pipe(pipe_name) + parser.cfg["update_with_oracle_cut_size"] = max_moves train_examples = [] for text, annotations in TRAIN_DATA: train_examples.append(Example.from_dict(nlp.make_doc(text), annotations)) @@ -451,10 +512,12 @@ def test_distill(): @pytest.mark.parametrize( "parser_config", [ - # TransitionBasedParser V1 - ({"@architectures": "spacy.TransitionBasedParser.v1", "tok2vec": DEFAULT_TOK2VEC_MODEL, "state_type": "parser", "extra_state_tokens": False, "hidden_width": 64, "maxout_pieces": 2, "use_upper": True}), - # TransitionBasedParser V2 + # TODO: re-enable after we have a spacy-legacy release for v4. See + # https://github.com/explosion/spacy-legacy/pull/36 + #({"@architectures": "spacy.TransitionBasedParser.v1", "tok2vec": DEFAULT_TOK2VEC_MODEL, "state_type": "parser", "extra_state_tokens": False, "hidden_width": 64, "maxout_pieces": 2, "use_upper": True}), ({"@architectures": "spacy.TransitionBasedParser.v2", "tok2vec": DEFAULT_TOK2VEC_MODEL, "state_type": "parser", "extra_state_tokens": False, "hidden_width": 64, "maxout_pieces": 2, "use_upper": True}), + ({"@architectures": "spacy.TransitionBasedParser.v2", "tok2vec": DEFAULT_TOK2VEC_MODEL, "state_type": "parser", "extra_state_tokens": False, "hidden_width": 64, "maxout_pieces": 2, "use_upper": False}), + ({"@architectures": "spacy.TransitionBasedParser.v3", "tok2vec": DEFAULT_TOK2VEC_MODEL, "state_type": "parser", "extra_state_tokens": False, "hidden_width": 64, "maxout_pieces": 2}), ], ) # fmt: on diff --git a/spacy/tests/pipeline/test_tok2vec.py b/spacy/tests/pipeline/test_tok2vec.py index e423d9a19..ee62b1ab4 100644 --- a/spacy/tests/pipeline/test_tok2vec.py +++ b/spacy/tests/pipeline/test_tok2vec.py @@ -382,7 +382,7 @@ cfg_string_multi = """ factory = "ner" [components.ner.model] - @architectures = "spacy.TransitionBasedParser.v2" + @architectures = "spacy.TransitionBasedParser.v3" [components.ner.model.tok2vec] @architectures = "spacy.Tok2VecListener.v1" diff --git a/spacy/tests/serialize/test_serialize_config.py b/spacy/tests/serialize/test_serialize_config.py index 85e6f8b2c..82f01dcc2 100644 --- a/spacy/tests/serialize/test_serialize_config.py +++ b/spacy/tests/serialize/test_serialize_config.py @@ -122,33 +122,11 @@ width = ${components.tok2vec.model.width} parser_config_string_upper = """ [model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "parser" extra_state_tokens = false hidden_width = 66 maxout_pieces = 2 -use_upper = true - -[model.tok2vec] -@architectures = "spacy.HashEmbedCNN.v1" -pretrained_vectors = null -width = 333 -depth = 4 -embed_size = 5555 -window_size = 1 -maxout_pieces = 7 -subword_features = false -""" - - -parser_config_string_no_upper = """ -[model] -@architectures = "spacy.TransitionBasedParser.v2" -state_type = "parser" -extra_state_tokens = false -hidden_width = 66 -maxout_pieces = 2 -use_upper = false [model.tok2vec] @architectures = "spacy.HashEmbedCNN.v1" @@ -179,7 +157,6 @@ def my_parser(): extra_state_tokens=True, hidden_width=65, maxout_pieces=5, - use_upper=True, ) return parser @@ -285,15 +262,16 @@ def test_serialize_custom_nlp(): nlp.to_disk(d) nlp2 = spacy.load(d) model = nlp2.get_pipe("parser").model - model.get_ref("tok2vec") - # check that we have the correct settings, not the default ones - assert model.get_ref("upper").get_dim("nI") == 65 - assert model.get_ref("lower").get_dim("nI") == 65 + assert model.get_ref("tok2vec") is not None + assert model.has_param("hidden_W") + assert model.has_param("hidden_b") + output = model.get_ref("output") + assert output is not None + assert output.has_param("W") + assert output.has_param("b") -@pytest.mark.parametrize( - "parser_config_string", [parser_config_string_upper, parser_config_string_no_upper] -) +@pytest.mark.parametrize("parser_config_string", [parser_config_string_upper]) def test_serialize_parser(parser_config_string): """Create a non-default parser config to check nlp serializes it correctly""" nlp = English() @@ -306,11 +284,13 @@ def test_serialize_parser(parser_config_string): nlp.to_disk(d) nlp2 = spacy.load(d) model = nlp2.get_pipe("parser").model - model.get_ref("tok2vec") - # check that we have the correct settings, not the default ones - if model.attrs["has_upper"]: - assert model.get_ref("upper").get_dim("nI") == 66 - assert model.get_ref("lower").get_dim("nI") == 66 + assert model.get_ref("tok2vec") is not None + assert model.has_param("hidden_W") + assert model.has_param("hidden_b") + output = model.get_ref("output") + assert output is not None + assert output.has_param("b") + assert output.has_param("W") def test_config_nlp_roundtrip(): @@ -457,9 +437,7 @@ def test_config_auto_fill_extra_fields(): load_model_from_config(nlp.config) -@pytest.mark.parametrize( - "parser_config_string", [parser_config_string_upper, parser_config_string_no_upper] -) +@pytest.mark.parametrize("parser_config_string", [parser_config_string_upper]) def test_config_validate_literal(parser_config_string): nlp = English() config = Config().from_str(parser_config_string) diff --git a/spacy/tests/test_misc.py b/spacy/tests/test_misc.py index 618f17334..e4e0f9d83 100644 --- a/spacy/tests/test_misc.py +++ b/spacy/tests/test_misc.py @@ -5,10 +5,8 @@ from pathlib import Path from spacy.about import __version__ as spacy_version from spacy import util from spacy import prefer_gpu, require_gpu, require_cpu -from spacy.ml._precomputable_affine import PrecomputableAffine -from spacy.ml._precomputable_affine import _backprop_precomputable_affine_padding -from spacy.util import dot_to_object, SimpleFrozenList, import_file -from spacy.util import to_ternary_int, find_available_port +from spacy.util import dot_to_object, SimpleFrozenList, import_file, to_ternary_int +from spacy.util import find_available_port from thinc.api import Config, Optimizer, ConfigValidationError from thinc.api import get_current_ops, set_current_ops, NumpyOps, CupyOps, MPSOps from thinc.compat import has_cupy_gpu, has_torch_mps_gpu @@ -81,34 +79,6 @@ def test_util_get_package_path(package): assert isinstance(path, Path) -def test_PrecomputableAffine(nO=4, nI=5, nF=3, nP=2): - model = PrecomputableAffine(nO=nO, nI=nI, nF=nF, nP=nP).initialize() - assert model.get_param("W").shape == (nF, nO, nP, nI) - tensor = model.ops.alloc((10, nI)) - Y, get_dX = model.begin_update(tensor) - assert Y.shape == (tensor.shape[0] + 1, nF, nO, nP) - dY = model.ops.alloc((15, nO, nP)) - ids = model.ops.alloc((15, nF)) - ids[1, 2] = -1 - dY[1] = 1 - assert not model.has_grad("pad") - d_pad = _backprop_precomputable_affine_padding(model, dY, ids) - assert d_pad[0, 2, 0, 0] == 1.0 - ids.fill(0.0) - dY.fill(0.0) - dY[0] = 0 - ids[1, 2] = 0 - ids[1, 1] = -1 - ids[1, 0] = -1 - dY[1] = 1 - ids[2, 0] = -1 - dY[2] = 5 - d_pad = _backprop_precomputable_affine_padding(model, dY, ids) - assert d_pad[0, 0, 0, 0] == 6 - assert d_pad[0, 1, 0, 0] == 1 - assert d_pad[0, 2, 0, 0] == 0 - - def test_prefer_gpu(): current_ops = get_current_ops() if has_cupy_gpu: diff --git a/spacy/training/example.pyx b/spacy/training/example.pyx index d6f3a07fb..a36fa0d73 100644 --- a/spacy/training/example.pyx +++ b/spacy/training/example.pyx @@ -1,5 +1,4 @@ from collections.abc import Iterable as IterableInstance -import warnings import numpy from murmurhash.mrmr cimport hash64 diff --git a/website/docs/api/architectures.mdx b/website/docs/api/architectures.mdx index 2a1bc4380..54b5065e8 100644 --- a/website/docs/api/architectures.mdx +++ b/website/docs/api/architectures.mdx @@ -553,18 +553,17 @@ for a Tok2Vec layer. ## Parser & NER architectures {id="parser"} -### spacy.TransitionBasedParser.v2 {id="TransitionBasedParser",source="spacy/ml/models/parser.py"} +### spacy.TransitionBasedParser.v3 {id="TransitionBasedParser",source="spacy/ml/models/parser.py"} > #### Example Config > > ```ini > [model] -> @architectures = "spacy.TransitionBasedParser.v2" +> @architectures = "spacy.TransitionBasedParser.v3" > state_type = "ner" > extra_state_tokens = false > hidden_width = 64 > maxout_pieces = 2 -> use_upper = true > > [model.tok2vec] > @architectures = "spacy.HashEmbedCNN.v2" @@ -594,23 +593,22 @@ consists of either two or three subnetworks: state representation. If not present, the output from the lower model is used as action scores directly. -| Name | Description | -| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `tok2vec` | Subnetwork to map tokens into vector representations. ~~Model[List[Doc], List[Floats2d]]~~ | -| `state_type` | Which task to extract features for. Possible values are "ner" and "parser". ~~str~~ | -| `extra_state_tokens` | Whether to use an expanded feature set when extracting the state tokens. Slightly slower, but sometimes improves accuracy slightly. Defaults to `False`. ~~bool~~ | -| `hidden_width` | The width of the hidden layer. ~~int~~ | -| `maxout_pieces` | How many pieces to use in the state prediction layer. Recommended values are `1`, `2` or `3`. If `1`, the maxout non-linearity is replaced with a [`Relu`](https://thinc.ai/docs/api-layers#relu) non-linearity if `use_upper` is `True`, and no non-linearity if `False`. ~~int~~ | -| `use_upper` | Whether to use an additional hidden layer after the state vector in order to predict the action scores. It is recommended to set this to `False` for large pretrained models such as transformers, and `True` for smaller networks. The upper layer is computed on CPU, which becomes a bottleneck on larger GPU-based models, where it's also less necessary. ~~bool~~ | -| `nO` | The number of actions the model will predict between. Usually inferred from data at the beginning of training, or loaded from disk. ~~int~~ | -| **CREATES** | The model using the architecture. ~~Model[List[Docs], List[List[Floats2d]]]~~ | +| Name | Description | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tok2vec` | Subnetwork to map tokens into vector representations. ~~Model[List[Doc], List[Floats2d]]~~ | +| `state_type` | Which task to extract features for. Possible values are "ner" and "parser". ~~str~~ | +| `extra_state_tokens` | Whether to use an expanded feature set when extracting the state tokens. Slightly slower, but sometimes improves accuracy slightly. Defaults to `False`. ~~bool~~ | +| `hidden_width` | The width of the hidden layer. ~~int~~ | +| `maxout_pieces` | How many pieces to use in the state prediction layer. Recommended values are `1`, `2` or `3`. ~~int~~ | +| `nO` | The number of actions the model will predict between. Usually inferred from data at the beginning of training, or loaded from disk. ~~int~~ | +| **CREATES** | The model using the architecture. ~~Model[List[Docs], List[List[Floats2d]]]~~ | [TransitionBasedParser.v1](/api/legacy#TransitionBasedParser_v1) had the exact same signature, but the `use_upper` argument was `True` by default. - + ## Tagging architectures {id="tagger",source="spacy/ml/models/tagger.py"} diff --git a/website/docs/api/cli.mdx b/website/docs/api/cli.mdx index 8b84a02ff..80b1362bc 100644 --- a/website/docs/api/cli.mdx +++ b/website/docs/api/cli.mdx @@ -361,7 +361,7 @@ Module spacy.language File /path/to/spacy/language.py (line 64) ℹ [components.ner.model] Registry @architectures -Name spacy.TransitionBasedParser.v1 +Name spacy.TransitionBasedParser.v3 Module spacy.ml.models.parser File /path/to/spacy/ml/models/parser.py (line 11) ℹ [components.ner.model.tok2vec] @@ -371,7 +371,7 @@ Module spacy.ml.models.tok2vec File /path/to/spacy/ml/models/tok2vec.py (line 16) ℹ [components.parser.model] Registry @architectures -Name spacy.TransitionBasedParser.v1 +Name spacy.TransitionBasedParser.v3 Module spacy.ml.models.parser File /path/to/spacy/ml/models/parser.py (line 11) ℹ [components.parser.model.tok2vec] @@ -696,7 +696,7 @@ scorer = {"@scorers":"spacy.ner_scorer.v1"} update_with_oracle_cut_size = 100 [components.ner.model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "ner" extra_state_tokens = false - hidden_width = 64 @@ -719,7 +719,7 @@ scorer = {"@scorers":"spacy.parser_scorer.v1"} update_with_oracle_cut_size = 100 [components.parser.model] -@architectures = "spacy.TransitionBasedParser.v2" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "parser" extra_state_tokens = false hidden_width = 128 diff --git a/website/docs/api/legacy.mdx b/website/docs/api/legacy.mdx index ea6d3a899..70d6223e7 100644 --- a/website/docs/api/legacy.mdx +++ b/website/docs/api/legacy.mdx @@ -225,7 +225,7 @@ the others, but may not be as accurate, especially if texts are short. ### spacy.TransitionBasedParser.v1 {id="TransitionBasedParser_v1"} Identical to -[`spacy.TransitionBasedParser.v2`](/api/architectures#TransitionBasedParser) +[`spacy.TransitionBasedParser.v3`](/api/architectures#TransitionBasedParser) except the `use_upper` was set to `True` by default. ## Layers {id="layers"} diff --git a/website/docs/usage/embeddings-transformers.mdx b/website/docs/usage/embeddings-transformers.mdx index cf80822fb..0de173a21 100644 --- a/website/docs/usage/embeddings-transformers.mdx +++ b/website/docs/usage/embeddings-transformers.mdx @@ -140,7 +140,7 @@ factory = "tok2vec" factory = "ner" [components.ner.model] -@architectures = "spacy.TransitionBasedParser.v1" +@architectures = "spacy.TransitionBasedParser.v3" [components.ner.model.tok2vec] @architectures = "spacy.Tok2VecListener.v1" @@ -156,7 +156,7 @@ same. This makes them fully independent and doesn't require an upstream factory = "ner" [components.ner.model] -@architectures = "spacy.TransitionBasedParser.v1" +@architectures = "spacy.TransitionBasedParser.v3" [components.ner.model.tok2vec] @architectures = "spacy.Tok2Vec.v2" @@ -472,7 +472,7 @@ sneakily delegates to the `Transformer` pipeline component. factory = "ner" [nlp.pipeline.ner.model] -@architectures = "spacy.TransitionBasedParser.v1" +@architectures = "spacy.TransitionBasedParser.v3" state_type = "ner" extra_state_tokens = false hidden_width = 128 From dc0f527039c37ea8e5c13649d09e7ae7cb39a071 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Wed, 18 Jan 2023 12:54:56 +0100 Subject: [PATCH 038/123] Revert "Temporarily skip tests that require models/compat" This reverts commit 378db0eb1e9231c565faf72078bcfb012f439e9b. --- .github/azure-steps.yml | 44 ++++++++++++++++++++--------------------- spacy/tests/test_cli.py | 2 -- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/.github/azure-steps.yml b/.github/azure-steps.yml index d0db75f9a..ed69f611b 100644 --- a/.github/azure-steps.yml +++ b/.github/azure-steps.yml @@ -52,17 +52,17 @@ steps: python -W error -c "import spacy" displayName: "Test import" -# - script: | -# python -m spacy download ca_core_news_sm -# python -m spacy download ca_core_news_md -# python -c "import spacy; nlp=spacy.load('ca_core_news_sm'); doc=nlp('test')" -# displayName: 'Test download CLI' -# condition: eq(variables['python_version'], '3.8') -# -# - script: | -# python -W error -c "import ca_core_news_sm; nlp = ca_core_news_sm.load(); doc=nlp('test')" -# displayName: 'Test no warnings on load (#11713)' -# condition: eq(variables['python_version'], '3.8') + - script: | + python -m spacy download ca_core_news_sm + python -m spacy download ca_core_news_md + python -c "import spacy; nlp=spacy.load('ca_core_news_sm'); doc=nlp('test')" + displayName: 'Test download CLI' + condition: eq(variables['python_version'], '3.8') + + - script: | + python -W error -c "import ca_core_news_sm; nlp = ca_core_news_sm.load(); doc=nlp('test')" + displayName: 'Test no warnings on load (#11713)' + condition: eq(variables['python_version'], '3.8') - script: | python -m spacy convert extra/example_data/ner_example_data/ner-token-per-line-conll2003.json . @@ -86,17 +86,17 @@ steps: displayName: 'Test train CLI' condition: eq(variables['python_version'], '3.8') -# - script: | -# python -c "import spacy; config = spacy.util.load_config('ner.cfg'); config['components']['ner'] = {'source': 'ca_core_news_sm'}; config.to_disk('ner_source_sm.cfg')" -# PYTHONWARNINGS="error,ignore::DeprecationWarning" python -m spacy assemble ner_source_sm.cfg output_dir -# displayName: 'Test assemble CLI' -# condition: eq(variables['python_version'], '3.8') -# -# - script: | -# python -c "import spacy; config = spacy.util.load_config('ner.cfg'); config['components']['ner'] = {'source': 'ca_core_news_md'}; config.to_disk('ner_source_md.cfg')" -# python -m spacy assemble ner_source_md.cfg output_dir 2>&1 | grep -q W113 -# displayName: 'Test assemble CLI vectors warning' -# condition: eq(variables['python_version'], '3.8') + - script: | + python -c "import spacy; config = spacy.util.load_config('ner.cfg'); config['components']['ner'] = {'source': 'ca_core_news_sm'}; config.to_disk('ner_source_sm.cfg')" + PYTHONWARNINGS="error,ignore::DeprecationWarning" python -m spacy assemble ner_source_sm.cfg output_dir + displayName: 'Test assemble CLI' + condition: eq(variables['python_version'], '3.8') + + - script: | + python -c "import spacy; config = spacy.util.load_config('ner.cfg'); config['components']['ner'] = {'source': 'ca_core_news_md'}; config.to_disk('ner_source_md.cfg')" + python -m spacy assemble ner_source_md.cfg output_dir 2>&1 | grep -q W113 + displayName: 'Test assemble CLI vectors warning' + condition: eq(variables['python_version'], '3.8') - script: | python -m pip install -U -r requirements.txt diff --git a/spacy/tests/test_cli.py b/spacy/tests/test_cli.py index c88e20de2..d00f66c60 100644 --- a/spacy/tests/test_cli.py +++ b/spacy/tests/test_cli.py @@ -618,7 +618,6 @@ def test_string_to_list_intify(value): assert string_to_list(value, intify=True) == [1, 2, 3] -@pytest.mark.skip(reason="Temporarily skip for dev version") def test_download_compatibility(): spec = SpecifierSet("==" + about.__version__) spec.prereleases = False @@ -629,7 +628,6 @@ def test_download_compatibility(): assert get_minor_version(about.__version__) == get_minor_version(version) -@pytest.mark.skip(reason="Temporarily skip for dev version") def test_validate_compatibility_table(): spec = SpecifierSet("==" + about.__version__) spec.prereleases = False From b052b1b47fa300c3ddd3ab96e41bfd89405c5bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Wed, 18 Jan 2023 18:28:30 +0100 Subject: [PATCH 039/123] Fix batching regression (#12094) * Fix batching regression Some time ago, the spaCy v4 branch switched to the new Thinc v9 schedule. However, this introduced an error in how batching is handed. In the PR, the batchers were changed to keep track of their step, so that the step can be passed to the schedule. However, the issue is that the training loop repeatedly calls the batching functions (rather than using an infinite generator/iterator). So, the step and therefore the schedule would be reset each epoch. Before the schedule switch we didn't have this issue, because the old schedules were stateful. This PR fixes this issue by reverting the batching functions to use a (stateful) generator. Their registry functions do accept a `Schedule` and we convert `Schedule`s to generators. * Update batcher docs * Docstring fixes * Make minibatch take iterables again as well * Bump thinc requirement to 9.0.0.dev2 * Use type declaration * Convert another comment into a proper type declaration --- pyproject.toml | 2 +- requirements.txt | 2 +- setup.cfg | 2 +- spacy/tests/pipeline/test_tagger.py | 4 +- spacy/tests/pipeline/test_textcat.py | 8 +++- spacy/tests/training/test_training.py | 4 +- spacy/training/batchers.py | 58 ++++++++++++++------------- spacy/util.py | 8 ++-- website/docs/api/top-level.mdx | 30 +++++++------- 9 files changed, 64 insertions(+), 54 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 72f04dee3..837cf1fd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "cymem>=2.0.2,<2.1.0", "preshed>=3.0.2,<3.1.0", "murmurhash>=0.28.0,<1.1.0", - "thinc>=9.0.0.dev1,<9.1.0", + "thinc>=9.0.0.dev2,<9.1.0", "numpy>=1.15.0", ] build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt index 5c49f8d29..5a8b41aab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ spacy-legacy>=3.0.11,<3.1.0 spacy-loggers>=1.0.0,<2.0.0 cymem>=2.0.2,<2.1.0 preshed>=3.0.2,<3.1.0 -thinc>=9.0.0.dev1,<9.1.0 +thinc>=9.0.0.dev2,<9.1.0 ml_datasets>=0.2.0,<0.3.0 murmurhash>=0.28.0,<1.1.0 wasabi>=0.9.1,<1.2.0 diff --git a/setup.cfg b/setup.cfg index deeec99a0..d67945864 100644 --- a/setup.cfg +++ b/setup.cfg @@ -39,7 +39,7 @@ install_requires = murmurhash>=0.28.0,<1.1.0 cymem>=2.0.2,<2.1.0 preshed>=3.0.2,<3.1.0 - thinc>=9.0.0.dev1,<9.1.0 + thinc>=9.0.0.dev2,<9.1.0 wasabi>=0.9.1,<1.2.0 srsly>=2.4.3,<3.0.0 catalogue>=2.0.6,<2.1.0 diff --git a/spacy/tests/pipeline/test_tagger.py b/spacy/tests/pipeline/test_tagger.py index 344859f8d..505b41f8c 100644 --- a/spacy/tests/pipeline/test_tagger.py +++ b/spacy/tests/pipeline/test_tagger.py @@ -24,7 +24,9 @@ def test_issue4348(): optimizer = nlp.initialize() for i in range(5): losses = {} - batches = util.minibatch(TRAIN_DATA, size=compounding(4.0, 32.0, 1.001)) + batches = util.minibatch( + TRAIN_DATA, size=compounding(4.0, 32.0, 1.001).to_generator() + ) for batch in batches: nlp.update(batch, sgd=optimizer, losses=losses) diff --git a/spacy/tests/pipeline/test_textcat.py b/spacy/tests/pipeline/test_textcat.py index 9c0eeb171..506897a45 100644 --- a/spacy/tests/pipeline/test_textcat.py +++ b/spacy/tests/pipeline/test_textcat.py @@ -91,7 +91,9 @@ def test_issue3611(): optimizer = nlp.initialize() for i in range(3): losses = {} - batches = util.minibatch(train_data, size=compounding(4.0, 32.0, 1.001)) + batches = util.minibatch( + train_data, size=compounding(4.0, 32.0, 1.001).to_generator() + ) for batch in batches: nlp.update(examples=batch, sgd=optimizer, drop=0.1, losses=losses) @@ -128,7 +130,9 @@ def test_issue4030(): optimizer = nlp.initialize() for i in range(3): losses = {} - batches = util.minibatch(train_data, size=compounding(4.0, 32.0, 1.001)) + batches = util.minibatch( + train_data, size=compounding(4.0, 32.0, 1.001).to_generator() + ) for batch in batches: nlp.update(examples=batch, sgd=optimizer, drop=0.1, losses=losses) diff --git a/spacy/tests/training/test_training.py b/spacy/tests/training/test_training.py index 9fdd416b1..0c8962098 100644 --- a/spacy/tests/training/test_training.py +++ b/spacy/tests/training/test_training.py @@ -918,7 +918,9 @@ def _train_tuples(train_data): optimizer = nlp.initialize() for i in range(5): losses = {} - batches = minibatch(train_examples, size=compounding(4.0, 32.0, 1.001)) + batches = minibatch( + train_examples, size=compounding(4.0, 32.0, 1.001).to_generator() + ) for batch in batches: nlp.update(batch, sgd=optimizer, losses=losses) diff --git a/spacy/training/batchers.py b/spacy/training/batchers.py index 73678c7fc..d9aa04e32 100644 --- a/spacy/training/batchers.py +++ b/spacy/training/batchers.py @@ -2,12 +2,13 @@ from typing import Union, Iterable, Sequence, TypeVar, List, Callable, Iterator from typing import Optional, Any from functools import partial import itertools -from thinc.schedules import Schedule, constant as constant_schedule +from thinc.schedules import Schedule from ..util import registry, minibatch -Sizing = Union[Sequence[int], int, Schedule[int]] +SizingSchedule = Union[Iterable[int], int, Schedule] +Sizing = Union[Iterable[int], int] ItemT = TypeVar("ItemT") BatcherT = Callable[[Iterable[ItemT]], Iterable[List[ItemT]]] @@ -15,7 +16,7 @@ BatcherT = Callable[[Iterable[ItemT]], Iterable[List[ItemT]]] @registry.batchers("spacy.batch_by_padded.v1") def configure_minibatch_by_padded_size( *, - size: Sizing, + size: SizingSchedule, buffer: int, discard_oversize: bool, get_length: Optional[Callable[[ItemT], int]] = None @@ -25,8 +26,8 @@ def configure_minibatch_by_padded_size( The padded size is defined as the maximum length of sequences within the batch multiplied by the number of sequences in the batch. - size (int or Sequence[int]): The largest padded size to batch sequences into. - Can be a single integer, or a sequence, allowing for variable batch sizes. + size (int, Iterable[int] or Schedule): The largest padded size to batch sequences + into. Can be a single integer, or a sequence, allowing for variable batch sizes. buffer (int): The number of sequences to accumulate before sorting by length. A larger buffer will result in more even sizing, but if the buffer is very large, the iteration order will be less random, which can result @@ -40,7 +41,7 @@ def configure_minibatch_by_padded_size( optionals = {"get_length": get_length} if get_length is not None else {} return partial( minibatch_by_padded_size, - size=size, + size=_schedule_to_sizing(size), buffer=buffer, discard_oversize=discard_oversize, **optionals @@ -50,14 +51,14 @@ def configure_minibatch_by_padded_size( @registry.batchers("spacy.batch_by_words.v1") def configure_minibatch_by_words( *, - size: Sizing, + size: SizingSchedule, tolerance: float, discard_oversize: bool, get_length: Optional[Callable[[ItemT], int]] = None ) -> BatcherT: """Create a batcher that uses the "minibatch by words" strategy. - size (int or Sequence[int]): The target number of words per batch. + size (int, Iterable[int] or Schedule): The target number of words per batch. Can be a single integer, or a sequence, allowing for variable batch sizes. tolerance (float): What percentage of the size to allow batches to exceed. discard_oversize (bool): Whether to discard sequences that by themselves @@ -68,7 +69,7 @@ def configure_minibatch_by_words( optionals = {"get_length": get_length} if get_length is not None else {} return partial( minibatch_by_words, - size=size, + size=_schedule_to_sizing(size), tolerance=tolerance, discard_oversize=discard_oversize, **optionals @@ -77,15 +78,15 @@ def configure_minibatch_by_words( @registry.batchers("spacy.batch_by_sequence.v1") def configure_minibatch( - size: Sizing, get_length: Optional[Callable[[ItemT], int]] = None + size: SizingSchedule, get_length: Optional[Callable[[ItemT], int]] = None ) -> BatcherT: """Create a batcher that creates batches of the specified size. - size (int or Sequence[int]): The target number of items per batch. + size (int, Iterable[int] or Schedule): The target number of items per batch. Can be a single integer, or a sequence, allowing for variable batch sizes. """ optionals = {"get_length": get_length} if get_length is not None else {} - return partial(minibatch, size=size, **optionals) + return partial(minibatch, size=_schedule_to_sizing(size), **optionals) def minibatch_by_padded_size( @@ -101,7 +102,7 @@ def minibatch_by_padded_size( The padded size is defined as the maximum length of sequences within the batch multiplied by the number of sequences in the batch. - size (int or Sequence[int]): The largest padded size to batch sequences into. + size (int or Iterable[int]): The largest padded size to batch sequences into. buffer (int): The number of sequences to accumulate before sorting by length. A larger buffer will result in more even sizing, but if the buffer is very large, the iteration order will be less random, which can result @@ -112,13 +113,12 @@ def minibatch_by_padded_size( The `len` function is used by default. """ if isinstance(size, int): - size_ = constant_schedule(size) + size_: Iterator[int] = itertools.repeat(size) else: - assert isinstance(size, Schedule) - size_ = size - for step, outer_batch in enumerate(minibatch(seqs, size=buffer)): + size_ = iter(size) + for outer_batch in minibatch(seqs, size=buffer): outer_batch = list(outer_batch) - target_size = size_(step) + target_size = next(size_) for indices in _batch_by_length(outer_batch, target_size, get_length): subbatch = [outer_batch[i] for i in indices] padded_size = max(len(seq) for seq in subbatch) * len(subbatch) @@ -140,7 +140,7 @@ def minibatch_by_words( themselves, or be discarded if discard_oversize=True. seqs (Iterable[Sequence]): The sequences to minibatch. - size (int or Sequence[int]): The target number of words per batch. + size (int or Iterable[int]): The target number of words per batch. Can be a single integer, or a sequence, allowing for variable batch sizes. tolerance (float): What percentage of the size to allow batches to exceed. discard_oversize (bool): Whether to discard sequences that by themselves @@ -149,12 +149,10 @@ def minibatch_by_words( item. The `len` function is used by default. """ if isinstance(size, int): - size_ = constant_schedule(size) + size_: Iterator[int] = itertools.repeat(size) else: - assert isinstance(size, Schedule) - size_ = size - step = 0 - target_size = size_(step) + size_ = iter(size) + target_size = next(size_) tol_size = target_size * tolerance batch = [] overflow = [] @@ -179,8 +177,7 @@ def minibatch_by_words( else: if batch: yield batch - step += 1 - target_size = size_(step) + target_size = next(size_) tol_size = target_size * tolerance batch = overflow batch_size = overflow_size @@ -198,8 +195,7 @@ def minibatch_by_words( else: if batch: yield batch - step += 1 - target_size = size_(step) + target_size = next(size_) tol_size = target_size * tolerance batch = [seq] batch_size = n_words @@ -236,3 +232,9 @@ def _batch_by_length( batches = [list(sorted(batch)) for batch in batches] batches.reverse() return batches + + +def _schedule_to_sizing(size: SizingSchedule) -> Sizing: + if isinstance(size, Schedule): + return size.to_generator() + return size diff --git a/spacy/util.py b/spacy/util.py index 63af4c85d..1dec50872 100644 --- a/spacy/util.py +++ b/spacy/util.py @@ -1583,12 +1583,12 @@ def minibatch(items, size): so that batch-size can vary on each step. """ if isinstance(size, int): - size_ = constant_schedule(size) + size_ = itertools.repeat(size) else: - size_ = size + size_ = iter(size) items = iter(items) - for step in itertools.count(): - batch_size = size_(step) + while True: + batch_size = next(size_) batch = list(itertools.islice(items, int(batch_size))) if len(batch) == 0: break diff --git a/website/docs/api/top-level.mdx b/website/docs/api/top-level.mdx index 7e47d324a..39d7f8f3f 100644 --- a/website/docs/api/top-level.mdx +++ b/website/docs/api/top-level.mdx @@ -751,14 +751,14 @@ themselves, or be discarded if `discard_oversize` is set to `True`. The argument > get_length = null > ``` -| Name | Description | -| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `seqs` | The sequences to minibatch. ~~Iterable[Any]~~ | -| `size` | The target number of words per batch. Can also be a block referencing a schedule, e.g. [`compounding`](https://thinc.ai/docs/api-schedules/#compounding). ~~Union[int, Sequence[int]]~~ | -| `tolerance` | What percentage of the size to allow batches to exceed. ~~float~~ | -| `discard_oversize` | Whether to discard sequences that by themselves exceed the tolerated size. ~~bool~~ | -| `get_length` | Optional function that receives a sequence item and returns its length. Defaults to the built-in `len()` if not set. ~~Optional[Callable[[Any], int]]~~ | -| **CREATES** | The batcher that takes an iterable of items and returns batches. ~~Callable[[Iterable[Any]], Iterable[List[Any]]]~~ | +| Name | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `seqs` | The sequences to minibatch. ~~Iterable[Any]~~ | +| `size` | The target number of words per batch. Can also be a block referencing a schedule, e.g. [`compounding`](https://thinc.ai/docs/api-schedules/#compounding). ~~Union[int, Iterable[int], Schedule]~~ | +| `tolerance` | What percentage of the size to allow batches to exceed. ~~float~~ | +| `discard_oversize` | Whether to discard sequences that by themselves exceed the tolerated size. ~~bool~~ | +| `get_length` | Optional function that receives a sequence item and returns its length. Defaults to the built-in `len()` if not set. ~~Optional[Callable[[Any], int]]~~ | +| **CREATES** | The batcher that takes an iterable of items and returns batches. ~~Callable[[Iterable[Any]], Iterable[List[Any]]]~~ | ### spacy.batch_by_sequence.v1 {id="batch_by_sequence",tag="registered function"} @@ -773,11 +773,11 @@ themselves, or be discarded if `discard_oversize` is set to `True`. The argument Create a batcher that creates batches of the specified size. -| Name | Description | -| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `size` | The target number of items per batch. Can also be a block referencing a schedule, e.g. [`compounding`](https://thinc.ai/docs/api-schedules/#compounding). ~~Union[int, Sequence[int]]~~ | -| `get_length` | Optional function that receives a sequence item and returns its length. Defaults to the built-in `len()` if not set. ~~Optional[Callable[[Any], int]]~~ | -| **CREATES** | The batcher that takes an iterable of items and returns batches. ~~Callable[[Iterable[Any]], Iterable[List[Any]]]~~ | +| Name | Description | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `size` | The target number of items per batch. Can also be a block referencing a schedule, e.g. [`compounding`](https://thinc.ai/docs/api-schedules/#compounding). ~~Union[int, Iterable[int], Schedule]~~ | +| `get_length` | Optional function that receives a sequence item and returns its length. Defaults to the built-in `len()` if not set. ~~Optional[Callable[[Any], int]]~~ | +| **CREATES** | The batcher that takes an iterable of items and returns batches. ~~Callable[[Iterable[Any]], Iterable[List[Any]]]~~ | ### spacy.batch_by_padded.v1 {id="batch_by_padded",tag="registered function"} @@ -799,7 +799,7 @@ sequences in the batch. | Name | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `size` | The largest padded size to batch sequences into. Can also be a block referencing a schedule, e.g. [`compounding`](https://thinc.ai/docs/api-schedules/#compounding). ~~Union[int, Sequence[int]]~~ | +| `size` | The largest padded size to batch sequences into. Can also be a block referencing a schedule, e.g. [`compounding`](https://thinc.ai/docs/api-schedules/#compounding). ~~Union[int, Iterable[int], Schedule]~~ | | `buffer` | The number of sequences to accumulate before sorting by length. A larger buffer will result in more even sizing, but if the buffer is very large, the iteration order will be less random, which can result in suboptimal training. ~~int~~ | | `discard_oversize` | Whether to discard sequences that are by themselves longer than the largest padded batch size. ~~bool~~ | | `get_length` | Optional function that receives a sequence item and returns its length. Defaults to the built-in `len()` if not set. ~~Optional[Callable[[Any], int]]~~ | @@ -1401,7 +1401,7 @@ vary on each step. | Name | Description | | ---------- | ------------------------------------------------ | | `items` | The items to batch up. ~~Iterable[Any]~~ | -| `size` | The batch size(s). ~~Union[int, Sequence[int]]~~ | +| `size` | The batch size(s). ~~Union[int, Iterable[int]]~~ | | **YIELDS** | The batches. | ### util.filter_spans {id="util.filter_spans",tag="function",version="2.1.4"} From 6348a7a4b4af0e5a4df02df9432b251a0888680b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20de=20Kok?= Date: Thu, 19 Jan 2023 09:25:34 +0100 Subject: [PATCH 040/123] Set version to v4.0.0.dev0 (#12126) --- spacy/about.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spacy/about.py b/spacy/about.py index 640e9e93b..eddbeea09 100644 --- a/spacy/about.py +++ b/spacy/about.py @@ -1,6 +1,6 @@ # fmt: off __title__ = "spacy" -__version__ = "3.5.0" +__version__ = "4.0.0.dev0" __download_url__ = "https://github.com/explosion/spacy-models/releases/download" __compatibility__ = "https://raw.githubusercontent.com/explosion/spacy-models/master/compatibility.json" __projects__ = "https://github.com/explosion/projects" From 3b8918e166ba1aa09ec36dc95d745940d2dbbee7 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Thu, 19 Jan 2023 13:29:17 +0100 Subject: [PATCH 041/123] API docs: Rename kb_in_memory to inmemorylookupkb, add to sidebar (#12128) * API docs: Rename kb_in_memory to inmemorylookupkb, add to sidebar * adjust to mdx * linkout to InMemoryLookupKB at first occurrence in kb.mdx * fix links to docs * revert Azure trigger setting (I'll make a separate PR) Co-authored-by: svlandeg --- spacy/kb/kb_in_memory.pyx | 2 +- website/docs/api/entitylinker.mdx | 2 +- ...{kb_in_memory.mdx => inmemorylookupkb.mdx} | 13 +++++++------ website/docs/api/kb.mdx | 19 ++++++++++--------- website/docs/usage/101/_architecture.mdx | 2 +- website/meta/sidebars.json | 1 + 6 files changed, 21 insertions(+), 18 deletions(-) rename website/docs/api/{kb_in_memory.mdx => inmemorylookupkb.mdx} (96%) diff --git a/spacy/kb/kb_in_memory.pyx b/spacy/kb/kb_in_memory.pyx index 485e52c2f..edba523cf 100644 --- a/spacy/kb/kb_in_memory.pyx +++ b/spacy/kb/kb_in_memory.pyx @@ -25,7 +25,7 @@ cdef class InMemoryLookupKB(KnowledgeBase): """An `InMemoryLookupKB` instance stores unique identifiers for entities and their textual aliases, to support entity linking of named entities to real-world concepts. - DOCS: https://spacy.io/api/kb_in_memory + DOCS: https://spacy.io/api/inmemorylookupkb """ def __init__(self, Vocab vocab, entity_vector_length): diff --git a/website/docs/api/entitylinker.mdx b/website/docs/api/entitylinker.mdx index 5c30d252e..bafb2f2da 100644 --- a/website/docs/api/entitylinker.mdx +++ b/website/docs/api/entitylinker.mdx @@ -15,7 +15,7 @@ world". It requires a `KnowledgeBase`, as well as a function to generate plausible candidates from that `KnowledgeBase` given a certain textual mention, and a machine learning model to pick the right candidate, given the local context of the mention. `EntityLinker` defaults to using the -[`InMemoryLookupKB`](/api/kb_in_memory) implementation. +[`InMemoryLookupKB`](/api/inmemorylookupkb) implementation. ## Assigned Attributes {id="assigned-attributes"} diff --git a/website/docs/api/kb_in_memory.mdx b/website/docs/api/inmemorylookupkb.mdx similarity index 96% rename from website/docs/api/kb_in_memory.mdx rename to website/docs/api/inmemorylookupkb.mdx index e85b63c45..c24fe78d6 100644 --- a/website/docs/api/kb_in_memory.mdx +++ b/website/docs/api/inmemorylookupkb.mdx @@ -43,7 +43,7 @@ The length of the fixed-size entity vectors in the knowledge base. Add an entity to the knowledge base, specifying its corpus frequency and entity vector, which should be of length -[`entity_vector_length`](/api/kb_in_memory#entity_vector_length). +[`entity_vector_length`](/api/inmemorylookupkb#entity_vector_length). > #### Example > @@ -79,8 +79,9 @@ frequency and entity vector for each entity. Add an alias or mention to the knowledge base, specifying its potential KB identifiers and their prior probabilities. The entity identifiers should refer -to entities previously added with [`add_entity`](/api/kb_in_memory#add_entity) -or [`set_entities`](/api/kb_in_memory#set_entities). The sum of the prior +to entities previously added with +[`add_entity`](/api/inmemorylookupkb#add_entity) or +[`set_entities`](/api/inmemorylookupkb#set_entities). The sum of the prior probabilities should not exceed 1. Note that an empty string can not be used as alias. @@ -156,7 +157,7 @@ Get a list of all aliases in the knowledge base. Given a certain textual mention as input, retrieve a list of candidate entities of type [`Candidate`](/api/kb#candidate). Wraps -[`get_alias_candidates()`](/api/kb_in_memory#get_alias_candidates). +[`get_alias_candidates()`](/api/inmemorylookupkb#get_alias_candidates). > #### Example > @@ -174,7 +175,7 @@ of type [`Candidate`](/api/kb#candidate). Wraps ## InMemoryLookupKB.get_candidates_batch {id="get_candidates_batch",tag="method"} -Same as [`get_candidates()`](/api/kb_in_memory#get_candidates), but for an +Same as [`get_candidates()`](/api/inmemorylookupkb#get_candidates), but for an arbitrary number of mentions. The [`EntityLinker`](/api/entitylinker) component will call `get_candidates_batch()` instead of `get_candidates()`, if the config parameter `candidates_batch_size` is greater or equal than 1. @@ -231,7 +232,7 @@ Given a certain entity ID, retrieve its pretrained entity vector. ## InMemoryLookupKB.get_vectors {id="get_vectors",tag="method"} -Same as [`get_vector()`](/api/kb_in_memory#get_vector), but for an arbitrary +Same as [`get_vector()`](/api/inmemorylookupkb#get_vector), but for an arbitrary number of entity IDs. The default implementation of `get_vectors()` executes `get_vector()` in a loop. diff --git a/website/docs/api/kb.mdx b/website/docs/api/kb.mdx index 887b7fe97..2b0d4d9d6 100644 --- a/website/docs/api/kb.mdx +++ b/website/docs/api/kb.mdx @@ -21,8 +21,8 @@ functions called by the [`EntityLinker`](/api/entitylinker) component. This class was not abstract up to spaCy version 3.5. The `KnowledgeBase` -implementation up to that point is available as `InMemoryLookupKB` from 3.5 -onwards. +implementation up to that point is available as +[`InMemoryLookupKB`](/api/inmemorylookupkb) from 3.5 onwards. @@ -110,14 +110,15 @@ to you. From spaCy 3.5 on `KnowledgeBase` is an abstract class (with -[`InMemoryLookupKB`](/api/kb_in_memory) being a drop-in replacement) to allow -more flexibility in customizing knowledge bases. Some of its methods were moved -to [`InMemoryLookupKB`](/api/kb_in_memory) during this refactoring, one of those -being `get_alias_candidates()`. This method is now available as -[`InMemoryLookupKB.get_alias_candidates()`](/api/kb_in_memory#get_alias_candidates). -Note: [`InMemoryLookupKB.get_candidates()`](/api/kb_in_memory#get_candidates) +[`InMemoryLookupKB`](/api/inmemorylookupkb) being a drop-in replacement) to +allow more flexibility in customizing knowledge bases. Some of its methods were +moved to [`InMemoryLookupKB`](/api/inmemorylookupkb) during this refactoring, +one of those being `get_alias_candidates()`. This method is now available as +[`InMemoryLookupKB.get_alias_candidates()`](/api/inmemorylookupkb#get_alias_candidates). +Note: +[`InMemoryLookupKB.get_candidates()`](/api/inmemorylookupkb#get_candidates) defaults to -[`InMemoryLookupKB.get_alias_candidates()`](/api/kb_in_memory#get_alias_candidates). +[`InMemoryLookupKB.get_alias_candidates()`](/api/inmemorylookupkb#get_alias_candidates). ## KnowledgeBase.get_vector {id="get_vector",tag="method"} diff --git a/website/docs/usage/101/_architecture.mdx b/website/docs/usage/101/_architecture.mdx index 5727c6921..2a63a3741 100644 --- a/website/docs/usage/101/_architecture.mdx +++ b/website/docs/usage/101/_architecture.mdx @@ -79,7 +79,7 @@ operates on a `Doc` and gives you access to the matched tokens **in context**. | ------------------------------------------------ | -------------------------------------------------------------------------------------------------- | | [`Corpus`](/api/corpus) | Class for managing annotated corpora for training and evaluation data. | | [`KnowledgeBase`](/api/kb) | Abstract base class for storage and retrieval of data for entity linking. | -| [`InMemoryLookupKB`](/api/kb_in_memory) | Implementation of `KnowledgeBase` storing all data in memory. | +| [`InMemoryLookupKB`](/api/inmemorylookupkb) | Implementation of `KnowledgeBase` storing all data in memory. | | [`Candidate`](/api/kb#candidate) | Object associating a textual mention with a specific entity contained in a `KnowledgeBase`. | | [`Lookups`](/api/lookups) | Container for convenient access to large lookup tables and dictionaries. | | [`MorphAnalysis`](/api/morphology#morphanalysis) | A morphological analysis. | diff --git a/website/meta/sidebars.json b/website/meta/sidebars.json index 339e4085b..bf3fa13e9 100644 --- a/website/meta/sidebars.json +++ b/website/meta/sidebars.json @@ -129,6 +129,7 @@ "items": [ { "text": "Attributes", "url": "/api/attributes" }, { "text": "Corpus", "url": "/api/corpus" }, + { "text": "InMemoryLookupKB", "url": "/api/inmemorylookupkb" }, { "text": "KnowledgeBase", "url": "/api/kb" }, { "text": "Lookups", "url": "/api/lookups" }, { "text": "MorphAnalysis", "url": "/api/morphology#morphanalysis" }, From 0f5d8a27f2848740dc9915e5e3b913e9f5568598 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Thu, 19 Jan 2023 16:13:04 +0100 Subject: [PATCH 042/123] 3.5 usage page (#12057) * skeleton * Fill in non-CLI details from release notes draft * Add TODO for fuzzy matching * Website updates for v3-5 draft * Fill in usage examples * Add fuzzy matching to intro * Fix fuzzy examples * Shell example formatting * Fix typo * Format * Remove trailing periods in internal list * Update * Fix spacing for nested lists * Update InMemoryLookupKB link Co-authored-by: Adriane Boyd Co-authored-by: Ines Montani --- website/docs/usage/v3-5.mdx | 215 ++++++++++++++++++++++++++++ website/meta/sidebars.json | 3 +- website/src/styles/list.module.sass | 4 + website/src/templates/index.js | 4 +- 4 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 website/docs/usage/v3-5.mdx diff --git a/website/docs/usage/v3-5.mdx b/website/docs/usage/v3-5.mdx new file mode 100644 index 000000000..ac61338e3 --- /dev/null +++ b/website/docs/usage/v3-5.mdx @@ -0,0 +1,215 @@ +--- +title: What's New in v3.5 +teaser: New features and how to upgrade +menu: + - ['New Features', 'features'] + - ['Upgrading Notes', 'upgrading'] +--- + +## New features {id="features",hidden="true"} + +spaCy v3.5 introduces three new CLI commands, `apply`, `benchmark` and +`find-threshold`, adds fuzzy matching, provides improvements to our entity +linking functionality, and includes a range of language updates and bug fixes. + +### New CLI commands {id="cli"} + +#### apply CLI + +The [`apply` CLI](/api/cli#apply) can be used to apply a pipeline to one or more +`.txt`, `.jsonl` or `.spacy` input files, saving the annotated docs in a single +`.spacy` file. + +```bash +$ spacy apply en_core_web_sm my_texts/ output.spacy +``` + +#### benchmark CLI + +The [`benchmark` CLI](/api/cli#benchmark) has been added to extend the existing +`evaluate` functionality with a wider range of profiling subcommands. + +The `benchmark accuracy` CLI is introduced as an alias for `evaluate`. The new +`benchmark speed` CLI performs warmup rounds before measuring the speed in words +per second on batches of randomly shuffled documents from the provided data. + +```bash +$ spacy benchmark speed my_pipeline data.spacy +``` + +The output is the mean performance using batches (`nlp.pipe`) with a 95% +confidence interval, e.g., profiling `en_core_web_sm` on CPU: + +```none +Outliers: 2.0%, extreme outliers: 0.0% +Mean: 18904.1 words/s (95% CI: -256.9 +244.1) +``` + +#### find-threshold CLI + +The [`find-threshold` CLI](/api/cli#find-threshold) runs a series of trials +across threshold values from `0.0` to `1.0` and identifies the best threshold +for the provided score metric. + +The following command runs 20 trials for the `spancat` component in +`my_pipeline`, recording the `spans_sc_f` score for each value of the threshold +`[components.spancat.threshold]` from `0.0` to `1.0`: + +```bash +$ spacy find-threshold my_pipeline data.spacy spancat threshold spans_sc_f --n_trials 20 +``` + +The `find-threshold` CLI can be used with `textcat_multilabel`, `spancat` and +custom components with thresholds that are applied while predicting or scoring. + +### Fuzzy matching {id="fuzzy"} + +New `FUZZY` operators support [fuzzy matching](/usage/rule-based-matching#fuzzy) +with the `Matcher`. By default, the `FUZZY` operator allows a Levenshtein edit +distance of 2 and up to 30% of the pattern string length. `FUZZY1`..`FUZZY9` can +be used to specify the exact number of allowed edits. + +```python +# Match lowercase with fuzzy matching (allows up to 3 edits) +pattern = [{"LOWER": {"FUZZY": "definitely"}}] + +# Match custom attribute values with fuzzy matching (allows up to 3 edits) +pattern = [{"_": {"country": {"FUZZY": "Kyrgyzstan"}}}] + +# Match with exact Levenshtein edit distance limits (allows up to 4 edits) +pattern = [{"_": {"country": {"FUZZY4": "Kyrgyzstan"}}}] +``` + +Note that `FUZZY` uses Levenshtein edit distance rather than Damerau-Levenshtein +edit distance, so a transposition like `teh` for `the` counts as two edits, one +insertion and one deletion. + +If you'd prefer an alternate fuzzy matching algorithm, you can provide your own +custom method to the `Matcher` or as a config option for an entity ruler and +span ruler. + +### FUZZY and REGEX with lists {id="fuzzy-regex-lists"} + +The `FUZZY` and `REGEX` operators are also now supported for lists with `IN` and +`NOT_IN`: + +```python +pattern = [{"TEXT": {"FUZZY": {"IN": ["awesome", "cool", "wonderful"]}}}] +pattern = [{"TEXT": {"REGEX": {"NOT_IN": ["^awe(some)?$", "^wonder(ful)?"]}}}] +``` + +### Entity linking generalization {id="el"} + +The knowledge base used for entity linking is now easier to customize and has a +new default implementation [`InMemoryLookupKB`](/api/inmemorylookupkb). + +### Additional features and improvements {id="additional-features-and-improvements"} + +- Language updates: + - Extended support for Slovenian + - Fixed lookup fallback for French and Catalan lemmatizers + - Switch Russian and Ukrainian lemmatizers to `pymorphy3` + - Support for editorial punctuation in Ancient Greek + - Update to Russian tokenizer exceptions + - Small fix for Dutch stop words +- Allow up to `typer` v0.7.x, `mypy` 0.990 and `typing_extensions` v4.4.x. +- New `spacy.ConsoleLogger.v3` with expanded progress + [tracking](/api/top-level#ConsoleLogger). +- Improved scoring behavior for `textcat` with `spacy.textcat_scorer.v2` and + `spacy.textcat_multilabel_scorer.v2`. +- Updates so that downstream components can train properly on a frozen `tok2vec` + or `transformer` layer. +- Allow interpolation of variables in directory names in projects. +- Support for local file system [remotes](/usage/projects#remote) for projects. +- Improve UX around `displacy.serve` when the default port is in use. +- Optional `before_update` callback that is invoked at the start of each + [training step](/api/data-formats#config-training). +- Improve performance of `SpanGroup` and fix typing issues for `SpanGroup` and + `Span` objects. +- Patch a + [security vulnerability](https://github.com/advisories/GHSA-gw9q-c7gh-j9vm) in + extracting tar files. +- Add equality definition for `Vectors`. +- Ensure `Vocab.to_disk` respects the exclude setting for `lookups` and + `vectors`. +- Correctly handle missing annotations in the edit tree lemmatizer. + +### Trained pipeline updates {id="pipelines"} + +- The CNN pipelines add `IS_SPACE` as a `tok2vec` feature for `tagger` and + `morphologizer` components to improve tagging of non-whitespace vs. whitespace + tokens. +- The transformer pipelines require `spacy-transformers` v1.2, which uses the + exact alignment from `tokenizers` for fast tokenizers instead of the heuristic + alignment from `spacy-alignments`. For all trained pipelines except + `ja_core_news_trf`, the alignments between spaCy tokens and transformer tokens + may be slightly different. More details about the `spacy-transformers` changes + in the + [v1.2.0 release notes](https://github.com/explosion/spacy-transformers/releases/tag/v1.2.0). + +## Notes about upgrading from v3.4 {id="upgrading"} + +### Validation of textcat values {id="textcat-validation"} + +An error is now raised when unsupported values are given as input to train a +`textcat` or `textcat_multilabel` model - ensure that values are `0.0` or `1.0` +as explained in the [docs](/api/textcategorizer#assigned-attributes). + +### Updated scorers for tokenization and textcat {id="scores"} + +We fixed a bug that inflated the `token_acc` scores in v3.0-v3.4. The reported +`token_acc` will drop from v3.4 to v3.5, but if `token_p/r/f` stay the same, +your tokenization performance has not changed from v3.4. + +For new `textcat` or `textcat_multilabel` configs, the new default `v2` scorers: + +- ignore `threshold` for `textcat`, so the reported `cats_p/r/f` may increase + slightly in v3.5 even though the underlying predictions are unchanged +- report the performance of only the **final** `textcat` or `textcat_multilabel` + component in the pipeline by default +- allow custom scorers to be used to score multiple `textcat` and + `textcat_multilabel` components with `Scorer.score_cats` by restricting the + evaluation to the component's provided labels + +### Pipeline package version compatibility {id="version-compat"} + +> #### Using legacy implementations +> +> In spaCy v3, you'll still be able to load and reference legacy implementations +> via [`spacy-legacy`](https://github.com/explosion/spacy-legacy), even if the +> components or architectures change and newer versions are available in the +> core library. + +When you're loading a pipeline package trained with an earlier version of spaCy +v3, you will see a warning telling you that the pipeline may be incompatible. +This doesn't necessarily have to be true, but we recommend running your +pipelines against your test suite or evaluation data to make sure there are no +unexpected results. + +If you're using one of the [trained pipelines](/models) we provide, you should +run [`spacy download`](/api/cli#download) to update to the latest version. To +see an overview of all installed packages and their compatibility, you can run +[`spacy validate`](/api/cli#validate). + +If you've trained your own custom pipeline and you've confirmed that it's still +working as expected, you can update the spaCy version requirements in the +[`meta.json`](/api/data-formats#meta): + +```diff +- "spacy_version": ">=3.4.0,<3.5.0", ++ "spacy_version": ">=3.4.0,<3.6.0", +``` + +### Updating v3.4 configs + +To update a config from spaCy v3.4 with the new v3.5 settings, run +[`init fill-config`](/api/cli#init-fill-config): + +```cli +$ python -m spacy init fill-config config-v3.4.cfg config-v3.5.cfg +``` + +In many cases ([`spacy train`](/api/cli#train), +[`spacy.load`](/api/top-level#spacy.load)), the new defaults will be filled in +automatically, but you'll need to fill in the new settings to run +[`debug config`](/api/cli#debug) and [`debug data`](/api/cli#debug-data). diff --git a/website/meta/sidebars.json b/website/meta/sidebars.json index bf3fa13e9..b5c555da6 100644 --- a/website/meta/sidebars.json +++ b/website/meta/sidebars.json @@ -13,7 +13,8 @@ { "text": "New in v3.1", "url": "/usage/v3-1" }, { "text": "New in v3.2", "url": "/usage/v3-2" }, { "text": "New in v3.3", "url": "/usage/v3-3" }, - { "text": "New in v3.4", "url": "/usage/v3-4" } + { "text": "New in v3.4", "url": "/usage/v3-4" }, + { "text": "New in v3.5", "url": "/usage/v3-5" } ] }, { diff --git a/website/src/styles/list.module.sass b/website/src/styles/list.module.sass index 1a352d9dd..2fb9ab8ef 100644 --- a/website/src/styles/list.module.sass +++ b/website/src/styles/list.module.sass @@ -20,6 +20,10 @@ display: inline-block margin-bottom: var(--spacing-sm) + .ol, .ul + margin-top: var(--spacing-xs) + margin-bottom: var(--spacing-xs) + &:before content: '\25CF' position: relative diff --git a/website/src/templates/index.js b/website/src/templates/index.js index aa7595ddc..80b5a24d4 100644 --- a/website/src/templates/index.js +++ b/website/src/templates/index.js @@ -58,8 +58,8 @@ const AlertSpace = ({ nightly, legacy }) => { } const navAlert = ( - - 💥 Out now: spaCy v3.4 + + 💥 Out now: spaCy v3.5 ) From dec81508d28b47f09a06203c472b37f00db6c869 Mon Sep 17 00:00:00 2001 From: Adriane Boyd Date: Thu, 19 Jan 2023 16:13:41 +0100 Subject: [PATCH 043/123] Update README for v3.5 (#12132) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 195424551..49aa6796e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ production-ready [**training system**](https://spacy.io/usage/training) and easy model packaging, deployment and workflow management. spaCy is commercial open-source software, released under the [MIT license](https://github.com/explosion/spaCy/blob/master/LICENSE). -💫 **Version 3.4 out now!** +💫 **Version 3.5 out now!** [Check out the release notes here.](https://github.com/explosion/spaCy/releases) [![Azure Pipelines](https://img.shields.io/azure-devops/build/explosion-ai/public/8/master.svg?logo=azure-pipelines&style=flat-square&label=build)](https://dev.azure.com/explosion-ai/public/_build?definitionId=8) From 8a3ca77d9ec548655cffe8d98a0b66c306c55b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Bl=C3=A4ttermann?= Date: Fri, 20 Jan 2023 16:57:43 +0100 Subject: [PATCH 044/123] Fix broken social media image (#12137) --- website/src/components/seo.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/website/src/components/seo.js b/website/src/components/seo.js index 5d12ffa04..d338c43f3 100644 --- a/website/src/components/seo.js +++ b/website/src/components/seo.js @@ -9,6 +9,8 @@ import socialImageLegacy from '../images/social_legacy.jpg' import siteMetadata from '../../meta/site.json' import Head from 'next/head' +import { siteUrl } from '../../meta/dynamicMeta.mjs' + function getPageTitle(title, sitename, slogan, sectionTitle, nightly, legacy) { if (sectionTitle && title) { const suffix = nightly ? ' (nightly)' : legacy ? ' (legacy)' : '' @@ -25,7 +27,7 @@ function getImage(section, nightly, legacy) { if (legacy) return socialImageLegacy if (section === 'api') return socialImageApi if (section === 'universe') return socialImageUniverse - return socialImageDefault + return `${siteUrl}${socialImageDefault.src}` } export default function SEO({ @@ -46,7 +48,7 @@ export default function SEO({ nightly, legacy ) - const socialImage = getImage(section, nightly, legacy).src + const socialImage = getImage(section, nightly, legacy) const meta = [ { name: 'description', From f9e020dd672b16f04cc8672d44ad7aab3b4ad424 Mon Sep 17 00:00:00 2001 From: Richard Hudson Date: Fri, 20 Jan 2023 19:34:11 +0100 Subject: [PATCH 045/123] Fix speed problem with `top_k>1` on CPU in edit tree lemmatizer (#12017) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor _scores2guesses * Handle arrays on GPU * Convert argmax result to raw integer Co-authored-by: Madeesh Kannan * Use NumpyOps() to copy data to CPU Co-authored-by: Madeesh Kannan * Changes based on review comments * Use different _scores2guesses depending on tree_k * Add tests for corner cases * Add empty line for consistency * Improve naming Co-authored-by: Daniël de Kok * Improve naming Co-authored-by: Daniël de Kok Co-authored-by: Madeesh Kannan Co-authored-by: Daniël de Kok --- spacy/pipeline/edit_tree_lemmatizer.py | 69 ++++++++++++++++--- .../pipeline/test_edit_tree_lemmatizer.py | 17 +++-- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/spacy/pipeline/edit_tree_lemmatizer.py b/spacy/pipeline/edit_tree_lemmatizer.py index e83fe63ba..332badd8c 100644 --- a/spacy/pipeline/edit_tree_lemmatizer.py +++ b/spacy/pipeline/edit_tree_lemmatizer.py @@ -5,8 +5,8 @@ from itertools import islice import numpy as np import srsly -from thinc.api import Config, Model, SequenceCategoricalCrossentropy -from thinc.types import Floats2d, Ints1d, Ints2d +from thinc.api import Config, Model, SequenceCategoricalCrossentropy, NumpyOps +from thinc.types import Floats2d, Ints2d from ._edit_tree_internals.edit_trees import EditTrees from ._edit_tree_internals.schemas import validate_edit_tree @@ -20,6 +20,10 @@ from ..vocab import Vocab from .. import util +# The cutoff value of *top_k* above which an alternative method is used to process guesses. +TOP_K_GUARDRAIL = 20 + + default_model_config = """ [model] @architectures = "spacy.Tagger.v2" @@ -115,6 +119,7 @@ class EditTreeLemmatizer(TrainablePipe): self.cfg: Dict[str, Any] = {"labels": []} self.scorer = scorer + self.numpy_ops = NumpyOps() def get_loss( self, examples: Iterable[Example], scores: List[Floats2d] @@ -144,6 +149,18 @@ class EditTreeLemmatizer(TrainablePipe): return float(loss), d_scores def predict(self, docs: Iterable[Doc]) -> List[Ints2d]: + if self.top_k == 1: + scores2guesses = self._scores2guesses_top_k_equals_1 + elif self.top_k <= TOP_K_GUARDRAIL: + scores2guesses = self._scores2guesses_top_k_greater_1 + else: + scores2guesses = self._scores2guesses_top_k_guardrail + # The behaviour of *_scores2guesses_top_k_greater_1()* is efficient for values + # of *top_k>1* that are likely to be useful when the edit tree lemmatizer is used + # for its principal purpose of lemmatizing tokens. However, the code could also + # be used for other purposes, and with very large values of *top_k* the method + # becomes inefficient. In such cases, *_scores2guesses_top_k_guardrail()* is used + # instead. n_docs = len(list(docs)) if not any(len(doc) for doc in docs): # Handle cases where there are no tokens in any docs. @@ -153,20 +170,52 @@ class EditTreeLemmatizer(TrainablePipe): return guesses scores = self.model.predict(docs) assert len(scores) == n_docs - guesses = self._scores2guesses(docs, scores) + guesses = scores2guesses(docs, scores) assert len(guesses) == n_docs return guesses - def _scores2guesses(self, docs, scores): + def _scores2guesses_top_k_equals_1(self, docs, scores): guesses = [] for doc, doc_scores in zip(docs, scores): - if self.top_k == 1: - doc_guesses = doc_scores.argmax(axis=1).reshape(-1, 1) - else: - doc_guesses = np.argsort(doc_scores)[..., : -self.top_k - 1 : -1] + doc_guesses = doc_scores.argmax(axis=1) + doc_guesses = self.numpy_ops.asarray(doc_guesses) - if not isinstance(doc_guesses, np.ndarray): - doc_guesses = doc_guesses.get() + doc_compat_guesses = [] + for i, token in enumerate(doc): + tree_id = self.cfg["labels"][doc_guesses[i]] + if self.trees.apply(tree_id, token.text) is not None: + doc_compat_guesses.append(tree_id) + else: + doc_compat_guesses.append(-1) + guesses.append(np.array(doc_compat_guesses)) + + return guesses + + def _scores2guesses_top_k_greater_1(self, docs, scores): + guesses = [] + top_k = min(self.top_k, len(self.labels)) + for doc, doc_scores in zip(docs, scores): + doc_scores = self.numpy_ops.asarray(doc_scores) + doc_compat_guesses = [] + for i, token in enumerate(doc): + for _ in range(top_k): + candidate = int(doc_scores[i].argmax()) + candidate_tree_id = self.cfg["labels"][candidate] + if self.trees.apply(candidate_tree_id, token.text) is not None: + doc_compat_guesses.append(candidate_tree_id) + break + doc_scores[i, candidate] = np.finfo(np.float32).min + else: + doc_compat_guesses.append(-1) + guesses.append(np.array(doc_compat_guesses)) + + return guesses + + def _scores2guesses_top_k_guardrail(self, docs, scores): + guesses = [] + for doc, doc_scores in zip(docs, scores): + doc_guesses = np.argsort(doc_scores)[..., : -self.top_k - 1 : -1] + doc_guesses = self.numpy_ops.asarray(doc_guesses) doc_compat_guesses = [] for token, candidates in zip(doc, doc_guesses): diff --git a/spacy/tests/pipeline/test_edit_tree_lemmatizer.py b/spacy/tests/pipeline/test_edit_tree_lemmatizer.py index c4f9b09f3..128d75680 100644 --- a/spacy/tests/pipeline/test_edit_tree_lemmatizer.py +++ b/spacy/tests/pipeline/test_edit_tree_lemmatizer.py @@ -101,14 +101,15 @@ def test_initialize_from_labels(): } -def test_no_data(): +@pytest.mark.parametrize("top_k", (1, 5, 30)) +def test_no_data(top_k): # Test that the lemmatizer provides a nice error when there's no tagging data / labels TEXTCAT_DATA = [ ("I'm so happy.", {"cats": {"POSITIVE": 1.0, "NEGATIVE": 0.0}}), ("I'm so angry", {"cats": {"POSITIVE": 0.0, "NEGATIVE": 1.0}}), ] nlp = English() - nlp.add_pipe("trainable_lemmatizer") + nlp.add_pipe("trainable_lemmatizer", config={"top_k": top_k}) nlp.add_pipe("textcat") train_examples = [] @@ -119,10 +120,11 @@ def test_no_data(): nlp.initialize(get_examples=lambda: train_examples) -def test_incomplete_data(): +@pytest.mark.parametrize("top_k", (1, 5, 30)) +def test_incomplete_data(top_k): # Test that the lemmatizer works with incomplete information nlp = English() - lemmatizer = nlp.add_pipe("trainable_lemmatizer") + lemmatizer = nlp.add_pipe("trainable_lemmatizer", config={"top_k": top_k}) lemmatizer.min_tree_freq = 1 train_examples = [] for t in PARTIAL_DATA: @@ -154,9 +156,10 @@ def test_incomplete_data(): assert xp.count_nonzero(dX[1][1]) == 0 -def test_overfitting_IO(): +@pytest.mark.parametrize("top_k", (1, 5, 30)) +def test_overfitting_IO(top_k): nlp = English() - lemmatizer = nlp.add_pipe("trainable_lemmatizer") + lemmatizer = nlp.add_pipe("trainable_lemmatizer", config={"top_k": top_k}) lemmatizer.min_tree_freq = 1 train_examples = [] for t in TRAIN_DATA: @@ -189,7 +192,7 @@ def test_overfitting_IO(): # Check model after a {to,from}_bytes roundtrip nlp_bytes = nlp.to_bytes() nlp3 = English() - nlp3.add_pipe("trainable_lemmatizer") + nlp3.add_pipe("trainable_lemmatizer", config={"top_k": top_k}) nlp3.from_bytes(nlp_bytes) doc3 = nlp3(test_text) assert doc3[0].lemma_ == "she" From 950fceceb69ef681b689c8021dafaa0205d40806 Mon Sep 17 00:00:00 2001 From: Raphael Mitsch Date: Mon, 23 Jan 2023 14:42:33 +0100 Subject: [PATCH 046/123] Make test_cli_find_threshold() more robust. (#12148) --- spacy/tests/test_cli.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spacy/tests/test_cli.py b/spacy/tests/test_cli.py index d00f66c60..249c44672 100644 --- a/spacy/tests/test_cli.py +++ b/spacy/tests/test_cli.py @@ -1074,7 +1074,7 @@ def test_cli_find_threshold(capsys): ) with make_tempdir() as nlp_dir: nlp.to_disk(nlp_dir) - res = find_threshold( + best_threshold, best_score, res = find_threshold( model=nlp_dir, data_path=docs_dir / "docs.spacy", pipe_name="tc_multi", @@ -1082,10 +1082,10 @@ def test_cli_find_threshold(capsys): scores_key="cats_macro_f", silent=True, ) - assert res[0] != thresholds[0] - assert thresholds[0] < res[0] < thresholds[9] - assert res[1] == 1.0 - assert res[2][1.0] == 0.0 + assert best_threshold != thresholds[0] + assert thresholds[0] < best_threshold < thresholds[9] + assert best_score == max(res.values()) + assert res[1.0] == 0.0 # Test with spancat. nlp, _ = init_nlp((("spancat", {}),)) From e9048fd4a13bc373da87a6f59240a4e3ea402e6f Mon Sep 17 00:00:00 2001 From: Edward <43848523+thomashacker@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:01:22 +0100 Subject: [PATCH 047/123] Add how to load probability tables to existing models to spaCy docs (#12051) * add section about adding tables to models * change to lexeme_norm * Change syntax * change to _prob * Update website/docs/usage/saving-loading.mdx Co-authored-by: Adriane Boyd Co-authored-by: Adriane Boyd --- website/docs/usage/saving-loading.mdx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/website/docs/usage/saving-loading.mdx b/website/docs/usage/saving-loading.mdx index e0daebe35..aad8ea353 100644 --- a/website/docs/usage/saving-loading.mdx +++ b/website/docs/usage/saving-loading.mdx @@ -304,6 +304,28 @@ installed in the same environment – that's it. | `spacy_lookups` | Group of entry points for custom [`Lookups`](/api/lookups), including lemmatizer data. Used by spaCy's [`spacy-lookups-data`](https://github.com/explosion/spacy-lookups-data) package. | | [`spacy_displacy_colors`](#entry-points-displacy) | Group of entry points of custom label colors for the [displaCy visualizer](/usage/visualizers#ent). The key name doesn't matter, but it should point to a dict of labels and color values. Useful for custom models that predict different entity types. | +### Loading probability tables into existing models + +You can load a probability table from [spacy-lookups-data](https://github.com/explosion/spacy-lookups-data) into an existing spaCy model like `en_core_web_sm`. + +```python +# Requirements: pip install spacy-lookups-data +import spacy +from spacy.lookups import load_lookups +nlp = spacy.load("en_core_web_sm") +lookups = load_lookups("en", ["lexeme_prob"]) +nlp.vocab.lookups.add_table("lexeme_prob", lookups.get_table("lexeme_prob")) +``` + +When training a model from scratch you can also specify probability tables in the `config.cfg`. + +```ini {title="config.cfg (excerpt)"} +[initialize.lookups] +@misc = "spacy.LookupsDataLoader.v1" +lang = ${nlp.lang} +tables = ["lexeme_prob"] +``` + ### Custom components via entry points {id="entry-points-components"} When you load a pipeline, spaCy will generally use its `config.cfg` to set up From de1fe8dce35c5d9870dfce4fc047cfeef01fa2f7 Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Tue, 24 Jan 2023 10:02:07 +0100 Subject: [PATCH 048/123] Fix Azure ignoring website files (#12129) * ignore all mdx files and all files in website * have both .md and .mdx * exclude everything but universe.json --- azure-pipelines.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0f7ea91f9..22539a763 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,13 +11,21 @@ trigger: exclude: - "website/*" - "*.md" + - "*.mdx" - ".github/workflows/*" pr: paths: exclude: - "*.md" + - "*.mdx" - "website/docs/*" - "website/src/*" + - "website/meta/*.tsx" + - "website/meta/*.mjs" + - "website/meta/languages.json" + - "website/meta/site.json" + - "website/meta/sidebars.json" + - "website/meta/type-annotations.json" - ".github/workflows/*" jobs: From fcedcd54a8dcd1cd4b86382c7d105b021e2feb4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Bl=C3=A4ttermann?= Date: Tue, 24 Jan 2023 13:51:39 +0100 Subject: [PATCH 049/123] WEB-30 spaCy pattern in `.png` (#12158) * Fix gap in landing pattern at the top * Replace `.jpg` patterns with `.png` This drastically reduces file size (for the landing page from 221kb to 57kb) while doubling the resolution to look sharper on retina displays. --- website/src/components/landing.js | 12 ++++++------ website/src/components/main.js | 10 +++++----- website/src/images/pattern_blue.jpg | Bin 116280 -> 0 bytes website/src/images/pattern_blue.png | Bin 0 -> 48883 bytes website/src/images/pattern_green.jpg | Bin 121676 -> 0 bytes website/src/images/pattern_green.png | Bin 0 -> 48883 bytes website/src/images/pattern_landing.jpg | Bin 103423 -> 0 bytes website/src/images/pattern_landing.png | Bin 0 -> 8015 bytes website/src/images/pattern_landing_legacy.jpg | Bin 88239 -> 0 bytes website/src/images/pattern_landing_legacy.png | Bin 0 -> 8109 bytes website/src/images/pattern_landing_nightly.jpg | Bin 128993 -> 0 bytes website/src/images/pattern_landing_nightly.png | Bin 0 -> 8109 bytes website/src/images/pattern_legacy.jpg | Bin 108939 -> 0 bytes website/src/images/pattern_legacy.png | Bin 0 -> 48883 bytes website/src/images/pattern_nightly.jpg | Bin 160418 -> 0 bytes website/src/images/pattern_nightly.png | Bin 0 -> 48883 bytes website/src/images/pattern_purple.jpg | Bin 114852 -> 0 bytes website/src/images/pattern_purple.png | Bin 0 -> 48883 bytes website/src/styles/landing.module.sass | 13 ++++++++----- website/src/styles/main.module.sass | 1 + website/src/widgets/styleguide.js | 6 +++--- 21 files changed, 23 insertions(+), 19 deletions(-) delete mode 100644 website/src/images/pattern_blue.jpg create mode 100644 website/src/images/pattern_blue.png delete mode 100644 website/src/images/pattern_green.jpg create mode 100644 website/src/images/pattern_green.png delete mode 100644 website/src/images/pattern_landing.jpg create mode 100644 website/src/images/pattern_landing.png delete mode 100644 website/src/images/pattern_landing_legacy.jpg create mode 100644 website/src/images/pattern_landing_legacy.png delete mode 100644 website/src/images/pattern_landing_nightly.jpg create mode 100644 website/src/images/pattern_landing_nightly.png delete mode 100644 website/src/images/pattern_legacy.jpg create mode 100644 website/src/images/pattern_legacy.png delete mode 100644 website/src/images/pattern_nightly.jpg create mode 100644 website/src/images/pattern_nightly.png delete mode 100644 website/src/images/pattern_purple.jpg create mode 100644 website/src/images/pattern_purple.png diff --git a/website/src/components/landing.js b/website/src/components/landing.js index 084587b74..e7c671d7d 100644 --- a/website/src/components/landing.js +++ b/website/src/components/landing.js @@ -1,12 +1,12 @@ import React from 'react' import classNames from 'classnames' -import patternDefault from '../images/pattern_blue.jpg' -import patternNightly from '../images/pattern_nightly.jpg' -import patternLegacy from '../images/pattern_legacy.jpg' -import overlayDefault from '../images/pattern_landing.jpg' -import overlayNightly from '../images/pattern_landing_nightly.jpg' -import overlayLegacy from '../images/pattern_landing_legacy.jpg' +import patternDefault from '../images/pattern_blue.png' +import patternNightly from '../images/pattern_nightly.png' +import patternLegacy from '../images/pattern_legacy.png' +import overlayDefault from '../images/pattern_landing.png' +import overlayNightly from '../images/pattern_landing_nightly.png' +import overlayLegacy from '../images/pattern_landing_legacy.png' import Grid from './grid' import { Content } from './main' diff --git a/website/src/components/main.js b/website/src/components/main.js index da7ab08ed..411423ba6 100644 --- a/website/src/components/main.js +++ b/website/src/components/main.js @@ -2,11 +2,11 @@ import React from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' -import patternBlue from '../images/pattern_blue.jpg' -import patternGreen from '../images/pattern_green.jpg' -import patternPurple from '../images/pattern_purple.jpg' -import patternNightly from '../images/pattern_nightly.jpg' -import patternLegacy from '../images/pattern_legacy.jpg' +import patternBlue from '../images/pattern_blue.png' +import patternGreen from '../images/pattern_green.png' +import patternPurple from '../images/pattern_purple.png' +import patternNightly from '../images/pattern_nightly.png' +import patternLegacy from '../images/pattern_legacy.png' import classes from '../styles/main.module.sass' const patterns = { diff --git a/website/src/images/pattern_blue.jpg b/website/src/images/pattern_blue.jpg deleted file mode 100644 index 78153b9f8cbc3589dd88cdb08a0b7ae642af98ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116280 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 diff --git a/website/src/images/pattern_blue.png b/website/src/images/pattern_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..fa28b0993f4299227c09aa3c6d665a481bdf5f16 GIT binary patch literal 48883 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 diff --git a/website/src/images/pattern_green.png b/website/src/images/pattern_green.png new file mode 100644 index 0000000000000000000000000000000000000000..ab665f2dbef422a801feb12b9c2d9baaefaea6b9 GIT binary patch literal 48883 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

^zr*&={eDxH$T6=F@s%8U!P$T%iKMN zPV)rjL_FwLEwVmDj+?Lsb0~)PBhbK!TyOQKvs#~1A%XB0A8dWZ zq2^zb;9Y_GZD;s_nP%JhS2bc9+vx5z)dj+z<-RzSN$c#ZCRgi^|F@}l>vb{uKAF8< z`4*e!J}QQU7Ex`nDjN)tS*!BP_P+n?M1a~a=e~&q9=*&z9>v~_L=u>GvtTf; zmCR_3^3HWUV@tHqo}ONwau!=M@C~nTh-uRDNa-0s?e$?Qx44(}Vz67ZKu+$@ks7a* zE{FtIeXY(F%6w57B@gG@TBO~su~(U&L5E{8^KX3%srVl;*r(=U>$A9=Q+a?0%5o1F zMmTpg!0qF*hK9|+=N_36z2!yq+_dVzRJ+b*%&C8)Sxc`^H54wNRs6Ou*bzb+CCZXd zEZl%CY=ah#t|lwpx(v!~Y`Gi!;G~p8unFlbWWsj?z^aq~Vzip1WOVsJ7ZCVcRYrne zFR6*eKCGlt)$$h$2TJ{vJ)Gpod2~Myaw1FwYS!Bnpvsld9P2T)2S=nvmzywO#n0`E zf5fhu3><{JU0Q-zCuozI*Q-DxPVMCg>|hKFiQD0e6Wz4Px%((%a$W@tr+0nbPsIUO z(XbJt)PyN6_nfmuIMoLzgd@2>ru1iV_Z!tp7Dq36g0o?v%VNzP06j&{33& zCaiF5;_ZW-NU`*q!6hLzvw+`4AbQ}req8CCTpj+{^CrcccW;lUtT?X$%d)bAb>uT3 z%()OJ<}^1=FgR0A<=zyXp;>+dJO|~MC}xh%3k+G;W(@8f)edoop`#JbvhbH!;L&=Q z_cOEAc6B~l36(OuFS~3gF}%Ut@b604?+-2b6YtNXbG$&4sX>Y1P8|mKiZR$Q%Hn$G z;}k`OlYiWdn$Tf{We~+)<^yq{EMNuYq+*mw1m*66pksLBwBqzC-dJiw2TzwAQ z;4qEr?&q3d?0nm}9^Lhq&Q_&$O3#-U)gPxHoaLMQGTCzb*N8J~&;GTabVv$XvxL;_PFvBQ(~cbCS?*IjU~Fv>)Nqg^q8lquM*rc1P^x zgQxk|v)G{zt@_(Qn!~bGvQ+FC{PXd7=CJEW>%-1y(M za(hn=aWOMh@E91$^BGg*?#ONf+qtl{q(2FzWcyvvoJ#n(Wf5Z~?%8FXjKwfXGFdT0 z*?#I3*7pQQsRpiM(BG3Bpj>;7FS51FDfv9$__>+&`GX<`-)2&|2jY-AkqA_UWeKQ> zP}7{%6_5%o7rLGJ)iMAy{km949vYMqdA=Hk(kmOHizEz1?(*TsOKm^Vq_Nk?se#0t z+3E7Df_RML%QqEUhRql;ht+@nQP|I=L#C(Y3n<*VzNOS49gCt6?4R8yj=eXg)4JYU zHMuhz>)>F1L3cLs;TCA!0-rEa{8yovx^7(p4wlg7#ff4-W4V` zbh13Td$65xW!TCnk!NZ{2FDw#(^o+dkZd3)SVA@on>pRO6L z-mXvE34-t{uP*}>DWPh{WMU=p64CZ>0RU?-l$WInNw1w4z;1it-2ed|I5P)teQg>a ziXnFT06(<}C3sdc>oGw9SL6;5-=+>Khgr|D9A5# zdF8@01t@C_EFPN><BR%{tLLo_@=^%=DHy z+%R@%^3L#<`RoCgPCwclEYFZ-o)@41(LcNeR448$-Ez7w^Sr2mwQGsm2jJr0##ZIL zD@Pb<1i|kY-V_Q@Y|bX;JUH$v6(~LG!P2AdpMUAZC6w8iH3-2{FXfaT+DKc~s#-?= zE?NOHPE+EYsFWZ!DG0q6=ydKJEN;wS{sC)KiIIW_mQ+m+Ol^|JhI?N6BSYxNx8L?E zb?&(JPZ4Z^St#a;-;(#Yn~!Xolacq*`h|4Kt``~9hV8%0{lOiVNd@&-y2vABdqP7m z!GEF+J>cv`(7NvthiHzJbYW?_K@Se+$xj_$1eKE9_Y5)yO^kDhgXfWm%R78uDRTA# zP0a-e!=U;ZO2LXRg*F;al*h%@L^9i z5T!%3wWAbFIt5cx9D9_V#i1^fEE@I#E$W-KAG|C=3TX?WP#@!!C<2BUW$R)u?|V2{HLTv!r_`Z*z4=$I`i+ zy?IBUvo@tw5PDLv8d#EIz3K&3Q^I4ct#7opLpLg+=o0jt4Px?f-Xd`i^O)f=;@5)Y zh2P6?7Cg5ztXyitKRSH!ElT--@Z;zT^mrUrkCO7aIOgWz+bQjj;rcPu2f4VC?B|rx zX7>QA`}ow26Xyt)&Mt6c8|HC^%J|YwMs~#mN{=BneDhW9icU=|Gg>({82)Pb39ve@`=NT-0zO-j_+!aZI8b{^e$-x z+`j-VO$kw+or1Q?2S5yS_J?c8{CeI?Uv6ExYh!f@qQ((Yy_25i&+~m-Ee@-@!$q;t zxY~#9>RA{?ZzO+ZH=)>&r`-~))`cFF9B#Gp z=%^~lxCqs(q&nWVo=Uk0CSkBDCt{F)Wa%j_<869&g`!?dnJBcG{jef=X{QZOmTO@d z1KA-$BJYLd{~i%Ro~-3gjn;$qTHq5y&#P^Vn&xosDqtZ6VmD+=9r$OLLdy~D9VlYU(C@gt_&RkH+rcwQW*&+$? z{=#6vNNTf0kN}0{Md$=xcUJ51p1Y-%n@pGGY7qBU+xctIm3{3T?`8oxB5$T)^Ur}X zwCm^DBZC*J$3Th5Wtu;J#qpeFZTvntI!uy?$&fk5`ro`*)+aUl>IHALSfu~aj8(1~ ztW>NpBl>=%^aRxZdL%6Lna>%`W{ z^TTH&b9W9Mp=-X2-eB@s5N&!;)r_Sq^pbHwz2CNMglBr4A4flp1#&tO_8VB_Nhjv) zPWeN!gM(Yazc};N4?op~b$Rj+`BZV<(MvH&P#Q2yNGgcLR%ll23MBP0-Oqm`&KWel7k$pFF*(TO85cO|vAWjU%Z zE&4Yy=#=q~`kEVNsVjJT0wc55sS^j9F|#Kx(}&g=h4Gk$shNjw;+KYoDf(<>p*P@r z|G6%3%Y3=-`=1Q9@N+gTW+pQsqUv9QRG-!ha^4nuX;X~~WOOf90MW!~{+EtAO_!9i zDRW-*iH&9g^Gk%`jZHjbE{bFq^- zM>kbT{2hh0T$425{&bEX5`Otur}_J0@xz+oz3bKrGILs|ix-UHVa~ZbUz#pgQ4LKU z+FqxYIQ0eyobky}r^rRhgGB7UGfNL2p0a(f8U>BvGR;3e1wRT%KB{tZ*L?DBqZKUzWmgP_(0SB zQKHpH^3;_N#|Eg3NZ{mPeGy0Q7>y4kQe!PNd`R4;5}$=5JIa6JIXL`6Ha}4ghhP<7 zsHB!c$H`>xipJvz;OlSr?VCuO{GX(wHQ;-ja;{_I6CKqdEr*g(qvjk{EJa@`*$laA z7n6|ty<8_0GMK*$s5_Rw#oo}U3d`Q+*1ZZ^%$2v^Tm9oZ=X1~*$7LEtU2uyJMRHcB z^X5wJ&gTg>;E!s^zC6{nPWComI$_Y#cGT|`{iFqG=-Z7J&&#=5qlV&8L-Gxy_*z${ zr^ubpjL0N%9LFwKC{(#y+Ugmhpvl1wC(IOKs%hB=D(L}mHft?fEHc&1?{dCXI=BtI|e_7=c*%7-Ih0)Pn{=mJqa`I zz{hZ&8r$eC)e-&JfOgZ!UiBW|+K9PxVRQ?m-2C<`TPrQJ{x=;iQM%O?fxOS|xi(xn*c!9L3fa9EJJ z+w%Tu1pB;K;;O~YF+tKk7jRgM($7V2UL(KalZw0@!1$WE);%^P#qv zNnCZA63s;SVd*MbIWw_iJFyzI zn^ZvMe)DTjf#I6!A-RkR8%JlO32dT%0$sO*m!?FRj2@+J}x$I z!IPsxRY4^G{ne@7UVb@COxTa=XzWp#U+Md;xdvmw*hAbx=_bi^HF&mm-MEZs z3(^j)7WXrkv`37mjzsl*FkP-~p7P3u*oD8Z`wI^&M`1zHz~{RtG)8w=L>EyBx&z;4 zn0RY1dfk4fVYbu3%90mJ7InU}5A)sb#4x;^OO3cP&Nd)8kuxH!G}quN@$N^5m&CXE zbqX5RpTd0wF&L(-P{3}5n)oVN?U8R=ZUkL+j2Se0BIucxfxKCtcKfFIz>{APh&3D2 z37;r8Ke&LtlfE1aJ^={!KeL_7tkeiaO>?oTdK*)t*W^BD&n;N>-h^|fL5->K=C1}S z?S4-u%GN0AC>%5G^}y$|k?H}b6Ce@`?C9*^r3=y`rV7*swU?3qxL=+gCYU81DA-em zjl2?}K2UkMK%-U5YL-38K+B$IJ+*?F{#l@sG(N(bURin)y8HKr{-kYelF3IBVQ3`2 z6|VL*~lBLGc$dT!njd<82YyI=sdi> zJ$#BDsTR2TBIHd_)`VR-!&66g*p48yJcBoQ`pbCQaf?D2c3jKb3=49d~^GFrvPFI81LE=`lOwFg;G}(AZc?j1&6696#$qfD27C!3vGo=YL z_4aVf{J=3$2v~qttW>*pz0R&b&Ib|IEc0gdVLAdwc<~)@@L_fS4D}5CM{rJ4Vkh26 zV|(tY+T>06KBArapwObfjjg=qO8g=x-PQVf{gac02vLPehZl~Kz~%jk*M$X<@Lc4-yw4TcP{jc`)j;nf&=;mV zfS%y#C`i|W$G^pvAIX&#A3Zphf#e9AVyJ|qA4hn*oRq3jP)1<5RzM5h{NeMyI%ySeAb(JL^wRX3T?ya0PhdbSh#2uE8+!2A&N}G)l&Bu#xPmuliUw(dtJAs%=i-uw6 zbtrU6F1sXuLlE10w@TR1C2d39(PXDNQb#xrJ%PVPN_a%pSxC@07|b{VB=SY zwZfk`UM$n|{gv6hWIlC&tIl$i0l3Qk(=y<7zz9WXN134}OlUjm-&eDbq@e1n7on7Z zea@B?Y=?sH_?V6tu}g>*8XPkZi!fcbZo_ZSXuLzstnO!{5p6}`kiU=t5!Z<2q>n}&LpqIOxtHU;i?;|G>6)yH7F2Fc&)QJPNhYt$Uma6F2UL`Y@- zz0FV8&cMZUQG(b-+uORUjBby)mA^xko-(1@WVxpAd3l;9dF&64u5%58#IDKdS_u+- z`XKaN04kU`4b`av%_hOt>|}Fus&S;%!&G7_`u0Fq`Fm8*s$mODiNQ_SbJEs^?~+88 z>^7YniF@@)7zy_Pplv~VOC64w{05m%G3k=!UxK9stFzACGnZbIa=t1B%MJ%3Iw&Bf|y#-mJ7O6fv1)m4ZZ|T zSZXAYK^f%#MWdXG*>*00BP!5?7R2>1aFs~YHX#VSWkvjnuP22NM z7q_P#WJ?U}`L?%j|B!hKZ3!yH1j|9V=Dj6 zI;E?=kXJoT3mkO{MP=>ixQv$Nr%nTZ^dNq3cSC$o>B3) z(~6yUL4XYl`!Q*KpwOEZz1SVNb&=TMgHazhjz(TNUB3+TSlT0H=@s92r*NttHOJ~; zNgkGs3F&fsO3*Ye=k(Q78~2ATHOLvMW2d2yq=NK6^){Y7bO$Ufl^0?vJCz8wW7_*|>mYCLMN_R-5TnVlwr=@N z7?jue^rMn0-%4b;Hf|>DeW#tELz^XO(ug3og#&+=2vykH!#W^zIWg&Fh|;vs|HMMk=E9Lj5b>jVJ5J(GtZ zD6s+Mp)}brs*}GE^u7$xZkX~Sh$;5Gu>5mns0-7HP4x~ET3Bg7Z!fohumMXYdg#04 ztV7Jt>+V-T$+Wt!^&${8Nj^WjI0a=dhX_H=enrb^0En_y5Vhvbd z8mV!>b?+qK)&SYY)O*%+@;a>Or~zgv_3gnM&zPVO6S3u3)N+ zo?aG+0%@1o>jSicMC>3NhhrQsIcSVEZtJ_KV-v=LhAE9w;591siXO`&>Q86iq z0+q?sljM-M4pu=oVt!BHF>c>4K9HT|gO_xG;)n${W_T%e8B8|}y(NgY*MT&k!0}Hswz2kk@~l3*`sU*zb?4gn zJe%!MZQfbOwEYal@-(X#-5oSn1AvftwCA^bSxl(_g5Hd%?dv2ay!1a+zXIM%O-9-C z(!;&4Ri)G6kQ0mhAOL!c%7vUoPu<0wCScTUW>W|M($ruAYlT9_tco|O)WqD+%4Gxp zKeoc+`CR893FtR6J>m(3Xx#Ip#~21BHE%@&`Tw z{d>Sn9+lHYTgTH4HYXLqw*{k&;IL{e%L5B!-`m@Qwo1}Sz;5gMRh8^<-)G1pmCi~j S@{kz7pUyS?|8lS1fB8Q`j->$r literal 0 HcmV?d00001 diff --git a/website/src/images/pattern_landing.jpg b/website/src/images/pattern_landing.jpg deleted file mode 100644 index cdd1d23a78097e09bf4a235433357ff40ea66491..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103423 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%0DJjlNPd#v$O6M7Tprw!1JCyFo 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

|U`)c9Wj@#`EE&&@ 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%0A{FVNDL8}vstY4#Chil(3+OCh<~~p9%+*-ezwGJ6 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%0AZ3mP<+NKIs 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 CgFZU| literal 0 HcmV?d00001 diff --git a/website/src/images/pattern_legacy.jpg b/website/src/images/pattern_legacy.jpg deleted file mode 100644 index 2d2e112f4e6101f4f94e60b87ec3f8c75c92ac88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108939 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⪚dMrS+Vca-m_;}7p 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%0AjBBf|;+;ab)i<*pF~y?<9jM-hEt~aheA*3w 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 z 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

X<_?Uw%)SD{~0gRGbn*}N3m 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 {W+!300#c_9Bkwg^hZ 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

}s9tm@o&w}x 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

^zr*&={eDxH$T6=F@s%8U!P$T%iKMN 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 S@{kz7pUyS?|8lS1fB8S-*`xOW literal 0 HcmV?d00001 diff --git a/website/src/styles/landing.module.sass b/website/src/styles/landing.module.sass index 9629004b4..5c2a0754b 100644 --- a/website/src/styles/landing.module.sass +++ b/website/src/styles/landing.module.sass @@ -2,22 +2,25 @@ .header background: var(--color-theme) - padding-top: calc(var(--height-nav) * 1.5) + padding-top: var(--height-nav) width: 100% text-align: center + --header-top-margin: 27px .header-wrapper background: var(--color-theme) - background-position: top center + background-position: center var(--header-top-margin) background-repeat: repeat width: 100% + background-size: 799px 643px .header-content - background: transparent - background-position: center -138px + background-position: center calc(-138px + var(--header-top-margin)) background-repeat: no-repeat width: 100% - min-height: 573px + min-height: calc(573px + var(--header-top-margin)) + background-size: 1444px 573px + padding-top: var(--header-top-margin) .title font: normal 600 7rem/#{1} var(--font-secondary) diff --git a/website/src/styles/main.module.sass b/website/src/styles/main.module.sass index d36c04efb..880d37016 100644 --- a/website/src/styles/main.module.sass +++ b/website/src/styles/main.module.sass @@ -26,6 +26,7 @@ background-color: var(--color-theme) background-repeat: repeat background-position: center top + background-size: 799px 643px z-index: -1 min-height: 100vh diff --git a/website/src/widgets/styleguide.js b/website/src/widgets/styleguide.js index c12d6d38c..8b3d3eeec 100644 --- a/website/src/widgets/styleguide.js +++ b/website/src/widgets/styleguide.js @@ -6,9 +6,9 @@ import Link from '../components/link' import SVG from 'react-inlinesvg' import logoSpacy from '../images/logo.svg' -import patternBlue from '../images/pattern_blue.jpg' -import patternGreen from '../images/pattern_green.jpg' -import patternPurple from '../images/pattern_purple.jpg' +import patternBlue from '../images/pattern_blue.png' +import patternGreen from '../images/pattern_green.png' +import patternPurple from '../images/pattern_purple.png' const colors = { dark: 'var(--color-front)', From 3aa61e615f92920d0d04ab8689e5433324051aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Bl=C3=A4ttermann?= Date: Tue, 24 Jan 2023 13:52:55 +0100 Subject: [PATCH 050/123] Add missing label (#12160) --- website/src/components/copy.js | 3 ++- website/src/widgets/project.js | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/website/src/components/copy.js b/website/src/components/copy.js index 4caabac98..bc7327115 100644 --- a/website/src/components/copy.js +++ b/website/src/components/copy.js @@ -14,7 +14,7 @@ export function copyToClipboard(ref, callback) { } } -export default function CopyInput({ text, prefix }) { +export default function CopyInput({ text, description, prefix }) { const isClient = typeof window !== 'undefined' const [supportsCopy, setSupportsCopy] = useState(false) @@ -41,6 +41,7 @@ export default function CopyInput({ text, prefix }) { defaultValue={text} rows={1} onClick={selectText} + aria-label={description} /> {supportsCopy && (

rVPF&%Zu)(#l z^EMxQ&RXr9C%dgAu!fZ@I=WCTaeq&QkX37%ax3xD*0`I8O^`=dm8$1f@8puh3RjVT zEbgu`YwM+^4UBOnY5)h)GOJggl$95JF6QLg!PU;po+%LXd19cK$(Ia^l(7qcRO+r; zSD`8JLz{OYU}Jv8hzWF6v(Hn%h_;+Xf$fkjY99A|motTA6=tEAT+ZZRYH+PN;y5nO zxn^wYq+m`*v>H*5iro~g)-q9Fl8k!jB6~B0Sb&{CqT9VaKDf3W-EguJ@}IW1mk_}8 zooPM~&sez4o)o108jYYQ*!p3Y%&Sv~DA63!-^yj7N1pvt3(RX~!!+cE&`v-3nh`T= zhkxk?hW@diApe5PrkRe%J-AGF$k}m=5a{;W*=>qL6+l&;+tM8h>|As=pdZmwITXfw zj?NC+N{q23%X^wKl=0o&zddxt@hyXnlRz)p^u8Y``s`nZ5@0fL{{H2M1~4Cda@_G2u`={kK*|lABj?t1IUR@1Ur~QK+aWQ_qRO8QYeF_S&&V9Xw-tUrr(S zxhCZ!Nt;G|{~Lkio%tO>hn7^!BS>$3nL)<3%4nVwbPXg|Thxv=cL%q`b<1N9py41+1=Z zgOxcfoYE-;{=CeMz7w*OzOWinkbm*6SgI8}breIC%fUeZftbQ|vdqg)Qbn$A`V@Gc zidjQycSh!S4i%7`sX+U?G;{U0=Tg6XGkLvM_Yq zo|!XM;L|YNyKk1wXQKD}zDqG*bvEg?vNe9)`RncO9o@gXy-J*2-wa4uEjgIXcDToS ze>CnmHv*89(PP>Ets+qs%Bt#wI$YHA?`e3%J;Rqk_BXJzUmg>XD~I8`6D%}#9#}02v5PfBiD+Us2dfAww@Ph zI|!;ABI0qwwUzV~Ycmo8+v}M9&a^K7gnZ2&xAcfgfV*VKVp(Ee5Pa3u3F_+4%AYDg z-QpxlCpZ5G>@KH%%dR-ll`xF#t%+0lI>mx0id0qe$y&NBN*jBJY6JSsE-)QwBLj{= zo~UH)kso>7dr%zDSSIWskZ5xMThopTpM~pUU$(av+Iw3?NSmd1G8U`l)h^}~X~n9P z$$dvLkYQ>gGhmZx>28(L=d+xxp;qnA4-4hhW6@3(SD+lDPJ75*W%uDmRtE?bGpy@5<}4bjSVWTrTyS821l+P^>BTTZj&|W+{My}jl-Osb z*_oox~@5r^W zM6bE)jE*>c5{%crAMoi)_Bm0O3bIHn^r)E9 zDm(YY-8sV2h4;_vb?aO*ly*hwPPc_g#iWn3yj|83HLf}bPnk}!jV{%6F<1tQjvtLK zS^BgrzI)OnL3@T$f2QSMtBJuJEh02TKNS}H`>nr3*S3zL4mxd7$$FjOkuQsJMHg!C zAGpugGcVaDC`ByE9wVgROL<#{+0afeqDoN-F>O`Ku6xn#WZ& z&L8g=htzckyrniddr{CA4&>6;qvgAh)APn7B7P1Q4EM1$rfKD!1(2@LF~kpZEZn}q zHxZCqSW(-0j=hfcN_jr6)B*B+s-LE3s%4WqRK4xLwsmx0$H9A&=~g2Pbu%+GsHR;~ zDvGR_vhck0FF4TLcDP1O|IoC+li}(AZ@(F-#aJ4@10lz31fq>F+_aF{eg0ndyLk%n zw^3L&nPfoDHWr)!4HBA}s`bych#xAOROmiUm58h5F8n;bvnF1>!%1^PaR_ZD=A7w| z7L$9RWm|RSu4HNJnFf}n5FB}?em1w>fVXo{to0AmZSXk}+A&ku+QT!xT@R{1Vi_?t z=y0A8B-7@mTAkr-4DD_Y-2=xccGlTW@XV3>O;x<4k5vQlW=%SZ&@Y($r*V1mJ9&#| zo4U>Reak|4y&H6Q6r=rL2(xn|yWOF@@Ys=O5AzUAC_7o%D>sDLuI9i5svu9noCELkRXou_r5w-4&&Y6$S~kS$XGiWux` z!4M0F$z^e6xg0}ln3=|dHC<#k))6``W165u1 z5$HebxDrn^WPX8sxW~&^g-$PL4T@Z*uic~Gkb6&hgfmr-BslYb{gP4-D3+ZBBq*Fn zgsLBrSt>R5Xm}_NLi(`=761H6{L|&P32;96r}qlD_x`C@@303nzhAV}!;YH{Rob%p zAIyGt*?HZ-bRH5dUUNcia!F2DsxBULKi&57jC%#fv{$Kvde}}=wLb?(h5_42^hizG z>eeh355r=s(?!fe3i{iqtGCml?#L076ex%r;g#aUOBH1WdBiz!nQo%FaQrpU2X@r+ zGtX_>1&yYwA52p-WPT9-oX0Mx7L@7=oBi{}mXqu39mw{!e_Ujd7GK3C5HHVbsDykw zS7qPUm$^m-Y$370jIi+eV>T?ObDF#JBK_l&1iX2wklLdFzb?C-_Kh6p128VFsBnR@ zdnG-v^ihs85S6Nzk7pHMKwHvqbO141M`fpvgp4-Fz9=5;0@$}-5sodlJH=e>IElTM z?(&olX6fPEUT8G-OR&(|P$8LHC+N@kpA=$2Hde0Ae{6E9KONVYw}j!oo5WUR=u%o= znCL!g2vUZC4M?m6?N{$a4muq!KP(N3%hF(TsU?yS^^)$J4)cAo%uSXqWLnn2!&4t| zLo0DxR9F8#R$cgUcnZi>azx)vc>L%J|u8teV0}bcF1wSc@A-8X$&}IjZ zfgRzc6T8bl)W3vBvL@7dxq;q)fh6`Z@Cji^ad4OFhXFN8F-%YqKKK6 zyP7*RqM)i{9gAW2_}V8dYVH#EKON-_0Dk-{|F>~Kw-#Sqm)7A=a7fSGgb!{C++p8Rs+o6hNwV35r$U*&RzC zTkj@Za3dthxR>*#WWh!E)Z-Cw*1^Ze-qL-p?h)=0JqfjVJd}~ISIP`VsA7gWhdsW^ zLXv)4zXK1G-=4ZX-j`F(1d`V5O*~oq5rptG^nUTb7?m#uz|jE`{FVaEBn{QkzmNDT zS5&!SUGl%{W2cpa^CV3{aNmK&Vx~pZ5wLpfY^6}M7bhpImA|S7 z;b2>-kkEx)50GQ@24@MNhG8G*YoYr`PwOH7Z!t`)g|u@5ao}p~ER+9Jxeuw(LRd$N_*a+Q}{T|t-MQ6UPv z;pQf_t@AFJ6X*arUoQ(CHa9gm!M+F3t(9m%wNJ;fUNHlwd%n=Wvu1_+?0NwCNx{t% zAb}X}840xo{FN+m$wf7Ct2HPPO2z!QeQ84HW(l4Vch_Ejs3JYp%USZ*X0r<75F(a8 zX|gx8SrUA$xSo02bRsxzvIvB%I|{rmAzd5!Ywy%qCN_FDq=p#Ue!P#f2pcHyJo1T? z;eU*Ir9AEu_QwT>*B2=QB^S+_yQ6CM2@PNNHj3WeFO3O#v(5Q^fC?q|@*7lg43Yx` z5QlFVJg*~n5e|A$!(=;F4p)c|pA?QA_V}0p5ZS1X6wh@QEQ%6xykw1-nf)OqZ)=Zn zSe6hN%9N+hS#3$N36cK+`c5KrW^SAE2{r3L?*ku6=VQ+PQ)XuQU5mG)xR4$(l(Q3D zRJ1Z$ro%P1p8wp=Nm21m&O#Q@v%GK_V4Qie%u0rt*#gf02gTpZ1 z65sF}@zuCgSMWR^s3fGESZq$HLt3>GXDsDw;U@QK^G}TNLO@ycoVb{ia%fKL{WU;V z{FgYtbc-tjPeT{~LA=?H!P+1lClTiv+h#O~?ibE7&H4_h@+wfRbl8yu6@Gb;W4zeW z^%SFenXPgULCE@QA*78d`%-pe^K<-`_BC4@%)+9EX<2EN-MiXnltk3WbeqboCowbmiQpXpKr^;ijRD2cw~Iy`(w`CtS~CeZ1~i z3G_tv~(eYyL0da=DR{L0iW_# z2;E>7YG_2f(o>^6oJ|e#c6bWSVR2Kr;gOlFugR{}-X#2={J_*eRmIC>RW%kb!t*u@ zTS@V%v5M977N4eYL{W)=;??xCoQ&z22qYxKi|*soZDe)i7fv~$=v(8)?#H7kPRRll zJ@voKZqh;O_Wu-MR1dA$Nm7ngow~2!gvCA6yLfkdYZ?cKW(n;}MTjNCG9?KeSyuCi zFK3H7N$1HulJ1qmK&xBH zT+MzM3ss@3*>G2>(0uF4;bf9wv8XOGsNLNDo5`b|Aq1@Gux-~PMVp%GjOSKXkG>zg zZaLLqsIDC&gDSA*xYFW(P+O(^vvXT4mr*l{4!rg?t?kpMx3n5HWu`nE>MgwkTC0$w zRR!ihwq<#<{<)?t3V?|a|AXo({PlVaxKE1Ot|@3hzdtzlM5_9fD(RyZ4GJuXqGOS> z!_lyq)$w^6B@Cb^ORHaG{>(JsAHcVB zy#J8B+3?BK63=N4Td1NzBfw>ElQtra1A7wOE)vP*G%UGZt)vzsp7+#?+xAroT7_9! zkXR#oiTUbFCKa<=g@AlFYsEU#ln|pm;3gt zMZSR4ZaBrGRH#b@K>=(^{Rt@u0a5k&GDE_;E+fN8+5{tKX)u^fwh0&$U=^H)Bc+~H z++a#!k_pZ5PN|vx*q9FEbdsK&-XK0@rg_%XU)Wz%AE4N5EOhQ)>!nu^O#i046V!P#~$>M zM~};qfR85{w9Q0Qc!%Oa5Az^{be2D)oi|8a#?G{vK=O5 z3b8GRstr2JkBs*9hY(kMzKr^`*GN@R7Ab(E7y{RJ4;&NK6GJZ$6L$PmZYcVKTUFQ3 za~lh2jXOq1+i!`z#+(N;eTjmUR+urfCD_9KGsCIhRJ)!r0!fdzWoA}{MrNl6Uc&^< zZFfp63Je9O7W1Ciq9{T_`E7SHEuD*Y^qTQ7aJ@p}FT4Z8Uj3W}KQKW5NwGXtl4p*| zJkF?e#4$N129FoR(qG0^S9k9axdZuFR7N3Jv+s(|qFn!FhO6j&~ffid96XH`aS z_I4Sezx3ahKX#e!k4?(ZLNKj}mafUaT#xVt`V$A!-PvW6iD!z0y`d!MSS7g)nxx65 z!*XeQsZE8qf%)^|AWdz!4x=j9bF^jBg7N15i9$`K!QF~gNUVU?dAxgU7Th4N; zhS*b|I@#LRysX{Q691@Jo6jSP(vxMpD(pREl+XRZq{{WR*LJ-OeM#epm6GDl;JfF} zDpzSnEzg+)HLzw=&i9fZ_5ZDKBt%isp{sZv4vu_u0)W^P;C z#E0OHrh^vRFCP$t7L2Zq9!<)#JmP!IaIy>3R-dVdw<{?Q)e}kr3yWU@^&@HcVCRK&uyf#@E^z>Gwy0r z858`Wjz;RluMn0W87Tu5-^HSP4_~(|vAvRXD9nM{(zQa-YISiWX01Ua-6 zylCDId$q^EJMdawc)m=z8rgM>T};vM42-?s+;(NL_HY&2I;v-EoN}2SPitCPSI=?v z;ZegQV*6dFjG^a3XHh{gP*5}gOAL}X4uv2*`H?m{+O3=$6|IH%u=5AnZ}o%llyzPI z_f?;7a+O&y?^~I+SN^1`L?*de1Y%PFlp%lvzBx6sWo_SEpSKve`LcOe%x>>@lJJdH zBB%5nl_wvmq>&u}C~_+GZxs_0?Y-ePddqGUhy(|FhDdoh6@15slwQ0;`95powNse( zaO6x^w;eK@4YP{lYbLUd2se>k1mrJIlSqO#ozWfX5hJ7<(qc|z&-4&-z3MHP1p|Ah zDh%(Mks)TkA|+~Orj#FuRB3zb{vpVY?{t`+hRYrvaWgG5PD z9cV{*yWfa;WYItCz&F(YklBj=x!jm5Q0}FOnTRNj!OYn%`!Xvfe)= z#(jQ!?0?tyEVCfWfBl9l3V3nphjD(W$e1-jsup)|eEnM$|Brio*DF8*^3N;7EEN}n z9`!u?R`-8&ybm%bZH{>qubJg+HrPRkW!s{EnwhBSZlgmsSRXw8D_e$1q&+DQe@RSF zc&AG|w$0RzHs$GP&1T?Qny0Aw@Otf#3K3KdzIj)wGQ}*1bdB|5kk@!hI0BwJSVIK4 zSyh_iQp&g1jwSD<>+{-wN|HXjRc&j|&*VEP;j<&DhvvnkL&2Pty`dHM?C|=!)FviD z=N;RTy?Zi~Mi#8j1M89*vx{M`1*+@mJ@G3x~lTmpI*;0N(hPvi1s{AQZ6?MHFLEHY&Iuy8Te{p8t-AgXR&@;}+8U`>+x&o7;Wn+8VS82;-aCACt!#Ue4S=F{JoR0L@M92T(YbV z#e6ATufCxAU}uHAa=+htIyLg~EDOZWpDK<{wXNnuE>VooaMACt-jX7#vyGmH-j8#8 zf|j1LVfd-pQEC{A1OqgTx*B6>Yc+U*?PGlW$rP3*=3rZvBhMmyFj#cJc))u|0)MHx zjoZ!5*RWjXMPuPo2CaDB<;xQMmj@PNCbL&m-N-8*OWq-0zkUYj9+1ol@ypsVj}r8s zc-zfcMX?@+@GG2%*{u(B|NH1uE@QW+bTcdN{lrbn=D#=FaN4ON$F1lBCx;T=BfXio z=Tt7O|{g?DWp3+xYpmgT*{@QhP=WNTj-}6Uh>pkQs&STSC}*E z&c2SKL(3$hc@hg^K_acJX0pmz!YbRiY`u~a2*j!)L@aR-T?)%?xtlQoKHB0W8*P7YbU9@fYFA-(2< zYt2*B=8CMLNa9`FJ4OZy62@2GH#_^A6t?7En|z|8L7PoZAg)BQfIL_F+z7GhEehFl zlStE)bwii!d!^D!@_}NWwE7wbji0=3$c0h&vcMjaw=Z>Tp=H$vst+ewA{|ToQl5%# zhs{hyAx9Upae5gTui=924Y-X-`VOkH!U5!89q%S|WD__L0mDt6K48hzwcAynLz9C;sDGK=%Jzz91W%M+8a#RP zo~z>RfLu2#y`aU>Lu~TuYbc{a`K&JdMj~#((LIzKYa;tViBZ;3cD?}f5#bqAWsZ!@D zep;{eywzos?+tbXQ9Xs?JIZI{4+Zf8wA~M_3*c4UBlB}Syp9i@lIou{LEmyW~Ahdgm68x{epj4ZC#u&9GVjo*hqF0qX^5_zFSZ0a%WZJ~9M$1Eg- z6pFW?brYouvF_O(jxxyXQULX(jAUY=>YT@r_Da@}>Qde#uqi!B)#r_3Z(GDVE??f@ zI{bE;w6)V~v{Xut)k51E0X-F6xPw>OPl~U4o@ezp0-f7ntx=`zQ}c&k?He}+Tu;m~ zXTi+KrK-iEut}VvWo<_CEr~C3fMbgeJ5tVQv9r`C8)9lG(3q2&p^X)N22#HbkDka3 z_prWsh3>UZr3LO%kvAap$3J5J;+tU=X-3Z8nq7-IDJXe)BVE!%*C_7XZu{H%)JT9b zX)iCVYUuM{gB!3JW2v*aIOMja-k0^M^M+r0368eRi2PY^Px$HF%Y7!kMgIPhb>Dg| zKoe1bwb53XP>hJv0yoYLua<8|mBroUZq-HXp)Kf+$w5)9zq2nIA)Xc!XZx;-R}t?t z8KnBFX!yZZfAu1aOi;FblEb4DPc!p*HKDgvHxt~T5D8y!jn19!Z-Y7WNgnSmUy(95 zq7mK*`t$VI$N~K4d}n>&aPdQHEur{E1at5C>n`7SL%q)pQ4R|?+E+xDUcbAuNhP{i zMJTFncso}qx3BU!=UB&fPd+En6W<+x+;Ui+%Gj5;HeeJ>X{h!ZoX$QUxt?5WVz5oj z8tiCO|220-cEnZ3L8cz#gtKgf8?UC9wzTt%tTL<%eJUQVPP`ZfTVr|u!?Ypew9A49 zFEJ=CzL%-J7NBgB9Fu1oDg0+V*``|{ob<|b$Yr5O911PdzbI4k8Q){F)Xl4hTr_W$ z<~Mk$U~=(q#fzD{oUe#iN1f1)_u~YKdr zEtAX*PLmzS87-)?6Q4v+E!Egg-L_Q}_0GP}@78%4K@Kbn;5w***407MvTTtvr7afT zKo~hMLRrjHV9pgxtg}=1sBg2=U98tt4NKW*od-TwXoa<-{lVfq4OLc2rlWbzva|cJ z%7MaT@8o`w=WJk%L~7+8b@nA8#-UbNmWadh!dF{~=Y%)2q&wtKlmTIi-*gdN{aM;t z^qnBhXKkpF?q_FOUpISpbAe=Ur8u2yL&Vr0eaK8Zrh3|9H0yqj`=HaDQIn@cUOlQe zxLBfBJb+uzQFcvksc@{VEab+XTO*rf#|YKiSKxpjf8mS8x3$wDzJqG34u3xzT_Mf{ z=u#}@#Jq98WG1!nGGh?ZwL|=T;lh<$p1;5Tg^|7l%E+PqkOuJ7=WcNr$F!4N=K=l9 zLX(}?iq?yurSoskxL>>6+H&hTeHCWEYf^y6g1Q(?T)XDzn6AkjPESw! z>MA335y_$90U2>mC2fgYzb)gzyK4RCoKD(|cg&uno=gT};%D*BC6*7kkJOJaDk%FS zhmmy)eIUf>b3TsY$jP|HGz^mxSN?g6-eDkCN7}O>pXKSlAx3vS!YmsWgTw*T$GttRa9yxpc6c$ z9Wqj;CQf-I);P?@0U5KtPe7PQR;wYxpz)<7zrCE`n>+ar;K=&}I3t?=R6*On z1k|4pX;r_x+{3$E^-bb=cc{qv(<1*T<(#Bf^{rVv(YRAXyNCrDPtR@>gKXfR$%sZg zOm!*0S;Owy9>#8gyG0_b>ouIGS_0sEA%hb@=!o&~OtdVkIqH)X{584RE-FKwynx~|GQmjslicd_j z5>3lyhH$ECjg9W%9%Xb7ogiK_?74!5Xw(E>(XK%v*Ez_;3Qi1Di*t2og(;c_HMI8B zM2zRq47O70)Zjv{xZeCpp`h4(XOS@zAhiCnx3+~vyg>}(u5}jRyk(?;86&^O|jY|`ft_oZ~@F|j_ zD<#W~w}~~wJZXW1oaUu(M`giXD>aIIwby@0p2N5FTVKfcY=;tLxo=uTzyyl5Rvf+M z@l@Qet=c9&Kp{1%7%R?ra9Tukp{N@s1H`4^gjHkLkS<8tHgjsuejf|vOrLx|r(3#$ zNj~Od6PJg7Sh!ljv~3~>>{_7}0~k`(+Os;K=$7v0VB^>)WHMg@Q>p(dvwqMl z$0O~+A#Z|j-#!;mWPHn(Ro}NM5sgh(O*pi5B~V$>cXoO$u=+fd_fI#HfH!^hggjK|6}dF zqncW~a9>an-3W*%y(tPJO?n3r=}kH$6zL^|-n%G8s`MIAs&tTq&=Kjq1VTyZO-ks! z?Yr3f`|des+;i@@e_Y03jJ2|ol`$Zh?|kQ+&-0t2fHrMEkZod;dYxbRsKwnTW1%^t zF7b7;oE;xJ1n7z*%93$G#E{)EKYjWWE{`v|wa_ECpmj}rTH@Hh@zTUhnz#ZB z&u4eek;uD7IK#j3)Q=kfsW0_RXRlu)vo~h3)M8pdo$25TjQPZBck|>x;Qkgk^_$xd z9XUEYfE8V5Z+c&s;aU?AQm89OZ$BS3-T6R$pRIYDy@df+xTnWoaNF~Ik>d%ne#94$n$ztVEbhq@;W#RF(Rg+N|!-fhP>Cm2{drpKxpy#BIA0MMr|oD@~+&*$ z0w$80;~b$%_Fki85GHP1j&Rr~4CzpNYFzI&t=sG$3$)hj9qWgeGg*-@==zK^`qL$| zza}>NaA4 zQ-bhCo3XvsZZVem&JJ0-p@_-m#@Uf>|kkTkKE;Q=dZ)c9Kb8r*m+df1--_P zQ>pLkb&g4c#NyW4c9Nuje1MC>{ClwfUP+usb^iOZf|X{iPwF(RG{q+Z=}m@EArWDI zKQlE{_pLR7(S0wl$_I0rPN11&^9K*#-Q=z<%*ql6*c{%qghIZ16tkOGaye7B`3Dha zfj_#7&8goriF^za0#D@0SI7#xeID=vymM2QoZm2!!}Up@wVNsRnU=#ScCqE%`zN71 zL!O{thR}Y>d(oCbSInAgM&$rconN4^S7B&aBsg>>gPB;8Q}k8!d%B6B=O6CGeRWmS ztJ(JNh1cX$J8xwfX`OQe40I=0!&xY*|KX7*WOL)as8S{^$f&9NsAyZq^Vapw>Jh`& z!Z_TAPNHzUx^G0VptUX4pGHwiLx1DZWeSz5?4v4DKn5E*g>9wn$~zy1@8dyPtxqI~ zYT!CF=7{s8^Fs9=?u;w6C;7aQ19gVjohTCG=a`3hUxlIuO=cWeg$ImE1YoRcAV?u% zD#w1LS;(V}xv89%9*4AQhg*~AqQJ7bdi@ViEtvK!qOaxov1BI)QODduRLR%66+g`n zeSg5lA5qgMzquP7gkR}@%@5y5VN;DmZe}=yW@|ij4arN0+SZL3Z%JEY{mMRCZ^qhb z;4Upi_I#OK!-q;|tIIa?X^Neq7Pv=>fu&wSeS zo%^4Ha?^t(nzyV1Kc$GW(NVAIFZ)ER$frVtZk_?cz5o9uY)g$d)$)22o(GogkcKG? z-hNR-wBsh-EH08XAe`*M84Am;7$|#e_Hv3!0`jJXTPjJn^caTDcwyxHc=mw1NAVO; zTlrsz8IK2kk+~63vtPaPf;11;38-i<#cZ9twpvmFwn7uRMQLS*m8sv2qQBv zL!QeLuMB2!w9bn-55WKNS?FM3y<)HYW5x(6zQ9NMwhxQX${a!Gz|Mm(MWoc$6?^02 z?m_VTnYA2$^?>1(3SM|cnuy7g_%>a%W?BY97tujmHf;zc5HlOEtBu~an7lN^e#)>q zYN}r@b~W*6!C7l)b#RQU9*Y#Yfxn^C6b zA9o}>w)d7NtZMMZX-%*(w67)i#f)K|`TF$Cv`>O)ty6(|$SDn0n8#1=e8T;J`S%~c z5#G`o(NH>zey=b}gEYg5v8|;wwerY#Z9yfk1x{x_>k6*50RfkW$Lk22qD6aW6&m*# zYd6n>SDMAVvop!TIdONzr0m4HF7vr{a(9_GM{j~VP^TBKYb|q)>4euF;=6p7t0vpG zusKe%O3uG5n58}N{A#%btkz?wbPqJ#uKT#Xt9vW`m%2#JFOi|u65b*G8Bt&T!`I4ndBTAkmlQxRMhF`O3oh6UB_{N$b7MJfVda!?w(w0hiKZqbSMAfQCk1(--&==B zNT|(htM+gP={lmz2rrK3kS}{oVNKVJNvH*VGAHzGMQ(n{we+*b?OG$u^RX2&#Sk>;YL#G22MRPTF17*-i z&i&lh!l;dC`PM5^)jq$%yIFk20*r)*5<;B&nKWL5KgRqRhYzvHUMJh7e_w-gnPY1$ zjHZgoY1XaRrCN04vAH$>6|<^1>p{w7xZ0Rs_Ie^$bgHJbcjE??-g`#{#)uRb&?%%d$(5RLk4MMPHeBA6ClB3fmgiO2$C4TDdb!symu z8b*vGKJGVwbx$7oD(^KrV?}}s=K71LYR+nMnJu8i<}%>!Cy!OOeQylN7Iy5RuCw!K zxM2eBYA1eq@ZG!q{fW(Up1gFsla22LaU}Hst606KvDgTz0a_^E^k_&=JlsQ76Uo!o z1f2MU@#aJFWp{*t%I+ry^6Nq_|2b^#2LJVKQ-d^6PO@m|UPu<A%w8jJ1kJ{)KzdK~BP4tO7T4<8GQluy1b;csuh`2)u4 zF`Q1VB9mNSo{QDbBJkhH@-4LYJA4&a46`=qSix51COJ~}I{3Ih8Q?b9rV_|B0fs)u z(&-k@hWyvzURGIe^}+0hXe6n=YN?)^a~dnFT-;C!Vmm!mhT42r!I{#mtu}}=UAImq zrKf&o?*NR)ua756kUU-=^hvZhd`#*2qq_#*n{36nyuHV8s+#p_9(vWA(qlc6WJiHL zu23$i+6X(!Hu9B;#b5YsX560my>)gfa^CrdRS;PZ+tTxeULV#WT1#?@#pkA+tiT|( zdoM~a64?h*n`tgslA}N%n}R4;DsOFU!T!dh%p>b|>SAt47C)n@-ExKd8Ps$5W|pt` z%BRn57k+NQF+_~JM%r4Ql^wt~KrKpCjZ1^EAE10BCn>^blL5wK;)tzboMh2N9< z$~;1}k&1V)$)R%z94DD|6waIyeXliHSWxtrxyysW1^UKxbc>k1bVW|5S`%NIKPCMT>5sQU)|im^x@NGdu(P@DPLTWG`HR%FJW`LEUXq z+r3)r6Sf6U0NQNVl3;M-)NA`JUGqM*&>q6-iZ@Gg#`xuZcfR}2Gu1DZ6W1?J0O*rD zR4Z%F=dYwxm^!n$kZa{plc!Oqev4ASQFFpAh1prY93JFT4Cr`mSFN79S{Q)Lm4pnM`ik)v>q4Q&q5Bwd4kuxaUh`-mjGXap1+*Q`N$XmM-&W*ou+^N zVyN{%2(Qdes*nB5DR`Bx5aIXw@*K@SFTQ_R9!Q&=hrZKiUl1f z*V2b!1Xdirj92A;@a5^<1yqq+_pFC(VC)AskYM3YZp%94K@qny|4`cLtb;x6zz4$X!}9*s708o~<0jM_ zyB82ae&;N28o|>O62IeH4f+`>@?o*0cU-`hR=(#s5-o<;qy-Qe5Y31c9FLIcR;y2- z9KCxQ%=gIsu4LkuM#V70rH|M%XZ4k3jrPz?ibI{3X7&hTlF4Bc2ThE=x8HZGxc+L+ znvuiE;r2Dr2UGA!D&=Q16UGxb?t!M+7b5LOhJ5Q!7ibhOt=c~OWpA*HR!J^Mr25H| z6o<{tFYYh6N{Aqb({cNm93ERnxdbXYx3*XoCro?VvU78m+*`HFa%OrRm9@%6JkJ7m7=I2v;JTFV#&eJjn)Cpc4U!uyXd?exvy!{=7 z@92zo1}LDAJ-+jC=8@uZxBX$!wt8>N$HjU(f2JNoYG!vwmfx#5mSf~gsWV?3&iR>_ ziltPbpGGrvsS4WjonM{LHN)g(`d<+m13SEziP@jay?|U!|M9_?Kpe(0k6Uey@G(;|(1a@7J&axO(h*9IE>mkFtP{9bM`kX*?HN#s{Xbm-ym!N~g_$&)jv~ zX14X1Pa2^~p2d#S>$8@kUMaG|?_sCYBQkUx529;m&kVf{{Y%Tp^0UwxN;+fu=RnEu zP}}R$&z(-Pgdeb*uPp5^)RF5AG8F!aVFk0gN&!yfkrV|L16JY*vM*mP7X;+|pyL!I zod%z$SA%Ugz<%y6>I~6AGC`bAe?6kHA~nG99XKV1ek zSZh23g!j7Z^1qc^Btdy30^&3N5EU(kk@Hk_be#HZH<`=78st`Q;w!>0wphY52Z0R2 z%3oAK&xFd?SI1(>dj`BWi&@?$|NNes=It}ctzVa0#KmoDb&vM3N_1i^JN{k6a|x8n*}LzlG5xFwB$%Q>MuwxKftm)7+zpFtps0MMoZ)&9 z$apj>;m24SXz7zKgz74tFkiYmc}pyN-{9116LJEs*|?F%}!z7YPVSkfMZUDHbo+>Gcbm&@uW zDFrh>ReQfcH-Z7^z%+gjdQGc++bB!{srZGNp{+BjD?F2FZX`gK+AdlG8cm@X@y7AP zo+;91u(#G|bl^B<%w^lQ_y;iIfPV*?EF{tonOv(mO}|%LRaL+0eCPpz3XDA4jA3HB ziP)sD@{fD{CzHtvi}Rb7u5d=0gW1M`)G~7YP^`|wfkYR9&MD;UO*dM`J{X7-SZ2VQ zc)m zD{{sGFsOQ8wZsl zfN*XdMnCk=AkQPHErlKI6;@e0)%r4~j}4b>do9^8F*OLg^LsfKH?iV&uXoRiUZ@z@ zv*XofRPk9JFK_ZQY5yuP`=TK6>dGs}M&l{Nj3G(5*E2H-2k>*yFwJ!Z-;rnPq)L44r!3 zwOHV?PJVS1*7~(~TTXOFuy3@8;}EAKFN?(HdAePAmtAjCDOVq-M?~Ct!rnmP5PB^T zc?kFu?BzB*$s+$7k4!}}vD&+11)&6bGo7rK9Pqm8%V;%err!Yw=tuC^b$zg@GxiFd zf{{CcV)nRGb>ZLJbCu;a<86uOgtx>@qdcX_)!#ymp=-kc_=F z6a7asZhN%aE9k~qbBGVsR1!!=`+!cB#MQ+WhW^yeiQKMFs-i@Z{6SBbbmc#97brD# zY$qr`j2BnVD8dlaa3S6-OEO1GxZk-xxn z9;B|$l=_d**pHC?GrXyqMbE~GIuAN$f2-;B@;Js9cB1PrcJss~`>=b0c!(~m!9W0> zegN+8e>doTt+?EwUpnBeBClI5dhJs)o|Y*+<|O})4v#p9X@il6khA~BoARExM6@qm zS0v(But+R2$$2vE%UQDqj@Wm4!i?A%zpV!ED`|~#{~UR#e9wyW#PFZf$zG4TJdsi7 ztnIhl?Pnz;3M=LVwiz}6NmN>{{yuATbku|FNWML#jt%6K;{c^Y?F4B-k=xK9B(vY( zlXOi8n`IAp;!+?-Cf9wf zF}wQ&#p6c%pz~8*z(TLG`@jlmTlHs>BB|YBWF@{$OpUNc+JO(+uyi{+k;|H704isx z!&BgSzwpKP!YHxWJ@JgkINd1Ex#0$-EK_mSuWrJgT-wEv6P9Vy@;?EDTC_QNaY^Md z*QAd1zxo{W^+zWBk578gQX)I8e`=J3qlJBi8Z`f*gyNS`JJg96PH$9^ktNE#AF|C* z=^w1-xOzdP;xo^2oE%1m0RsF%EQ4ONu2y@wb4k5<%LXt(;xXg?w=oy6%@MMM=l%Vg+zLxH z#fo;X2skVdpIE_6s#U@bsrJZM(S#x}|~b&%P47@wH&l&;_quBaDDmkLJaT zAgip*9-s$`lBxbQHVI>gh#$BJ5r%pJZCLrBI^4>k!$cV|Zx|H|9cNvH;bSSRp z`Gu-O4#YE-;v2NB8)PFdD}3a5&#lR7gaj^+2MUKB8orFK-ZV2TAEBxx`9H|*qzgA| zSQIL!L2C9xe|{ds**niOVbGdKDxwwjk&qdcZ z(aR4slFn1hH~Z||UhzN23;B+nuCSv7(tIomb+e!hj{3(Q zMqhGkb*uw37}d&?!+seQC8MEgGiZu9E8Bm)-+T2VD?KJlqxWg$y2SVSjbw{8{}WW> z7BvbL=_*IZ>IOIhDC<%v#B~{jQj#=bf*SD<`$WC`(jR_%h<$TN3_ai*iC$msQjH$> zFxlwNR(!ZPNi&LHBV-+T$7Dw{Q!e7e3d)6^W$TR!dZERzFG_-0>@++P(1*RGG#dA-vE*#S{#oRPtE7pk16wQsoHKMFlts5|iL=>|>po}^~x zxMWjA>6h4T!&Nr<^4x97L_KZiy1$pk8whA->fJ%0@q)44f~$wPrqPtN%)Gt`MD+Nv zCt}myeaG3$;qs{`WgTPnx$6HWf#WMKapxL;hjqy?c_yPc$syP<%&Udi-`+8brT8=B zFtlA(HVUQrJqkvW+&gyt*m;rc+OFzTyv^3z^x_&Z_ zuoKu7wQ*?m>~zMTA(cJarKc9qLHxsAf-T{(&+a?TWA!+u`XemTH8vnU1~b9x_7A zk|(_?e1V*@v?UNN?p`m&n1787o&80k$7p6>1z9(UrJHL}&|E;&bp4=`R8uxxZ^<_| zLhn`q#hMwNX;6)JB=}B{;m?!W?Q|q~Lnnc51ZdlZOS%-qE9AMSuJH`MD7Sg8pYXwZ zB5OPq+7(|@>Vp~{?Y6Y9u!T^kw%_9t?46-&peQmH{W=ieU{zI6Hg2VHSJs#D@yPgV zL!o;fyF_YwtIS+xk1NKDavyh;*auP~Z51kwN&|jQ@qheG>nNTD`_e!y@~h_05se@# zT+$j#4Gq0esCzLhfvsUdGZoNz_MfKV$n(wIQ5Bn$W59$;TSY+vXgziGxW0YiPI4_C z@!3yICAqnM1)b8M_nuu_e1loFs0w7Fm*q*(x@EfDObpPj#LmB|6q&v_;Xqfj&Aouo zJD05MeGk8Z_DVlk=%khrT_VRpk-t5BUAVyYngtn~dttp5>^|cUor}UqhPN&s3eScV zyT7G&TbMfR8~x2xWHedrCbU;-@?G2?8BIS~x|@9(0dNyC2DyRV!$ULiUD3tMBTZ~J z!IfwF)|d|$YK`HUC@G!#4h7bTPK;lv=$)n9H3j~tVjw#Q#IT_x$BYdq~zp+NdEU8#f;ZaPH z+(mk>5&ah zBmM}gB71NQpT!jLANw>#&?q^u+fF+Gc9(=Mq>sIZzPSQ`z*dL94(4WPDzrL^f`yMC z&I)~Y^~`rDu7IKwHx3ML>5MM$l|EM!Um*hRz#aXYPrTVj39YproC9&(DvE@PV zUCU9XNLHdLv%TIdwtblW75(F?!Nt?8)?z1ueplJOYE!Y}Qq%Sgqpb0C7o;n?KBN)6q?JhTx_fAOR#UNR%pLVS}VK&+whZO*IsBrF#~X^N5?Dfg@Q4%*?D<$0ryUjFUg^bx#2+ z2rZ(lZpkIfQFFx!)srrWD>2f6fr{B!q6AqtuncsnSWM8wE#7qlxJuWZy=iv7dVv** z-hX9w+(qWH*Y1t~Lsh|L(=v1g2rK@F%HnF(+4+>@Ke~@}uK({Rbn`md_b(LR1DZZz zlRP$8|CK1{^G(92qqe*$k&T_Wp6#iC^m5UUDHLyn`=xx->0^!yOJ?9Q-!b@k8Sg(&*PSnZ(|sB3o=nP@H~GgprQpb<+vF0PL_se ze3XM1DfC}P-N&P~)NC?)=ADTE=OijVlPhr9S zz?$XAp)_U=5PKBUae|4(h@Ny2>iRFTx zd4|xs%oJp4F|;SFznme@co-lAM@DgmUh`!?+gcPc6r4e41yjo0@8npgk0fP=TFp&w z);fhk9DbhX6h8DjGUABqJwcSaGAz!o21CP-3NU>86%v~wHRe4ArLMj?`EjE^-wBA3NK}o1daNYQ1Sx zYZf}O#<8*|93}<2W~eVTS8ACpdIJ?=5E;2Jr;O;2F&)DmKK974@pHDJ$!qIjZW*Re zVv5I7qe8n)>Xi8o40AnJDOKOj1UdEcAHW()IiE4DV!vKTfjpg*>YjQwH7?lhU1YRy zCDH5~6MEGRkmq$o~98S^eAN;=0Ll7i> z4%SaXYNuCcf4_wWKACuZ*|VCCv6dQF4;w$3tByS^bue%wq!B`EcaL`UDyt3CbYfj- z@iz=79JXen+)9s?cz{q%8k)FqrIH0b6rdba4J#j)+O3eSw~T?+H|uzV+Zk15BZJ%g zYyGKW7~dYE3aDJpI%uS(pO~m$uEc6M&W`}f`u@`IZae69IWfG|hMLOmPknW2hhr@i zMj`a%-#lvGj$S-OM}EaDD@wNU=kxFJTF%khp|sx@>fAxu9ccnCFCCq(j(&nuJ&sBp zC4zlyeJ@gXK#+QY2~`ou=0wGE;lGmV^JIRLwQKbM9JO!c*w&PcLGuDP;n`m?=Wjf3 zAmZPxvjN)sB!o6h4}IQNi>sWktdv6TQV5hmkNNM$GRa$6qkCd!_;azd!$6l+P(p7u zcLNU24VG+ro~}2$xI1(DcAMKp%6hX}Ny<0&m*c`;ao7T%wI!*BX`q(cIWn)P!CyYG z#N*$w?ZFygbSH$y84h2Cu_<-6EdzWMv+g?}C2?wVPOe*Mf)hw%gO9fLB7c`S`7RKu zMS~j?;rp5DU-GfJ&zthD&P=_Gw&^NwGAv>}~1p+9B?v&W;=d=%ev{yH^cq@*^_ygSGjNx#AnuM}P9 zfKp3lhhYCpYjOH$_KAXOYMh$(W39A*#%EIsx(J><8Yo|Dj0;BB%FA`K&)gThAmS7T zbCWpcUKB#d;Et?^lF1cU;Q(46pk{|L1yIS7X2~6j>a|CNO+5*%Cek zvS!%3Xswwoy3G6cbrQCjzFj+aF+PR+DV3|WMtQ>YIHr)f2_Y61(IrJ6U|q`=j0u&e zgxB+`VrlJJJ2td3g^di+r7XemuY8klt;J=`)L=9FbV_xImJw(`f~sA*cEWb9oLEo@AHtTtLjQg_y)KIXXt5q?fmTJPqJceE#|@! z5*cn!EH-3(-CEPiZ?>%C*bhR z8(D!B{O0nS@S}3i&j)8*&~Yw7^)ia-&dR%0We{(?N|0VfnQ=i;B2FYsLHljy_KQJ#?caGr+>b(@0T z#Akx#?Rzm~B7<7LTQ>PQ$;hBW?>el^JWbS0goXw0fn+ist2#}tb`JY}#P$ZXT`-RJZ-txBf*&1{7MRhwY2ZdYj`|29;GPFdIt&jM8&V_q3TJE6{}#=a9nKkd}d z67m!7-d1+n2JtJd5`PS8;6zS$CrA9WrDtyA5uU4{xa~wwD{fGv%FR1sSi4C^#&;Hw z2NH#v3w+NJH-v~T$Eee+PT7xRM#jy4e%bGS{#kI@U_SHN;-tbwqfBC%aROhaMJPv= zek!upJgd1@Yr|c={Q&KO-pkNFA0Y?7rowbQr(L{ly1ueDpj)@x=igAzhK>U$Yfg&| z-|wnLx<~D0HAHNB^%*T|{01zaW5>NSJ z`T))c2h)Zsa(XU4sKa7zr>GaS#iirQ+V|Fi+R-u}7czi-0OxI8EMFW$=<_$k6kW^}Hr2?ek48LdOaD2nli$ zlg9f@H7yY>KyFmFXhI?r*@g3d>~x;)s}7$z)?@`Mih(s)b_5)1B?tF(KyRgsIX zlk?Eky*p~${Jv8aNR|a3lo+TvQeR=IXSkr;qux|m!UANRYq{osPh}h@_>4&XBTu7_ z3Y@q9zsA7CpkVwvWVIm^^lzm5ZpTp)+K3S!&yea>WnNJe!941=2oV%aZYCE+xZi(< zypAt)7YbuwwdT~B*hQ~Fu?k!-0@R^1d)xwY&wEEbtzLB<*AlYf)x_>}e67si6iwJu z^>1I%)RqjNfM(jr_janpILu+oy!Nu|M8Cpo8({n!J-}Ok?3e0m{@X6u^YM3qY1Kj4)`}Uv;C2BEGeb77U zMdj4Fd9gn84|Ni#GckJSp=L&w`*-Mm3iaROT@`t<;zKl6&Z|ytJV`f^Vw7`_3(r<$ zs?OJq6YUCT>!Hy_kwd+0N1HR(8gw_!zJzW?2r}qal}QFwB>M6Kk#Go7&SO1N(Qb72 z(Wv4twMVn2y^o=xD3!fJ)m3_GHYdJ^owrl(hzzb$bbISDllTo{B;5WW@rd!i0c0`! zN_+@G;BMappTxn$#ZNXV8y$bCgT$f_l14)yj+oRl|CKnqbd-mfg~Jsq2G2(%aVAY678ULtQRc`bBrgwjrBh=EW5>|4Cq0xm{bV z57RX+umQIN?`g-Z@J&cjU(HS!J~SJmgS)1OhrYxrdNQ>;tO5(-kA77S6j+Z_5L|Jj z;8x!6C`T{4#NW3}93Kk&68Hj#{aD4u;QC?{w7Y@6Q90ndD0buV z4d`V5ji=HBPmrm6)5cz5FSmd^&9yyrWgBGeZLVc4KR`~#ezv6ytUeAbvW6ckTQSmR zvMcZjNvHHk?X#7TuLyhjnQZHSQs{b0{M9ad&?{vfi!hY+Y_r=K*4FO)VV~&ElK<(k zl{#|h?_{zELe|Xy)N&F*YAJ7v0tr2KW zT;+a@WrmKG*mQdFkzjU<)Sy}Cs2}8%q(FMk;`|HT`3hB3>6oluw4qv@dGj#pWbLf~ z|Mi%1{!3-& zTgTI#1pnV7A+`S=s5jKluo7j`mL%}r?L43Gd^$)_cZnJsm4DB-*yvtC>*x2~V|*-x z+fE%UIX(tPRC#Y*sa_4OS;$MiFNFkX(T3tsJ+am6A)-BMi8gKxNb_Lo5v#u*dk#^S(-X^0~ECkuM!omcR5&|U*JX-?IsFFPUfDiOdcdoLWqPBs+J^#mGP zdlrQKS^dxB0}`>qlIv~jVmnhk=UOgdgimjd#}W<;R@6vj!bUykidffGt%;s-k>wuM zZv|}5%x3_kvaQjnjGrn0xom`$|FoScnb3Tt2w42nF}nTdeYBkBFA7QXc3L#mM>E0* zXa1*m+^{K(_@JUrQZw@{mTbU|^HFq>-SKyBz(-FxxG@f zXelbinBHw;#8W{aG;QU$LE)F@;`0afo(H!)ITtMp>vXAMdxc2-?Xz_8+R?56y@g%p zL||yqyIu5sgXZ9xK96^!PQUgp=O`k&FjCL{MYIsbK>LGt2Xl^3iFEp2cux2uj;f7s z^Ct)x7!7pZ{iUoXC1@Gn_!T}eO(hYK;%>=u?fML*CY#UMjIWy z7f<~h>(t!?XRiLn8!38Rnieca3*W~PdPy*-&VO|%Ax8x zEONhgrKOqg05Hl9VRtdn12XD>x%Hfc8#zcVNO%M~U2+o$CDI-Kx zN29ILhuiQ!A$Y=F`-aI#rarfD%`RbETmT>)^TGO^o#r7p-(`vypM?bqnNxugXPSl7iKcMl=u^6Z=v zq^_-F30znn;X>m-aMc&1whQFzIg`6S3!jC;UdmM>lN^MUKIeM9@iVQn?|gbN^kL9m6~|pV2-$ zbX82*&1UGIQ2f6-Zqxo%x}n1#r!7(8i$w(qPB^lOb%}QT_?gD3wi57ftTmV}2I4V2 z4KKq5YZ4HUu^UjSfP~&5O{n&gNh_h2?Zv_6D$BTHYw7WefwwX>Rzded&!X|!wKuS!Hn`pNB7x( zLU0z`Gsyj)M{n3u|2-(t1Jl0))gW-fZMBo$q@n{AMdDsH;4%(TxtEJEyggi<0(GX# z>!7H2&`>loC#Cr7Nu6Y|L)|aYe}X*#uev!%**HgeNbXDSIJ$3hK7IU?mxs31yT%Lp zhrKF1x^lW|X6#7oU2n|m6A|C9%MZfAd*+^ z8@TFhCHH$>C~J=qhktn?+QaRPh3~JWiLcnz+L&-)s;5T2{iA!7*{qNYNZ4}TFT2hc zmz@*?M&5wbw0av<+z5kjDqI2z#QVXw)N4Be6Re9|mB2eo@7CGajIxS_$fo5x_ZBGk z%UyIhc}+S1=iL8B%hiR}6E#M~xq!Uvd?6CjdZ%->i({97#0i;C2^(Gijh#utBI2z7 zJplsgyWVJqu6j9f!sb(0u>BsLyyvUcQvMn%l;hucy~h8!ou@OyzxO+Oe#KVnR5fiwxdX7gTmfeUO^1aq#30vow@6$Ek{qwZB3z;1F##q(gRl9giu_z?+pql~P@QAaur$XHx^754}^A86>Q~R0*V?n7v8jO!e z4EPo)r#_Nl{p3U~jU}_tph7pRBJ6lWM*97tkt*k2mmgh??Es8<+pz7YLD4#VAiN4M z_H9n=2q8gX(-F^E?zRC+`!r>b70-ne7*ix+>JLaXH(srIb{zc1<24UBpo6X5go+!mxlekZC3EVe?%Pkq7iwnA#imMW4vr2r`hKlbR$)tDUE*$Em|g&v=~(o%$lCJT z#LM@TG1Eqt1s~V3CRsWCjrYhoTLES7DelhJba@t;p$K>c3$-vV#ExZ{n9N_apE4gL z6shiXodzxgPPh`?Hq!TkS-K)A=nNs?04{f>-x(Mm_c5If>&JVWua}nYPM><~LM_%+ z_uET~pMV-(SKpPyJlQjy`ns&qgs?!xGLpLbYLWUx0#r@*<(~Rk=6_GrTW-5I$`vpi zQSMG>2i)ECidK=>;9fvTUJ|4CXi|O0Oxnz7%NDBzeSR?e=EkIp5UFN5!HJ^3S!mM(LPm8(%Q~0B*aO`+KsrH2%e7V4ON=WN}mPp%(y$X0oJRZJz&2rTKMU< zlc%s8L)Y@uVEzU?fG}`;mOseeRpw(fG$S(Nwqw_vLrA~ciPK?;gG)+r40U}r_k&ng zN}w34=gErMIhOxOci6JdIFtXNAC@}lGATWc>egWwO`LA9Tpy9UZWa{#ZLViH!~N_Y zelJx^=#ZvuNds=NdMuuo3VULKCZ2tRw>BBSVg|Lb*zN7%QG6`9DneznJ~w2^>1ngD zSYg*Umh?71bY5VqhDq?D?*}BX{B@$E}0-r&kA_T5lcj-VHWfM^CXF% z&M@MEx#_5Cj2I$}-7phIkIR-)q;}!3EPTYfz_@2Wc*(~%Xx?%L2e6=gb~c7*0%JSl zJ-%^%A}6ZMrefDeVp=OEDvdQW_i~EU+CKNSLmSMN4&+)#b=^QSiq6hx(I=~DKrM`j zrhv$%KQYL%`jWsi(o*J`oB6!c0gbUt`n74+V44x`%>e#`)rK3>2&a}!mzHU2*wISEu#jyKG1lLfyU0C&Ht3ozW*{vQ$W$xmW zL6XZS*0l&=6b6h`D)k3C1mv$`VqS%3p482MA@a)qrY}(FtNtp9t(b;)8Nu1-xQzTy zaQ9U@UDI5@sB2sW_$u0=6!LijZ?_@$IlIgpm`MoP?ImTZ%&Mj>YS3wI4K09vU`Efv ze4U}Ya4$fBL#-HYx@813Q<#_*q?hGsRi``o_Yq};!*vPuL*;=&`4d#tB1hvi;R88Q z88EDtwSu=dZGW!#@hD0^N_$44Ac2~InYWEfkYF1?Bm7*O#CO5N*L((#x&DjAG2VC8 zUt@-$+pDCQf57~c%wBCwJ*K=4Vyny`aeknWe$5l>oBnGTV;BU$aqt5nM9cV~p-}%R zfb4h}I)yf4HWJu~@saoII@Bo1u@CCI*T(G1L`3-U%J5%`2)na|P2w(s{MJ~{n^?YL!*xOO*V zDM$5d@IA4<3M340@IW%CW)D8Zv4P1%VjuZlxnn{se>szXC3q5Z%b0F@--K?Mf>>G4}EE{9FN zj?#Dy|2i*Mnc!Drl`A-Ib2eKU6Gah`1X{x2}ICKP;XS`}Y_fh_LS+Sd#3kFsei_xl> z@*-PvWx4tRPJ$ei;1ru)`2e-Rf(E_vXMyki=Ke$YzeheZa0@A|)Q@)2R=JlFvt={f zBIK*yf5^RJG$ZqI2R_AY`N5ZXdLiz3_KE4c&MBC@40-*ZT+h#)i9#T{hi_3Gp-)F> zAI>;>ujY85+ATbMY0z`!&P`!L+%Fm_RnB&D0=pIT^9;Y~=!ybH~>e=)KSUNdOee zHkuGnU|e5c3Da4!ypRd&7nK&;C<4+FLkOWG(xgj=gir#ZgG7PJ@b#eSz z0YATR!wk;=uz|g-ntb3iDBgviGp-naeq1QU-1a`c^7-BHK}pJIbFW8lUfG{?BrM_@Uc8>P^G{L+$@j;j#Y(N}zo>Ss&kk*#CknwRx%*0QUSFWbS8q z;Y$O6y`4CRG|~YS7N_8v;FzYUG|{{Ve(mp=os0LIS&aaILD~6Te6g@Q^w~B8dVbAo@c^09f^X!1#bQzZ_R(0Y0Grl*}Jx_{Qa9Kfea{A@V z(tR7xTh80BpSkcRi&LXZrD8E7uz@M29)0+%1C~cW6W?;4&#h?y%M?`$mI?o9AgI7Jz_Y-o&Ib*afFsbQ;6LQjmvrZjZ}_pZJcVwp07zD;CRM+@E?;)d@lG zb54FyQiWY2rTYwQgH}UXB?K={Epm~TqG zAAJO%)PEY@`#9FOd?R`kHhZuw*nj(#TgFI)Sp92KpYUUF|8MWx-8Z)mG1I0B`do9C zKTU6;g+75Am9aK+)-Uxh*k8 z^pJ0U6R{&txdo(Z5LmbqWcw^vdvXa@V#GTC{dhZUGnqXU)UMx0@^Cj3hs+IUDG}oa zX#kDcV;L5;Z31>P4GRVQ#!vsA;U*pMTE}0=;05k>b$x1RbJ)nPpycb|*CjrAB6m^c zC*%qw`I09cbbreI;Nw^G4 z5{}rFDMA#w3q%YOGI0BTe{?_GBQE~-@SLO|6SnapTJdbH+lFokb-s{s9MxT6>>57G z=%hSDZpcHkU1Vq|Ef2QS)4~96Pi~xA zbu{Cjb@BZ6roiVD=hTU54d3ULVZ9}g8{O}b;rVvT12C^zd{QInOiZHsS9+}Atajb% zRAGn5VoLt4L7|0%kINEk7S+&Nmx%RKYwoQxMrY!je6AKrWo0%pEfUTy-Y7b8lYAoZ z6|amN?8zt8vJYb~PPPN29;-A$0?FNZS-82m9??t9)(yRhyxo*I9EUU#^p-_NcnGky%pp_DR2=x0Evd>xiZ% zV4kpjcl{SHF){ZGgpVOarN%Odq{!0mLo>gQ6syYa1b%>cUypl_8QWFdv-pGq?ACtJ(teCuPj(!Y ze)RYWb^F)H)9Fd#1NO;Lh7S@zs>#XAtSwS_q+q8bxV=rg4fAzFW--*-X9ukh&2w)S zz4-9)L$#uUvYw?IO zWZ@6Y5V#%N-ug`gV3^5y(693>)$tIx)SFm-6D_{<7IU)YIf2g?g14);b_&IdbHge6 zZauuYAva-15;c76#1wuzuc;Y)@>;Q@``3EGC?gr#l?DZ5(aSfF9{JvTGIGW)to%|m zwnqK-wg)k4=FRoZuiIFyxd`GP+WMqcWz97)RUJ24ts?{y z*mytoMph}W#|z=H4~5{m8nWkA!;U%wLwK>*%_ljH$j?zJ#ww~jq5dVk>8ifQ3O12x5Vse_1CpyAJj7KiO9bSYJyVqkLU-R zWn~+^UvvnTsJ5anldhmor61JRG`c{c=;)Yp!)L|yo3gR}F46Qz;2+c{n>T~IHk;E= z;qVee2-BN({0i+#x4|YoHP0wN{nd%@=T`s8)cqg8gUyI9X_CGZc;z|#m%CL9-!uUL>{y% zG-(I42&B~kmvj+Ye&xqW%0Dph=Wpk|7A0=AY+F4TO2~6@m-QMopn`P`5=`P~K_@&52xA41_-#NCjuO7W~ zrR>R3#--OBzjRa&z;!=_3iP&{rU!wy6L$0R+D~)oY0z`I4RDjOBj6)n{fnruY*Vc< zjAgvr=Ox}H1IbT2MfUY3`iLDnKMM!!qUSdJsftLpQ~IBeUbddWrM8A2dH<3Hh!&Zvb&2HcadVWxotG*Hii)VLupsHm^g3@E=2o~SpV=1q-vI$IU<;E@PQ@N`Oe_t|myBVS zK_d6T=vd!H1pM~nM!Rk)l>Im30mEC-kA_RcR&~NmDCGQDc~o_fU5S&ApHJB$Qe<+{ z&Ef?x;MW!Q8!K_$g*IgaL4E=NG6=hdi^49!%q~0A)dc}rPl7uPZ7DZ)#`|ii%T;AJ z5&|~8^dikPA=%&Sj)C}bfWJzQ*t=>b*zHX9D^Co96?mlB{Uj7v5QDSUp<7{cv$x~}+Y`u!oM}o;43+9|Zfq5M?c90fN1FDS$vrfqxyC8&%b2-4u(K`?W1SwQ z*68+4DBrjIhrN%{g`=+o$|gLYzj_`&dy%D-4oZ5~=AI_n?mrzj^%SA88Kdri)+A@=(UDwR`bzjNS7VHNU?(@TJ`(mVAR zf3T{M4{_JfwZ=%Gp`+eg`mzRU#~9m?n3r)vm)Sf^^`)usi*cGZKr)-S_K;`G>+!~u zYMV1T>4y!f$~9LZcR-z@<70o8Hau-Nbb3t_lu_Z&dC+Ds*qF9dWqVmXNwh42bVe!GDM_^Bo8J=~;jipkf zitWdA?l8gO(wMrXr*Y0IJ{e_68 zpOIxr+?`e{gsny`+f(&djcp7>BsTiL zjihyBOLc+R>T*1y;rx4@gG*6aFO>iSN$&GW4Zgwq4fEk?=TdWl(cTg?pG>w0*n-BY z-~8O9!EICu^Kj{X90eE!$W^>fUuu|5iTX;)scBhNWZV@Qcmlj)p712TN<_bTTYA}O z>|Exv_QSO^M8Wac*BzH`2uXTQTQwRz);NErtIO?H=OuhZ9wRI>!%?ldW|X9<{Ph>m(iwK1KH z$(pa-1r+esu0NzMv0c>It?wMpCP2sMA0Brk9i2X)RzBI&Jl;n(Eq9pY19mNIJDF3& za?3RCbn~34q>e*YW$cOq@t6fbkNmVGMR*BDMB^LD7edfE>89RgC~CCPxs?S5V<{-~ zx55dU*S2e3Y$_*7P(naVviv(oUmsJZ8k+C7|9YpEjsz0WSp5A)rox4M+t<7&I5taZ znOX}p<1^WKLcdnnosj;HhB7XTxgDu>fVKcZ%ZSQ}N+MniUSu@GBYP?hhpBDA!gPO( zDH8;UfsWt{JL@C$&RNP$Nn3S15fyc4cO_sF3?(7i`MqDV(SYFi&;GYcMyC=_+Bgv} zGCxN>4OuUnBa(}JD}!ztddKRNlHXH$P`jH7-K}%(Lo=df5WG%y&fw}4J_nNH+xXNk7!?)C{1GJGp3{Fg644BxBus*E@0;^cI|rH2k-=*F;s)J)W z@*-5Qw>lEtRlx3M@>UzsuK*gjW#NK*)v-+3fIT-qgj2{i{t@7(@~k3JfVj@MXr#C0 zBjDrHt_p5u*j7K%u?4kOCAWfPEL6r;4@SYvityb_Eb=w(TVPC4zEQOY{yxB=t=pAPFY`$}>&+(YAK2NhBOs^YO z8`E%Ai#USJ<&O-l(lYPgJQVe4$N$yZ6X(Kdc zZ{Rp`Y3)dQYo(aV%=nw?IFyN<)9{OhF73R|h;@bB(?lgAiga^@(IPZn*F>tIS6cPo z^US_qC(F&9FVfRS;~q}`N~6R(QsL8abhzf*h?hAPyNp1EVwt0Ucd@? zZRfq9tS4`PZ1d7Jd83Aw!x(~gb6~h}u^zGBPbJUzqJ#NP_h`B6Fd)~iV=aYVS6zAI zI=|$*WC33lA<|kfQ>Aoaj`QU`+6;QulHeK$ZV44%kq$* zU57sHb!^OYrKmTipEZlXoNjzVk-pf&6C-^A`R)l~lJ>SNQDc3sB3Al^-4!D_NG|`c z_luQ?F-LRXvO7J>e=k`|VOLpnQUlsLUD$S`bImk8&m<81XQNlp(&Fw458lm3fJZ7u za9RQvUSQ(Nn-JSJCo%#$QOIw_bBN4gVGBi?X`~QHofD~&C$>%VnAns5*R*7 z>o&-G+p&zP?GUja*#W z>k@aWzg|B4vL-{2Nc_Trf5EJ$TwGONm?S&-ZC=%VY_VK-KJ4PRCAsUZQ@-n$MrF;< z;Ug*xxyp-vF)0g=BA1q*Kfy{(F!mmmbb$Vm81yx7?Af*bTkl4!o+o@|PD4@~@8@Vk z`2H@$)*7eB&;9+?B=R(Pj}21Cr^%B}PrPdk8-5Y!Hlr|12DsM~N>+4uy-IL(A{@GOO3@YJG($Ub8A5 zWfELb_puU!^>rB_SAFC3k~wHxMETeu@9`1aJ1&gRiVE7Up5W3kC$vjtOOEcyTGgGE zy^f$zha6qY&47TiQuaZulpSddLca|6cQN-3&Rj>D*Fvlv*ZmI>>{6hjbu2$v^B5!5 z*`w0m6AF@?iBVwqO4Om%>YA&L{92|bKzJK->$Th6*!|7{x@9Q=br{gbc%&{?7Qs%z zuaoy33=$ogCjEO`s|VUt%-jJEImj;G3=XP}3No;)qsPIU@SpkPv;#`Va9bT7JMIhu z@6sjrMfyC_h^49Rvq{-j2~+1@UR_{vy>hAVx|8a4Xt&qa=8>EL!FBS#)$rnWxdILA zI6(It+xiG5q!dWtX3>?jN05Z|URc0mYFfamc3}-Dt*uKpL{yIQ0@4Y@)EusF_Ll4$ z#q0NB0(a-AVUl0>u)A@~`Vjwry~|3^W$46}Vg7aPHs7YiXjlb0^W~b}#9`K6*Pv z?Pd`}W=}t7$jUXOL`*b>Fn}&o3kX9Erc~_hD9kSC$l43m6};gDm7${R!-C;6;QBU; zDS~>H)>1E|8=r1Bx95>7!PRhhs*udaRr;omvQA|?Q|3g~i)Q!5K)aRWpZ7H@SdMVQ zqI02MUW)@fz=z;awJ~q4RdY&_dtkGR1q!jAp*v@Yl)srNuF@?K(H1E6)Fj(c;LNf* zObl#|8L|a>wA~3AHp8s$zDvC)gHNRxF~`=-MMj4@wM1sZ9=S$##-Y0i9eG(q2YW+< zH=siIa|7+IIU>fm zj>f*)2HYvlzjI*cbKL^@0H=Zf+xf4rRu&%)dTgRmE7U#BnglA#a0FC+g1To>lD!!Z zE&9Up8`E#gOmGsc^WrT4{C84t<^nl-Gq#zg;<6bR_j%MfbAU9;K9Z=7EjGfxoKQz) z{u$-#+2VjpUR$8gfk=>u-8vz7>Jz0-pRuS@ATe4|FK)!66WON7Q_IGq=R{px0$GJO zgGzeS_8usdHNT_qegujD%nz30EP|rvD&n$$=&S#<+;!`F*w<3n_?%Ca58_$TZ{qxR zhR(>rEybt~I@qzY1P`>g6T~}m+a%`3s&ZY~aq_hWbp%DOfvqxfBD>A6r$7NveARz0 zbA{s@H-ftCe8sI_ELB^tV0$H(d<~5ein$Gqwb{hX!}PtbKAQ!gg}XSRM^~pXoyR`x6gtjkd3K;NTALb*(^8$$F^DlQsjsxNf?T;L(`Nw%I@QXa?OOgVng(4 zmKzgB{5BbO@ENVSwViGGLEM|)DxEy7y+}t#w&6kuG)0c~b}ST64z=~aX%r{H4nLPV znbyAEYx6RW?h?gyEXq3AW|Yw^AQ{z5axY%gvSbcM!2g(&7ZY==k#{=wVx3sMQxq0V z{nD14;=Vgmrz5hQu2nJvR4Hr907?r<2m$>IQqH0ztEoXQWA=f4lRzIl}5;NDoy-lz37 z`C<8Bil2nu(WL;Dd=vlS><_#l3i?Smu!kshjCdnXkB{J0^3}PqaX?k=>GoLDr3{lH zhrtdH9C9)Ps3D6%jBvH_F3@-M@()MLeQW?oNZ8gLF6Fo#paFWQX3+pb0oE{oCDuURhxwA zLfePE#PkJ^7pO>$k->|HU6cqjU?a%+r9i6);n>mgXV?XVX@Atlu#SW8#}X7<1&!(= zms0ok{a0-P6=c_pAf+hZsT&Qyx63jKwxNurM$z6hWSdro)h1yiX3Bx5E+-u#UQ^Sh zm`NyCc+)?hf(dCrp+yUopsB40&mzBuw%@yI>m*1^bS;#77ZggO9cU%aq0+>45fH5W zk~b|XDuXT^*#1hxel2>hf2ucRaqwQ?E_p{DbiN+3C~;Vr9`};dvpT#$r+BKBNxOl~ zYwu_4-KzlNN)uU|#q(-O4XpWPI#N+X#oqv7<^la1JC@zq@&5!5$fEwKDYJh;iuB*` zgZu$M{~tgjF|S{B;P>Osq0PytD&=!%odDY4W{X2HEx?-AN3q?zkvfY>BhOgJwbQfj z53TP<*S1;gyzQkJbs5xMNe`)2u9qCBD=S1quvy8)1tl`cn&-N6ZQ&C0Dxm-h}LqG^2_zqTLJ$3Hi zka6_D>`)><{oR!Ajn>D!jGSr10dI34ZQHa)in*i0_E zf4(6D{t-xy%pwW`gmZc69PvN|x-5n3OB zH@mv?Ri=a1z%2I=5F~D~y zL}Mac6ZLy*19zjUQ<$mU6aCHDqR;JmUdHW(`3S1Y!H?v6!9#A_A@52-Fin<3^b0G~ nyLS!tuB@hHyk3Ofs{(6Th-24!-h1$rY_5>(ru-SSS$9h5Qvd>6Jn!{R48n!rZP=p-*?Wvwyz&) zruC0bgFndiIp6tx-|zSR&bdCxx4X7&Dk-WiB7~GUHrt(q6x#?UsLhWEcMG!v3n>+9Yr?(E!ZbqD=A7slv@{J5Hs z<_$w3m%CpO`Ceg3nIyuQsNVPVI}wr=-GzuV%`Z1^JI zJY)p`zaYB!A^*NW#5&ZXp}1Cf#$mmNry*j0i-r}ov$KnD3x);WqBCgS27`fbwCFr8 zv#U|47y2INO$L)mZ#3#nCatl~T5qr#8hPoT1`>uneO9NvLrMpqS~Ol!3|aO1!NEb@ zV4W@)-lI2KEEc`NgcuN^jSL4w*N`?4sgV)vLc|^Rg+yO4z$2ooH+Vp7(Lk|`g+G*l z4MZfRKr{W2E2KB-49H3j?ChLB)bCG3M?|NPtT!ugq+3BBOI>|~(b#TpYN#`|TkIR_OpSF7?M92d)*f^p@CyM^Uh7G&HRfE4hVX|V zvt0=L1_Vz>IOyjoYpX9yEsan^qp7h2@J!ijVQW2EYGG@ekVp2ldMHMZy-n%0JOl>9 z$Ao#|L&E+-06ZTCbMN2(;4Ey6g08LI?TcT&eDB`9$#;4`h7pzM+_vK$x$$$uqlBz{ z(P3}x9-6&*<=i)B_y^RjZ*A~Z-nmdVZhpMt-8HU}D=OSw_y65j;Qv+u{?CCoCrR{& zH?H5QS@}_9nc7VFvolXetKuYjv$E!)^)ZfIUDvVIX?y3(#AbV8GCKWJ5{-7)ioNi$ zCYFCcK24wJ-p$ZwauoEOUPU}7rVI|we}S_NIEtTLibLgbkQhabRm4@*@UhU#m5{e| zzBRG@DeWS_)}r=dGQR8Ln``Niddg9RL4{uRRJ4Go&8i+-9(iR;4=hz+C(;qlf1C!X zsyQt*lpACHJzfQ)3hYEW+G=V7XRT^>L5T81ZKF;Z@Rb4I=a%CPNTB^ANZ{jOh;jy){XT*t+}IYRQe5bDd~gvQ zcu@s&yAY`74S)u^S5M}HAk=+e#`7n^o+tCwW*v&Avf(`oz5YkBJ=qNiuYL#}f;l-p z0Z`obl|h8Myf)u_<`MGBg~NM~tE#W8CRcB?*MIgBerI_5m;)Kce*5~V^J|fz&9?Gc z*w1;A_<+`g2l&L5fZzzumB882)uf`MGzO=##6V6+TvNM>!<94!N>SoSF;Ev2 zSF!Xc#7Qw&GRvimiSscIN-mOVK@8Gjxg;DZ25GJU>7Q>|XirHo-zH=e72 z>@>!fhbpjK5{^QSiED*`D#b{WK`up%M71lV1{^77epzdqR7vSmWUXGFl%7$2*_4p= zN3vw;F*Qt%?JHzi$1YPRl|=s$Y6 zN_j6CGu#aaFt!sRkqjRD^Vl^75|Qu}&n-e4Bz;Mz7$J2Jf)U_!Pld$OeV)z0s!TxQ zdjx5`x+4D4gLH$+BW&Mf@iJ^;?$%w}?oS{s#rzk*hl(mnSubSMDyhZJDEDxxW#-*w z*xu}r>BqwVCS>it9H%xtdnKbPwag^Gz!NJAWcg3%S&)7-(p|4S1eveX&--kU?08W? zK6C6up>#s1s@eHd>}BM@*AyD|5=)52hu8kXR+umigXE6AuzBG*D8tXh3a4}SF?c=U z3slSLD{H|SiLgds@gHdl(O6g3f)P(49a2p+Pi}h_WmtC^ zRZuzu2b9jrh_)a;qv&<=sK}B?(SijeQnX+Jy{0x{*66`qo7roL9+f?Tp0rX@F@?ht z!^lawmRdY>_)~=(|G~cZFKyK?x%3B=dMrBKM4ew+8CT6d36}ymlzP}VGF8tU`?iJW zG<~f@cta~QS)unZ9Nt{X91mOb)-q(G1;gOh;$x#n;bKE2V^WiMHZ8|LetXTAza z*mi?N#dQ1F@F(4Pu${D0t|T1XPZ``4c$Kxi3aiAOl&1utS0QvR77~@hiRz!*=Z@T6 zLY0NHhk{X_=?I&|vBWGb5-Y=o5o9;@D3}1iu?*b&_!9*qaxGAOMgcHKeImys>ZOqA zjFgHJIaAbN=M$z!58CcN-~acrblEZ)OFg7|DiM+d%HzLK&0b&MOBs|dX07-QT|#|{ zoTUOOVUTS0`eOWg4kVsvUJ1NxwhL=mt#ixeaQsPYMg3)co@mCNqnwBLxalR$vNrZ( z-Ah{%qoZ^b7N0I3I=G69xi1}KI*UhS94HOWECPZ}?*`#$3+ZJD_4wseN8!FqU4)6D zL6{9d`B?jOBoFVf16^nf@>eCq7;hzxLfnRG1iA zkh$vjB{(|UO0}8W__xo;&ead9;Z`M=t6cTsN=o8jB_06r(d&=d4)%Xo2zP!eR@y4i z3>d(jfTm?6;XVQ6;g$hk3eq1{)puG%%*}4?5SIA}>fD~Ff!{O2od>>3QK`}&f$G=F zP@?(wb4qVJDa_!_BZ=WBFe-Hoo;%MJy KKeKW7H~$SZZXYQC literal 0 HcmV?d00001 diff --git a/website/src/images/pattern_landing_legacy.jpg b/website/src/images/pattern_landing_legacy.jpg deleted file mode 100644 index 846b7b2c7028e8e6e72fe4fa1e5389b50402a467..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88239 zcmeFXWmH_t);8KefZ!I~-6goY1qi|2-Q6`<c_5YxdhvNT|1Q|K0ijQr@1P(d-oGvZ-v99%0Du?wfA{@!{r`gj+{bfYPn{j%|Ah_9PyDX1y3- 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 Z-$lSXxHoWcA^`cI|3?q_|MXb+{{ZN(F=zk) diff --git a/website/src/images/pattern_landing_legacy.png b/website/src/images/pattern_landing_legacy.png new file mode 100644 index 0000000000000000000000000000000000000000..d4895e269e08d211ba479ec576251b7869da931d GIT binary patch literal 8109 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 literal 0 HcmV?d00001 diff --git a/website/src/images/pattern_landing_nightly.jpg b/website/src/images/pattern_landing_nightly.jpg deleted file mode 100644 index 6ff0d574d1600e5e094a74284762ebf70a5a0519..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128993 zcmeFYcT`hL_dgs!K}GN?0s;bF6;w(PLO?o#fOG|<7p0Rx5JG@ZZHS0~(p%^)5Nc?l zDo71UsG)@*B7}|-%BAVceZJRweeQa{YrTKHzkhynX06Pb+4I?Z_RN_xd+(DUV?RCt ze$&y^)&wvx000a}7vRSv;KkA1|DG8Cr-|{u64QUDzj_~$GBO>}{deR4m%ATrfU_qU zm5ygIF`NZ3o@HP<%kbkP;Np>hj7&%1fWOmmX2xSIObjP}OaM;&Pd(K#0yBWf8>7H)X{4*6Qft<(`{G((Fz@h@`rcZ7Y3aD}kNpnd@0 zHwDYOZdMn<8@I;~0UX>7Bbt6I zCoIG)`m6UO!mIBfu%?DdE<;!_R6xaI)^k4D1-ow3d9l&n=60FYSk z@Cv+uwt68Hmxg5aJv9?DmUGy2e{GERGQ;Etfb~n6eAB||v0pKGX3|dY%3y^ zXzdy(ZM5otvYF_1*se1|n!4tv_RcHo6R5dg_XnVvA-KS&1v=o$T_4~~y0bwa&sN_o z7n2H(DztJ3H~c!Ir^^Pn$fus+}5cn|YccJ+fWXIc`z((Tg{Ab9!`K@GcI0(kw2u?tRc+P$pVk!)2(2wv#X$ znmsKq%O1IKw&EK|iu2(wxDuOoq6ROnC)GWa`Ut*Zo@67|B=E=WH5<7Cn``a2$}6{4 z;L1uZpOk{;!tjZG}ge8g^{xsJC>W`R?5*rb$2^%umGCGplVDrC}{lGIZX zsgKCLJ#uBBc~IwfQVoO=pYQQ(D(Y?g3p7pK-T%=y_h)a16GrzXw00L)69O8ahCW{y zS(e~zp>OsX{DKMK!K-`N1RuB_o_l(kVXkE|wm0oO>lxk8u<$b;qb~|JmHqm6=hk}@ zp6HQSdZ!cGP^Dq1JtPFZwf`n)L2>0*sFNjOEc)pQt=$Z{21=g1)d!%e-jU!L(}{A6 z2%4za7VLxF^XlQlvInS>i>IQQlq2%7q_42)-7?uy%<1Kk_wk+5zreBWljIVI2PfJ| zOzRZQ!0o7s7xGh42Gh=8Df5D)Y2f|oA52Dr9W%^kwBJqv60RIcBSrEjooIk7C-4_a@F@@!ph8EyGeO3%cpOchkE)`8o)-Lo`QGBCROCy^Wd#gvj&ufufz8}+KT^S z0noD*t-(jJ`9u#_>X&gOdXC|6(`PU7P!*{wRX$Tbp@aE5%R&Q&TWFm9!ApGAJj>+aT#>WP*85j1Rl(G zyC}FOXB}psNhSdj%Jsu#-)@a<9ZbuD`8N0M@Ico%X^DLXI}@zZ1cuOb?>dekWxG`f2GmKF~#ck6+xIxQ%bQe^`t8)U)kskzRir z6AcXsasm_FYkOJZ2{$(vDpFI;GVS6|YQ&@lI?Z|}7Ierq1YH}?K>YSMFn~#+WtCg| z5w6oop(jXpF13|pc9P8#A}kD_M8sUlg%cx)0DhKC(8GH2+IP7g4#T5*s0Wz$+JwlV@;FIZ(?+>RW`tyyfCogR`551Z6+Nq_PeZ|*%7HChY3f13wI40W48 zPt9!0?WpG1E-G0~v#kmSiPo#(?}>S15v`04B;Tilb4xc9I=+VuHV0q6Q7gYnej2z* zYnGTN+99=rH`?Om69RgAu?yDASxbF%V)#z_rg^J;2<}?It243bp99YH{lylr{J^cn z1?z>jsM}fKc3+fD=3x)*-=(QNTez1o9=L+s|F&2!Cc)=z5_-<5CzuaM(Z}QStIJgHG+6u0swDU(XSBtqRty@m6ab}n-Sa1F{ItI_S zf)&n`yCb{?4pR~*LAjp>U-q~5A8lMx&9xCk?j^QPm!agi(N~AmVBYD)vs?a5g+@G& zw%iIJ)CDEhjFbx2!!voa#Gt+Hy4EYO>8vLl@%qPhnjyRWO7*5mYP77s81eWNf_%*n zkoJ(#-xQnG@c8wn@6&7?gRszBW>I_32XNE2&-f_qWom3|4g+!@Mn#|k1S{4v3M0+^ z0o+Pg<;CoJcok(;vkhUxHVjEhcPC~KpZKqlbB3r}#OXP4RT_#loysZLMMxdqt}!&eqLDF2%;`w=Ej;C8;JcVXsqraw`_Fh{ry;Qj-%+F8FMmeallr^J7>mZp*SPVpUgOl#2g+e2ZMPCr zlJc%|ffaH`r=Y_w=&(pIM5=ws)4u*D2X!mUMr_aBt;ef) zZ$3;7t843E%7#xxKPQ3~6^D+VkFpq2`KBPCp8PH89me5NWaNi_+@h!ow$AR`o5iMb zJM#EhXZm&);t$=z%TKR0FROz)Tf+UnBX7=BaMqXFF!~IkB+^_`8iDtO8rQcrzrXvSfJDL!4Ck6CgJ*SsG##x z6$M-i1q056L=u$(xIyyVN-m;2bJ)SQ=6qhfFzhi7YcM-q`C*k`|9{4~Fucrm6_JjROKbjC zgkOu&71YfPQ(;f2)Wx~r1?uD}mV^XbgSnaIm!6?4`LOzwDaFd@)u%^#H0CyG+cJ#pmILzIJgZ&(M;1@-L z(9D%8sRt25+m~+os$zRIVa|YLKNb884hXi6r_j z1krte01RJk?0n_%Q4(qHO_5MJDRJi;@dE?x3L@9%m0Zl}V7cT4ON71}A#n>dH1PwV z6Bp5g#wOPGY}n_g4X$JP!L+k8zxT@#G2vy?l1w>6>+c@m!G?x|Gk3VGu4?s6>z~n& zX~Hx6Ehw3**=j3vf zX`cFVcG&4Xe(zBxbhGVXVq6inZTd!G;un;!L)T>LL*frWp~))?S03AU_{~DGiS*eo-&;v+d@t^R+tf2ZCAOGc`wcs>l}wDZ z#6sJM_sdnF*so;s&zg*8bMm`=?-v!9Nf0`TMXS&Xa@N;FE=S6c&1PCfP~26C8cvc< zvk}nE>>^I%%%aM4WFi*9h3kAXfkm!%=cSyNZQ{%@V@6x@2*IoelbnqKXvom?h%m%z z!$g-RlN38KrmUtPK%Q}O7BPq{NAZ2g)F}A42@Je~q=hISnuWHLOuXO^Mv1M?h^qq5v98r4V)G#u&7>X zg+Hafr4JU+97di`RjaRBh$5Pl0<=^bMoNQrIM?kCwK3f&-n2Xz>kD)fy0Uy+A^!N2vPFFp6iX;6UEgjOmJw{o zBDry`G}UBs%V2~ET6l2MGM_#nlkdA-0yTHJVcK(nN9D{(*rTx(c@uLR|J(mzHTEeF zEQI*pqx#-1wwSgOE*fx(jVq@9C@c;ntf#zxIGs|CK>v#P@hN$3VHfrJu- z4nwA4E@ijuc=Whtz53DwE;4&K;G%SwXxnTdD|{QH=>zl{2(qt89h(Q4S;pWu%|=O8 zCaJy7fnpYqtfCk_{d5B`7S-9<_s260IDAK%(cF&tAFGz)dwK08SWZu5H(X^a zme)#o6kGk^&aywP=MzU`} z&6W3K3qD1}=cN2K6Kg)xm|Fzbi(I?n>jn;UmEPf7N%dX^VRvx%hB8Jd7=HUSVg;Wi zu7Y1`w5={MMll<-D2w8UU0*P!z(wC=_P#K@O?&TdGrJUMV_JEaE*rqcWSB)?J|2^? zJJ|U8LXoo=SHo&jGj{V#4Ekpy%4RRFbKq@PdB?Q29@YT%#o`bY0mja2Lw|C9JgVm zw{BjYTw^~Bba7Jg^jGKiJL}5n(PdTm{`G!IfgMYaswXUJc~;N>1$mZotFGAHP3vXw zIIPr?2H0vg&4$;ibqE#I9Qf@(xavc7dXLV1K8yD^7i}K}Z_|>fp`rIcACm4APHx?3 zSPmjUa8B_QwE7qZ(Xbu-OfP3;0z zgfp!UEYkY|R08vWu`ufzF z^ny)<_mSAS@W(C#$d;~L8YMMZs!mPg=x8pK7LukCe>?`3Y&DZ(rL?s@4tC+coIrBD-q) zp|Np&=i)c&;E5@LNbCK^`&rLGr&u$_gtH1{yf=!wbT(VeHg~Nf2Q%xNtkR_r z!Vaf`sqbN*rfe@opY9EOi>I#Yze;RGN@Xv~hpCIHi+Ohvh!QD!8s9oQ{UGz^+~z4`C$X^2Fu7p0N)O;=IGsLn^W^g@2rna0_V6wQ6S?8Dss}( zSLB=Zn}q}NzG}7JVQ)Uf2<%z6#~EAaP_Fy?XUqeSCGXifn#n>CX?8k~E-1R?GC|)? zKm@-TDxBKgj9<%#?dUI5aIrtCd`wpP0Y|tlzW~OV&skd4?j8Rg=d{a_A@$C?RWvD;MK8Lvd##7A@%_o^uY~@h?Y(NJ z@8QFua7C)Uj&Ux;3vZ?}zEF{(2e+1Z(CDcMu=coEJZXV7mC5}sZz8VMla4XFox6%K z0MDuXesAIY_z%Ea>h8L0cM!(zdNY?@j6-0-G;UO9K2Y{LG$ux+0lu0RC75+Pz%;-P zw45B=b?K@|(@ve4`#sQEu2agJW)$Z9q|_<-@M}+x?1-fw0HZ}gkzJ$}BrzSih0WMp za4lVNx9%8_8)GypRr6kv*o3YtFJ2@&t1H;XC^XY|r+T|?50`iN5FbtWR64R?_$5kj z6Umsj*!1rq+`mOv(?cTqZ#DTv?PvI$n%h~u5<1~5&`#@MTbt$N-i|ZcG z_O-v8{wgT7H9D6DXCB?{Fh%mlzBJ2n^Z7T8lkE~80(ul}VVDZpZQm0-F0h(H5!Xgd zH$40osl!Upx)o^F{Rx1HyuPumNT{lb%U{X(7xih6CJ|n%TNC3W)n(oQ z1|l=zC0q2%0;M#t=n5SL#Z}U*W8Mo`99f0GB*y&UyZPPCX~Q8469B+-;k6eR$4|xY zlGk}%R|sl4`@x_5w{>GL?xX5xUc0}#F986T;aJg~ipKHwxQBpaJh2SaR583s?T0B* zO*>wy6J&1hZZp*;G;oZm?iYRlmY~3OrGu>uMQj$6tV)Ybm$z;@Sw~-2Kl0*4%H&1% z4e;sitrYoNY4r`e+|su?my5P&9dTv0JLoji)n5e=m>cbHG`xncIXuScI=-O;ha2l` z2`W~UD*9&4CxqYg(EpHxo@6Sla%~qgYFCHVx*rZV27;`Toz^cqt?UAS5sD$jJE&ya zf9Jg%ez4>&aw#qr(J@I4 z&XAz4q;08cslxK|OaCAMeseZtZ?*AnA1#wx2>86?TI?fApKC+}km}e{znQmA>20>e zi*;P(zcl1U(_$K4r>UBPs=S?0Df9VdmL>Sweg75>bwge_oGx_hmUI!IT?=EgX zaI-0dZ6nq}Wn;MlNlX-r`q6Kln$s!i0Z7=G`tXxqFtn0tOkud?7WVY$<$*{|1n0_9 zutxJxO@L(xXIB5Z{0T%AOdXbirPR9?`jp{yH#o{y{8X@|UleAwy@mhlKk@+-?!}G*E4B~1CTFi$%3Fpw5WK$N z(mmiwXoHp)P5Wyub>C|8UzgG;5u3&R!|M`S!d7qUQopsEIiKPseyd4$)E*A-e)10> zUf9+00t)8m(DcNO_3C2nAe?3oM8zt|q zHZ7m8lM;Sb-B@5yRbEl>`d0x#r9){wn1>z$pFL;C!%I~pS9G2D*<~*5Gl_Ofmo~Ny zER*DSBwQ8p)!1NAYDsQnXN{7S3nBb=;Np z(kS#wDvB0#v)=BBDW5Yh-%rbyX!3gpOwdak+4{QDk^OG-*2aG3`oOcKnBdQ!{uwA> zHN}^Gc_M!8hQGb_>y{m{F{kHcTS}z-eAulsrZJiI{@b-97Z2S;7EtzUh6zJ5Saxrvdj&ZMk zUYn;9nl(z)fwjYS~* zS$>*QP(GI!Os$ml2B*(YRP$I?<61u8Ouz7*HJv%rLI+KHbI#&O_^ByJ=##&|uLmOO zJ0&Dy6K9Y~ovk+ic$|b$JY9n>pSnU&+&ft1^rnS7-|-)^u6?x3_%eQ+H^s6L#w20K zTAHaGS{Cw@s8Mdq?{7?gXRDBsd~j%nfLdx;$1RHVYd8~0?sntUH@GQ zZ3HX5A)_47AMQshJ>mCF=1j(b(fqo}wsZGz@5q(Ts^@H8nom}bc9wSDK3=E zE5@QG;esu^L9``ZU5$iMUXpjcLS#e$FIBW_ngks!->jebDYDDRNMt0YPQKHQeI)O# zUw%rVW=BwzPSE~wJaWAgMz`5=KE!? z6FD@yxlQku)T3Er|4ix+2fkMvc_#X%G{k)WbcfA44-q+{&RJ_11VJPf1x9o=t*J+~ z4p3FBp||N~-=A8(P@GCYH9`vE%~ zp6MRB*DR*21mJN+%Q+`jt2QOqr+P-e26pKMr+YjNn?=&oxT}IjmeUt}{d>#vQAg%E z%Gsg<&HpWvW3){8uM#B(wdG(}%>4dQ+^8R4>RYX%PLc~T-#8<~Y(rU# zkr)~V1X>Xb0jD+(Sbd)`);fBxzTppA4TDMx-3tsk=`l-(6sEl%*)=pnMgQSoQ#jDE z6jB(wdK6s{-zSw&C4J>jU}e0)U$+BpN7UWwB6m;p)R?J*?8QQ6o3oD#h?#A7*t|<| znY{WNnGA5rdj`!C7<9(d?%`SF@ht$;-12uNQMJas(+dtu&dUz2wB^~A5qzwYg3qUC zhbIH*_Z&z$B1rbw>yEiW42;X^9&Xm7xmdCcmRmCfx8N5EpCJG7bQPE2jvy*i*P&ptx4fylAg&1i@3RcO#D~G6jCXJb%h_@ z@7NVEe4#ORBo|1F&zsk#yIb{@V?UoR6=|_3UETfWc`vrZ!#clr$T<1gs_#qF{tNrc z@RVZ7O?tI3THMGyU`@Gs<0IAHeVfM1h7@&z?Q8OE?G{SId*0;=n^`)_nU$0dx#@JulcdBTw$1A<|U)h zM=n8OzxYeyPfv_W`rX{QB`HBUzogyUTs$Zv|I*#2oH_V)fZR?&Ij5(8T0L^dxM5^n zYOURXn4~=GMsssqJud=rvZJf`RtJkW_6)6wC{9*})x;>l3ZFv-WmcmMgSzjH%svQb z?edx&2OQUS#nl}PM&wh2=wKu z+~j(QufdMobuBI;I7T|S2P^c(&80O;h+1qqkZXI$rwFgyI3W2#joDpYQ<5IlBwaw1 zP;OG3ZuR%|*RHb|gZ!Qqgp~Pg&|p&4k{-i*Ku}?2TF2yt{p1oQlUZ1c$M%CVjbPo^ zTLE*Uvcilf@?S0*Su}n+&O@Uq3#<$bp~%cA{pizc?gNeI1Ky;a7yHoMd350M%BI?8 zgz9q2jiFH`wr>tzH&#V^%f(Rx!Xq5&xY98w#S&iY=1#2Ifjss1c6!T9BL+Y0*WM)F zBwn^r3LoWi*{JrzA&BRvUdaT5AfC#8rZZaTOLgmg2;AdHDN8?qM)|rl(2?2@7!fEx zY1pCX=|qcCVs=grj46$(?HtMtXvT2{;Ycm*F%K_Ied?LtOb*c&l=@Z!6)m+@hJ7zA zOx`oC^evu;r1vj{to}iI4V2xbD?3^L02Fl$lZMRZM@?EnjiFCTHuV>(l?zmoMo0X@ z(uP|N*M#hHmSyTJIp!cwiH;3k2U~}R>|Qmrj)`1D2Vz#fqN%$-;d4{ti4rH>;CexoI!!__`_q(wMzxdd-vcDFmqk-HB})Qn9O@2!O(k57X#Oso zY{{0f!!@JmXH9-0L93`!p;~dw#G`mgaP%Ka-`1@!9+X?vnPd(3)`E1ZO|f;59{}C1KEmefZxqSeZytWAO0~`6Zg%J~h@nP3UPj z)v5wVYJMbE`g%zqP&Mx=?pK0&w=VB2gg9+l?DMoNj1(*z_eE68uX8vEdcF#XYf?%N zei9f}xpKal_A${Nv|?@+J#(DxbwA}_N(?Q3^A46{&8KnZRh)yk_P-by7Bgd*T+&wy|$Dzj;KD= zJ-;+qoq*k9%oQ^!cFe+OOLP^pK@EiZhs51yg)P6&w^Iv9Nkxw2xhVtS#%EY>A9LMTVXLY zLq?=s#Fd@MXBC+D(+!mW0nmzdu-PekG*s@;g%su5K$Mu)SxN*nU%fDWyJyXMr*bw^ zy;Z5F8KRgm0PXE+V(O~)-N+uF6&{&)PL_mktvgy7PxTGSM_cRP!rWiml*;&0ZkST2 zBU=43{6Up$IF1|RsHL1sg!?!@2NkAHRctnGD(;Y6SDX-LezNMtwFf(wi7c7-Qz|w@ zd8%wW$9sp-_g7bb0DOc=9ppm$n&f(%kcWtTae`&NLM*Ora!1sll-&m&U1mWd&)?W9 zmCz&H)It>!#arwr`i4w!Uwnc(cb24TFLppLufEZ5YL-XXPUQ?Q%ktTV9UStuSf=JL ztQV=1qk-$TS`p3jHl4=0;JzW(IcSHGZc0P4@8T*wlPsa4Ze~Uit>~zm0~SL8HyjUv z!Np|xRqE9}fw$&(oCL|!{JE@^gh8f^z-R`0sk8e-e8`ECRjl-fY5qzCTw17)yt`ks zed%?r@xmem83BJK>)+RiDg%&6dl#37J-#IaSFpmN=;`V zM5$!fnQrlcYtRz`NU(U&8&Y;7;0KcoTXFT8J_{EIhRPr*?Q>@M?@)c5~tVnAzq0|3l#pZYNU zs|9epie`3H=PA>vfdgAe|GOt&2bAk*?(?i)<~5{How22$xBrd6kT*?$2rX(AqTjiam+XPV+i>>(~*|BW@$VNQmr0wA|B7%QQt zxHwZC+9>yZ)R!l}x)cFS{v(}piH^(|3;VVd+^7&IWkK32CC0Z`pz$m8H#Fk z9C;HhbiuL0`BB=^_44pZdAtROreFLb$<(PS&gfTSn6HBclLdv9&H2laOrH-yr>X!} ziPIGElmWu>^m~r9@ONT>!78M?E5y5p*m~iLf{0QM3cMKE=a82-(-L4t&T6E zh(WBn^TlxN2;KrmiMlP)5#e5c-74%zY5yc?VoG(^xsO#$Mq)>yZJ=6z9CC=y8P>-) zm-P?Pk(SM2ml(ecL-~kUZ-{lNa0SJB@~H;i)S2e&&ivC({Idh|Cqf-_3SY{QNU94m z3X6V+Srx__&7pxgP~Nw^Nx~aX{((IX<*kD9)=NuGSfD^2N!KBtDeE`#BaF=l=kaiu zbPs0nQp5Xy$QjUj)jD_!H9V{t_UK{ynV25qHHZ~%SG3V_+TLz&nfyJ%sED{LW-|Jp%k*_Kl5?Qf z0ene6sR6?k`9v(dF}>yl%$iLXs8dDrZ@>|2QebQ#%xaVc_}l~BmAk48O<8~SU~sS1 zce3v#uC%*7hFGu5_gTi7@=VGpz_2qs(aN(vc~btKbi1#VoSX4RAOLO zu@T~(v28CfbwFvXHazi7WC3$Nkq+kVz?HnK=MwAw$pj6rAwnpaw9W`qF%a7M748XD zI<>PVKB|h$#>4k!&3aH=QyhdOC`pMybj#Z?o22dWJ8Xq-#pG~YDrW?DE0G3c-tKin7Ovafy|@P#pS&jMl*E(4h}Nl z66xNx00hw@RTqu=T*_k!LcjHt^l93P9fyIzQXW#(=bnoK5g6!CvA}RgPg!w>qfft` z!|JJgcyqA_^-Kk<_WF*cAW`!gqxWUOOpICJpQ9E<>Vt0U*_;Na6tTIeE3|dKV|onq zXt&@hzB))VDnP`(r{JQV{Tu?TBe@bYsPCBi9GOTsRzDo+U8(;_H<8XMRxuKJ?#nm` zGbN?@bvX4WI)Kf^Uxq*&^AJjHhs)Ok`W^Y+Y!Xv?&|Cz2N|d$q+oKgQ=MI#;jLj9l z3xDyIUZ$*^iSxJ7ytpW-qp7ZfTrm^nny0DD6D(j42Q4hf zs=Q>NDr5g$0RK(vRH<4MUB?Cxw-E%?#7B@&$h!S7%BesN4YW+UymX8#jl=cpzO8CE z0`NLhoWoW2zQ*P>=o}XP|$7Ee1y07Te7=If4rvUtA32D^9NjN1@(8#g7t%L ztUp+IjIrkBye_80RVUG{kL{{ONgB!#Dn3scl8-Pw)m^J@K8A_p0u6y26Ct{6+JNCy zP)V|ERF9MXBOL0}aB9*e>LZxG5V1@r6@MRlI{pbX%OiU z3yiV#M1gdac2R1iaNe*~2?mpJ1BDmMal!(Q_Od8#XABoq5}k^J=u}jV^Bz6z>d5}(f%Er4rLj7)Gb-j0-ua9Dq>IBCubtIiEaz&d1 zm@&zVNS}HtILRRJ!oZ`%{3`45rcSyHK^Th}k~IQqrU0u75UdzYI*gYXTLm@_n%}?; zz@6!Ec+*&Fea*Y3&V2KF0CSlxO4}#JhtOfYWGqB>^D0PRHkx<+O^9rIyWnWSGsO9W zdHXzht$7JU*Rc+~uPctFy{hFfx3ZrHjKuQRQvoo#B|34Vjv13U4|XC}=G9t6#~RBE z6_uZ?>=sL#sH=Pbtc z0h7~)M-g1i>*OPD^Wt#4E=XKOsr^W2K_%L|p^pl?jYv+7Vv>KG8ZWLbuV)15TUO|6 z=+chr8)MVXe>N}O`vGliPGw~~dKHSk_25vbsybTMsducLO~<6zw2LZmka^+kYP{|< zhzMlPk$JwrOteTBoOX$qIQMKO2MYnA(Lk#>bGOToFVYe9#Du6yC;eE>XC`FmB@4)h z#FR$)^ytQ#6kx(61Dt&XL+z9L^|T>35Q6E7~w zU6)NPtV&&72ByJ7Rm=8jAh@XFEdXL8DSz&d&Tff4kIDiF)|l}W2*lztWl=iLymp?Z z>5etyC3{mDnwB{V5Ru|87Q-bklccpVM~9J8op+eAC=eRLvlyRieiqF~s2_yN=&NDP zF0tW(Ff3};omXE&8;GqZ7GRwsh4B8&-)a$88zN-6fU;@Q9oA34jwNYkVzsfo1l$M_ zYqWd=;)LV4pHK9GTo@)kIhhxw)+8Lv08Gaij{}$)IL>qZc8(K#_L8*B zPN1(OyfPB? z#(KrU#XgDOD%TYsx+2xk(Wp|VaCuaKyc+w*-OQ~AmQN{`*PLm#&Y5_*p#8kLrOzAm zlj%J)DP&&;{91a?e5PFQLJ;WDj!WqFxhwCq&)(+Un|h?o#Z|V(Rhab7(7KMkTh;1a zc|Moh9X&91e)iG*>$^_Z@!vC4rrKrhST)^0M}GUMAYaeyS#)Vdh^n{<-ssDFyQEgo ze_fK~fLbEydz+h^rjZgF=y46UIiBF5OYWGv1~2z20OVPZdK8*HVwa)}yyE4sKk^#s z%(pctKS=RNI!S=kXj-|e8QT{qr9Rxy^S=1yMo?;vp)KuZ8d$4P1<3TRWN2>=K=u{z z6|fl!xDNn=@9sT+W~{)fa7HM{>y41a;S=Kx>0FL>v(u&p#(3-y7lkplW3-gZB5|A$ z`Psv$zUnAakduePUkzu>)GvvDnt{eR@rQ8;UtdO-_yTOTlWHwqB>^{DbYh1dTmt9% zi9oO3J;PAkt_;f@^ziy{-qL7R_{Ns5Gkxo>bK$xwA&I)8C>`_F$|Y~oC4by;_K*DU z`{h3X9ApbMm2asD-LLXQwbO#T<6Bdr1kcJN(X6PU3gxq1%$@Ytb&YJ4s11m_e_L zx!!B-&?V2imBYEcMgE@(fgSFZCrsQp&9OpYt40>q!OPp-zrCF6X8QgzV#aK;sAp{C z{niUHtY-yN%;`r2|AlA$ngM%X62;>18>>1Dx*?M6n{v8g?z#Sz__F(Ave5AomEY4b zb)$#BoizXcq?@F1e&*IH`R;f{`p~G=15pjD$FxBn#lFz~3#i&cYvG6CVb6n0jH=Kb z;;s0L3o-|rtBnF{4O_2g6mpgoUhgZs{7){UDP;Tr+{m1*%ITFjr-;+-FiG)zlY>nt z%kPx(Jgkj#6H&a3jV&Sre*h$vJ7UtV*kPdbc@VNnV5kqkESVC<6g8|0zhW z-gnJ26FC4jOdF}#m<0z5WheQ`%(-9u0qCAwy7?jbo_>mx+g3ObZBC7!g~4P}L4$dd=^@&}u>jZHf6m7%;_z^Xax4 zmz0!VDtZcGHMv{R8Ndq#Uk#AhUUU2|D5UgsYIH($#COXyp`sAS$=qzGEQS(Io?NLU z)PAUHmOgp#TIX0!5^Eq@sGQyU_?31u^WPtSv$A@dq-aoEUw-bfJ;!iFThOD9Q|v6f z6pyW?`S(N86NaNTVFm^i)O~@d3UlUKn;0ilj8io9OkO3=<$#Xoc(!-uP%ciWc5Wgn z+e{4~ox93Km1&B!araHBq6oZoJI-HVqtB`CSnj{&q55Gg%noYBIu`={0jPs~*Qf81 z=f6mC2CUiX5qf%MmGftyK^v<-w?TCGCZSKF;S)M;C_DOF}fqZxA^Ep>C62?~ha!}@_&{-3GDfl-7IQGCnKzqZ+}u6XTqs_n6-PhoxqYJ3 zC@B$aiPRMcuDfDX6;t?f+SZ{_dk>V46<1%03?-*Tg7m^ch zR{?t*56kn{hjmrqYYtLZ$lbufTHsYj{Hei9%S~6?ZFmsM>PTz- zz{oJj``}Jmz+q2syx=iYuY}wUyTeAa4QsS`Vzw+t6t&~RcaqH*ebiSk0RIT7Rw|*6 zYcH*?Qf5-gwQk>MFYE38EaRZ>#iM!eri^L!S!`Lhhz7NyLToqecaW8jwiVD=$yOS} zJKC-tcv78+uSm(zZ&>Qo2-7P z^11ldw@)tPBbj6ZtMYq`OSVKW7EFw*f9Cdw`5gE^o<-60|H^ZQD4JoC0`j6DXGwL; zW2l^_(yrzi^$E!u;Gx=ir`MzE6;YbHMvd=~8`1fG=isxhFWXJ3)2@hE_ohk+-rHWb zW-SvJyso6vB_pprl-YM{X^R!$T{TuSGyG9Z45bv=`O8l6IUlk@Ra!M zD`y4HTH1h@4}nSt>19JVC%G!T-monDG&Q=|inK?;uDP!U)%yf5yCo);K1;;aG(LAF zewu{W%LJ{lWhy*(Au6yF+QS7DU4a*o*ND>r)=pvgZ9(Ii3o-Vi$ErefQNGxe*Rr0K zIkuNejO06@8WleP>oc|c`dTmJ?B-K4l9Im8H7IA=_lEFsPuB3{2j*3+PpvdvSE9Dc z3i|v2JRAtcJG?mBJA=Sy{9d{%e_h8L>y7l~zvs`@V^?X~ZWi|aJD1A*Q~pn-xm(_a zKd@F`XEt2Fehchx~cS!8_pC|+Z^e&AW zJMl(_h|^~9FjvF{_V$493A^6f;-%31$h6!Se`wf`PF~MsdzC){!}Dm`$*y!ip?{|) zq%WorSwUSf>=#dc+S+SaD~;@zSW@)o{e-&Bb;pn41| zFz8+J^KsF^I+UozP~|6PgKAtBdcq)GN5;cSzisC#@mm3--iTmDDbc4;%|V;mnDP4WMr)}iz#VsYlAC{AJmc6i>yhQzM{ev+Q*jcvY{l}iZ}DoUS7esx2B}LueMNwv zGL4LIR93oLmlJxw%0db+MwrX5f)-2V5bDhPUblML(*Bn`Qx0Rl@g%iFlH$*jII(G4 z8?PGuoqsBT4tI8BQ|3<9Q zJ7r7!hT@(pjk86 z)a{et{T`_UVMCPR?qdKRgF83UCKXqs>F@1^;$NNxo)t{@WCIWONpME$KtEi zc0)zl@_TVe9(1EpsC0<@^8q8$v%&a$3F&;qeenpNHyKlS%f#Bo&PaQ4m*lHkDCKiY z4oH8i=UU+6#|3qz6H`+eV=ZSOKn#1HKY%m#4dCVLQHd9YPUeJ1NWD3OhPfukyNv}+ z40oUGI-E4HHD4@}s-}pF-gm!O#o%R*4wDJEi_SQjdHBQ?wQc8;!3KZ8;9Et^p zmKF_Cv?RDoaEfaMx8g-haS0lNOK}YpNpL4n+=@%T-1qN!o>ykxnQwBfpmSamWcpGy&B3d?`4m^}vFq1kEf^Q)}MDTi7)!{x&FX9OA- zMl6_yP2ZiRWnlE}&N~g$;AL7-#h#RB;O+G(Pg?}p!APA#nR&d)ze7Ad7LnC6#RL8L zivEE?&tqB5@XTvf=^!~FJx!TEW%f=U3LJbQGhY)@EI*{$^^XJ-yO<@CuVhNeaJ&jC zpefZQh9%UqaR@Y$Rbp376PdF6u(J(Z@1O1I63o9V{(PK-G*%`9)g7L{qluu)O4o{h)r7SNf{B7O)rLiysn=bd{bIHH`tEj zV$~S+Iabt~eV)?sO(cNNJDNNNZu`ZuAHfuA^1VN8YA(&Hpdy|XdJ{Sr+`Dj*6AZw0 zuYb13>te@mIotrBDxg+A3!*rGP~nA-=&Gj|k3zeon<0`ux@FO3KjX9UQWbql?O1*f zdW&FG zI(0mhdiOxd)LLTJ!B{;E!c9=wl-UoMQXIf`E{t-r?#)js^h@i<&kJcn9)uvn+?6 z_MN0h=__+R2*u`XmnrlZsyp@a^k&`qb!~M=zO^jcI^Wt}=MoJ z=@hkSIdJ)Oa({eHSdt{Y{{8WrOT}uX#-QchwO3h8Tj2Y}*KSYfeEV&GLVNKE8O^@P zLk*JO&hiiN>*nK7xkU^`M+eHIs-RqtXpT;Uos7X5YfDwO5cjjefF{$TRIRP~forGW zKEVS%Z)RgaH?QYId`8beg+HPIGMHD;U+7MKNA#k)7mGZa3OP0rGC_RUvV1`4QQA9&?Ow4TK(3;?i)^7`hWaJ3OU6z58? zXkoNelg0GGwCGApRVdtNnrrw8fwqq3E3H_?LArFeiiWo0>^CNw#Ilvb>3p*-b$r7e z)CEzJwI+FIg~MKxr;Hi7X}kkZ_6)9Sm!NQdb$Q*zCN1$}%4|PFR@p+m*DjLbKCU^- zT9lg4x--(R#IO)q^w_Rj-Tl@#&Q*8C@0f6waEt)*18H#qWr~u$M6=Hexm2~kM!ZtC zVQ5^f(Te-YNcG(owf2+8mKx{GU(_mscD!Tg{^{+Pqw=%|qEw5kh51kGhbNn0eEGd{ zw9U4BXnsPlmJA5J))kWuP#ge^Kkm_LA{RR2lc^aF51Z{TEh~p~^5qRG_kd)!zY8!L zhnA;m-~E0q!FClWEWvINzm}G2WQ~r?#Ef*Xa-6f@=i3wtQQk}YO6y?0+YSK&*&>S< z#7|P?dU;Mg(~iXhK0goTOqQP?x6)!jpb%1IABL@EX19w4IJ~FgM?9enHl68!{@eRb zr+ii&@SwvM?X}^oAE3SB)t|Y`WOTJC61u;TaJgGTy!#q!)X|e7$=YfFq@+$qrh1TZ z`9rKXH~~PmNncj_IZw521Q+Dw%ud&;J}RBbsXXa>xbTtkFP3|{ zqjSb;!lZL+2mM|-ZyB;e*VhYJ4be0Jc`{=z>xhBl61U;j)m&_ zzfDCOux)>B`;>Y-F zK?76aV0vdKZp?_sr9#^r`3}`VJz)rUF||_+@G`C6x%G_q2Liqad2ox$&*1P0JC#zt zR0)N5_$UDmJ>{A$5Ouf)+6t?t$<}@17Fs2;n43GK1I!UaaD*}G{IZ(64 zV^UlHLDB36m279#2}5!~ZL&4wJkZPjTnKkj#2bj?`gP~hZh0&C@xAsX!~_U_R_>we zFUtXcm$yUa#{$%YXWfgs#>=*#upDGR=v+--wzjOk?E~| zhi?n9l|l2XbtzDY$SBWUw;>$oFzU15nVPm<<3L3OA=ciJP4R~X@#eC*y~u!wXkHmk+d!2 zdlSH|>Ltd1uNUAG@#OS3+HP&jn@EH-0;M zU}CfXD?GzQXr;Cw_K@7T$qU@38m#^C>1$``Lv3hvc22`#q|NN1T5#3x*7nj7KZ}Eh zO)XLJ!sE$2MBCf@op(G-Lc5EmJq)Zwy+6DWIhfqtf8pPA@r6t)XzD-ei)uSoTfAG4 z$PdoG<+uW_s@QY)KMatqONkAs$Q>PgyBcjW_yI|KnOXvtR=Uhg*=MJ)fa{iW9~fbH z^y(c(8?WSu!}tBq12b)0R~r+<*8=Z` zw3IDkqwC0y$j*!bZz2d^(koGef6NwAGY)-fw^wkN03E>h01s{e4?)Dp>$+J-X#XI8 z(;?^P^r0i>p)RciG+f`%zp<-%OZE_KGGlnJM zR5Q=aQNjVe&OY?baAD6Am+0qzv7WcSTgZ4oWwi05s4XV`U44yvcG(w1YTVG^vAUr1IA6EaQTnp==ncR3ws1#u_PJ5PtgZXPbauz|44R~!yn=^^4Y^B?)qrC< zsgWMh&slb---DI9=+qPXC-<^XJAN$|8t4tiO_SiPDDq;Kl33G-K@k9T~6mZ0EG(f@!spHtvlcnfxA(YlK&I zZc1$E0+(o}@_?R3o*&Al^j0*9f@;?_w&^THjI(8WI~}#{s|FV8O+rx=NIbIe*+K3Q z1NawX4K zmCOBNIikq)XK8dsj76bSY?!Kha-jsKW-#*90hno3kfI|^AQ>I%O!)_r>14ihFT}~? zm|kv~Qx$;m0J;XwV+OX0k&D&IstCj!a>q{;08{VljHnIFSe}|+dFk^P>l}gdpiRkT z%F$Y9lz`tmv73*^H8~$$bz^M#!|yJ*VIbIqoZ~A>{VD6G2pg1fSd?fQO7wzfhHK7N zqk)GvQ6|MY9s(GQQsTIVJDT%Quo^EZ?CLY}YCrz^L~6luq$)?CY@t>>Ns4=zTNJ1V zO|@#FYTiX43ZsNV5^1zlTG;-SK|Vl{v7p#%2)w`ki$xF>#+SYkB@ra>&UEkCCmkf%Gq>LtJN_2Ky(=SI6wIdI*e5r%tg z6uaMJyE(igWc*q_+Gu)M?}e(n$$~0oWDdN@57BOaP9pQ-=jxAPK{lpMh;Da-jkW|} z2Oc>oP>ala``QxD?i`khKO6ETy|nhbuKhJ>pkdPBmIH(2)L19;oMEy? z?Z7EOL@`~qD;)P@D>tB+>?CG_sxa^}PaRXoAYE+XUZNhGZw?v~6K#9-2*$iZm>&|vS5+dm7CxpN8=B@b{2;GY zvj3Q5h4t0xC(%N>6)6w)#FH>&)pJ#X%Q^6)2mW^8A5GK6^?6n7hI(+)T-cH69%xJY zwp~NuocCC7bDr5CfY7kwxI$jIl|rI}d`WY3ni9{7OG1K+~Y zv4;O(NZnx^$RZRNZS5sMNpUuBztEe}qTe|wU`Bf8O-9 z@n6)AUex?ATn5u8-tb}X3E%I-l-=g-^pZfD2Lps{$( z+L@;9PTN=O>}{u$Ro6urbGSEj&NT@CNWD?q1R*>7KhySqJU{j&>b%-C~Zucbm7b>d7}G>LVdM zm-sQY6V0rAVZykr-ERX z3ywF`rSGr;qcripJJDzWb)?t*$zNDyEpr^4UrW9vs( zocEKB7@GeAUA19su+mP0groLTO@nZRcBO{Fqmwz4&#Ap=7EZiBF~&Iw!w+9g1m;7s z^PN(z3tNp1LT3RSiGDn6%G>7z(UkGC=T~!LO>X&D)5qqm4*l^ayk{Spo`FBE5fc!1DVF_Qjq-?*7Faygiey#?$yVKMK4pytC33% zx^s6r5wW}Y0PgFbA9SB47jkL5E~~bX{>e*Rp?recJOCjUYRLERz>6Bw+BZ~LNO;sR z-uFnFy3|FKaHobdI%{#5<{@gsS1qTk*Up1;rL;U`O+l&6uV zVQ+$uc3{5KeYjRB13GV5OtR(|zP223+(L@6oIrbgnv+VKf!Z4FK8G?sZ-tkqJgG*( z<;r#i>7%cz{jLT^xgOrUn43|T`Cj?VG*Ht9Vl%)XTY)ASNoVnvwf7BJ9F}NF1;qWj zNQ-vVZ;tU%X*J!mzqB_wP769TU)4w}1@SkKygU6+5s&?;$Asw;Ka{GO>LU*!_8Xv= z*1PwP-G-&)qW28WsPa-|9^$ipDs=v(BKWAhTE_pS9e#OH zYY4yfqix=?!q|QK?RX}EIJC)R0NGkYuF=+iVc|a~n}zywE?=SZcY*Ptf3fD_L4vi zXiLR;5)XE>{%@2+|L4lIOAg#BqRsA6h1qYG)&CX*t$J`4+Rw4>`8qk3RwN6{agDa# z;mfR(qy|HR= zBmi}Ey2BJ*UkP4o${mps`V4_XjXqKjBf1B!cu-YUah;gh;C~Q^hJYx_I_`X=!AE** z44*3}VE+lHD<)132Ldg~OA$$93^ql)K6@9jIv)b!E?}d7YKQ#Q@x!d8(EkAtjb3LbYa^V>Y za<5S=3Avh&tC}7TSxtn-%Zp2l7d^s`7e&Hf0+vbnM1zY^AEld0V+X!G?i2c=DB*%h1~Fz# z(5RfpHe55X?+-{v@p*gOO%>z^(P7*W#OM83Z>AeTIR?W6g1r{UGpX0}On$Sr|1bD} zY~m4IPVryvum15UHM@ZqF)bJVL?C;>fIRz0yiYF)CNe99`i~aMuc!o_CH`WC_-HxS zR(?sf5%a4(*$P`)%uMy|z2fvz(N~J<7bz*D!kcpDL%0Xo2dNT=eK`I~OxX5TXy>(u zqyOhq;CgEi3yMmXEHZoYr(_fsARCzF*eVi%nf5GQJGQ`d)N$ig)oEIza-!|u7G$({ zpFD=w$OUiQE9_JPK%O@$l~&9*w*RI?6fb8Zygnm0Jz&V4Em9ZszVvoRL?d!6WG~@) zgR3gQOfIhXd|wf`CuqTB-LQV+ras|Dp}6HIko~*eJMU_#6m2s~i2o`Myq8<MDKjPsZvsMJB#P;f5YJ*2b07?WZ_T?5K;H(O)F$j;xHAdqjNe9(!F!W3lzp)dYM{ zUyM43i+ILNpwE8a!q)A>88^k7IyE*TjJ!l+Aa@KXib zu`A=4dzQ*&Y`akwjnY5mW1)8(}0)76-YAfVPJd)=r5Lp$A@y{qax{lekRE| zhsK!=t^ML24m+h&3KC?4bCaN5Q#YPWr8bF-!@~?@6f+(WZCM!h+n|qf*XOx4pgAYB zxP(tTInR`Xex`k~WH2y{_sw4Yt;E|g0s0v0<4fCAt@}d;2Rrtb==1=ON3~>Kz9WfdWS0v2 z?}v5d)+H3iW^*w2?d8k<7t1>??NC|>Lq!PkS%lH1>$)QT&6+V@{lz*Gz4l*4wl6R`IhVaBuyrTY4?(U;nP6c_vB@ zcVS+2YE9Pou2d)ShR7g%*69-BwUn1Et_dlSaw?k}<`<=+#;cz9%bdsx@T>}W0~qtO z+>Bwrc?s5w>3vMqRa18EXNiPwpYy=uwb^P_0bE|s==Y@m>qTG93f>po!AwBdJxe3j zP1G?oYm{*(AhSrc&WcdOeQ1!tiQP2QC-)T8#)D6^^uIsr2cRf7<{e&hyKl3hqYc6) zpX8IjbGhLx z$}t&66V&Z8|5C-G?fTaRmYol@)S2ECA58}$cozaE`+?W~YUT5TkB-5!ZO-*G#>RB^ z)d{|8Yr*M-u>KADO|G|}^X8Q21wkcy8!5}heW$j3mVqJ+Gnag7@Q`m3APEu&KaYj) z$!t?tXKcCAXZ=;uA^n3jfh}79Ee&n3YH24E8|RQ$R9^x5Q6M=h+2|(WfNE=Gs{$kZm9ijLxnJ+lgo92V9&02Xp z=Yb?-YvMbPDwx(N%~3pKqk4DmyzrzVXLM%t?o8t<^m*{vM-R+APs%AKX4&oOd|-8v zHa$PicXC;O5io6p)M7t$Gt4K>Xa&FvXz;j*qDyQB$@ut9id6(}G3*EoFM>5qUxna} zK_M3h>r*PQV-{hYUwv~!vW8zuDh6cJq)c45o`=3b4CCi`;y!1LtlVoL>p`t(%5|OJ zE@4}u{_zH(C=-v!xr)_~jpW9Fe3np1MmY0zGp*W|U%l=T3W;VjuLU`q>th6|vn$FkLO(r(3C=+v} zGcoRvSfwYD4!?B52SUhME7WRJ+MC55)*rKn8u_07M06ozSLRjx`vxB7XWjR1GJJUi z>@vM9+tDO=M@7@1=F=eo`%2!{7=a}15-=i6b)nwaOD>FIxN^&5w`l>4@+N_055CC) zs6zmAg=E}&Tz|2qg76sAXt;oEedGL@-VxX6cH`98Xp^J}z7mjoUVH0%2L|=GK&DQ) zqK78_y*a^sx{&P>CjHjB`2{)j`+>x)LRPbpcSFzd^p|CsT8tcNr{o3RRU8%3>VD{k zv+_lVp0|h;)*36fE?9q?o8a>9JrMO*P|18263$AF8&PM&PV$t!P-Ta7@_Sc4$azNk za(<^$zv6{uNjR3 z)7QJUw6nE(aZLwgq@nn&`I%`=!&}pB=zo7ls+?hj5;Xg8YwU5z9{pabf?QaQ`S=|E z7<^hqistDRr6_)bWeA2y6jVWmg6i*3R>bZxfAD@#gd>@-JNu1v{pwt@Yblxz7%!p_ z=K=9_Cm8N@ib9+BFk2_p`!ZxZ=TFh!B8s+3#fm;<#I_^`>9$xJ-nJfA($Mi)T%2UK zqvAnF;%B?*Q=-&KPNh*Jo*xn5fd>?2Br#=W`$h#TqnYO9zEsk$q2rW}yya&OmkG{t zlRs5Nhv%yiPImG!nqSidXm0_WTa-wk2-p=7K1wtZyWm&M=}03r&11w>=ldh zjP}8RvV>haWat-5Ds@M!Wpa=U}e`8w`xb6@Y3uZJ>H!m24^E0fbs%*5 zi|)$iyEKWQ|0Jk>wP4azgAQWUua)t>My@1a*G(YUYHM^Q^lj0lr7}%dSg=|hu+GE| z8dE$^UcTW|dmMp7luM?yK(@g!6_Zead#Phc{v*dxg2IBgKA^FluSNRmHYIUgy(D`e zM8~T8(ZNz&iwQy0U##AcDXplV7!j%)`>kyjc)M`Bqb3r)?Xiy=N$3`*AJ%SEHc8ES&QBrz)mTD+8_e6V2Z@3oWCZi7yY#@>L zd7Ba2!@^~oHhgJ)o1rSd_-wW7bKGd~QTx5>-Q$DxNq$zV&5=nUFcH+qfm$ z{4yqyQj}E3`{2Jt4} zit*8f+X>^nEWe-FLJK=%YHF}rqqvo|uUb*_3d{*P6Klh)1Xwzzx_(MUvoj_WVFf95 zf3es(<^WCkcm4*4(-J54?OXKz2U&}4y_&S7-c^Y1MfPN^c)Bmbc1^Y5?yn7QpsoJ{ z#lk{T2TU)I+5gn_HdpkL((HMi`Elhh#< za`ebl8LRftZ03#qe3Jy)q`};V#3yBPf6C3qvQ=Kj!fLfhVkn^8x;C3VI^;NR(o4Kg zd{WUdQOcm~#H`CepZK$WS*SzsqO>bA#JwqV zAl_6&^AY$ntJF(UM_0&-z>cB{B$U=Rxfi`cj$f$fmOq-@wN#cQE(#EALVk@4B-RxA6-fxRAwJ>4Ngct62TvFqlU02PXUuZSxpkEPU z6AP$;m>hu+?PRgzwiysIapO|1&&*GLq{_QfiR$m0HdGj&;8BdHcz zTdZAc(y6Fk?c@yI)|cl9o2-Jd1?<16ntUy;)3$y1F%&+Xp+$q5eN|$n5qpOMmE4pF zTV6EWtNSl$|7!$`C-pZ=-#vTro{oQih$8`_mpJ1<=>8p1*-SA1iaIm#`O^i)E0L)} znw*9DL&dJn`qj0XKswExPOg8-x5e$Q1`52hPoo<6Vtg^8@G!ej^7zjK4b{6Kp%-^$ zhAJ9_HkPaUtn^fNxkh(R@Dz%8q=%zxsl)_?vlmW)F-WT+w&Z*Ti~o1RIB zI|QDkUO7}hI#fHPt_aLgsFCEZ!&r7#P?O=wSSK<*!f38F^;&07@v zNCD!`AoY%?0nPW#u));MwOzeawYUlWd_{$PYb&LaL31_kyTt6x{SfOaMsl%~FZ`?8 z27)`E$}vk(^6OVZ-hcRoXEkL5(}vM4|7#Ts{6GI6R`IUW2*sltWz|xBSb7>v(rc1m z5^bg=y6o|f=l;{Np&RRgfa$Eq^tn;3-`sS<)b)LL_OkyL+G6?{gc24#eduoJ`MYCq zN#9pfU~M2k%*8!EdM=MR?m1p45b1s*ydnj}#<(M~&MRMihB6{0-&{opjCO*zZ9 zDRjb7aPoTKhmaV@=S#g7!_S%TOvXg#3G1D(8L6(Td1(@Qb~$%-(NIHi42LVVanBLo z@Kdf?d+`Q4&l`{;+8*qe^rs&oJHg7uJyxx&`r}^kXu6bwySE-DJE&!XLlCE(mSMu9 z4F)j!&}b#?WQEyh%R`{xt)1fxn034p2WQw{^%KMAund%_B zM^rnxxm)ZJZb>IaJv-AkbSJOeOy%Km;kYQ9(IEP`v$;hzOU82d*;myg)p)RL-_dG{TzvW*WKTi)+|N_mD!Q{FdocRR zz)^|no9?FFn-_lfgE<|wmI8)#YllxULW*1V?J}iTMC~)HVV&J2u{W9!-hNr&8)A(D z$G3(9H2s4+NqctOQtES>S~nD?=&CrlzCXxdjfwm!YHHZ^WO`H)f>%}*LIes3K22P5y_NszW zL(W?CY-y~ubhT%JO3**wmo7-ErW!qIcjhU=S*K08V4cqF)ur5)A58N9lQ;GP*Vaj( zFogz4hTJqfd?Lbw{%WRgv=87VSevPz0twW77PP&d+0n?8JbuP!@SAip=i{|6KtOTI zPk6KCz}{y4;9LD#*H0|-Wi{JC!R!;1_dJMa(hut7foV0kvgLD9ad`bTUF85d+u|Q1 z?Ttf$Tg+U3{`+g7==@wRUAVEbD~-Fd?a?U^kwUd=TK@aoYig@RjuTUwnsxBepJtr8 z6KC*L*J2E%$trvv%}Y%ZM83vD`nK5Up#+VF*ee};OH)o$w@9Xv*g)Ti*&TN0=bClX zC%lBB(hF{&qj}Cv91Wo_Xc|bnp-kXhOtST6+Mvc};Q z5BaVM8Qm#w==jJmL<@mPeV-^DovYC)<7zbrWsSg7EUMdc)?ueZ%4bOKH-?wg&qsqh zNAA+M>lsa)gYW8G4r&L65G-qr@N!cZn8# z``FU)Y@CIruWWd|TZVf`)?lk}76V&?7P)YyaN1#hdhz4+{&4E!^)9{C2NkYFk(n~0 z6Y8nHbNo2VT2)zb`LPLo5raXmUV2784e_slnqQ@+o$Du@z*qk<=jIpT9_{hje*zAR zgxkTRmo8KttSF)x*TYm;JKeBYq180i}R19%QM@5u^yd? zOwjjp5j7pJeinRXKo1luS}0aVg!=A`iO&4nG{#jL?-0yfaqvc&kx~zn;T9l364^{; z8KyA!|E>ygA~&qB?zIPU3pYJ&GNyt&G_e*&ZB=ETB;jScM-03oXQ#_&98<#o{3*s6 zPNEy6Xlet~hf4O(?vJvDbg;h|0GCh*#r65;JS{J0K({w*0&VoS4QI980si=@jaZ$& zCOkYDxk*k9$-`X*l!bAVY6@9v+MiV)7OR;?0oM_k0_<8#&<*q_bZjpZ#c<04BKhY*0GtX3Y#!$wZxNd;|md(+l89WhizS) z*=6_9o8j!@sj2PSD(e)7MS%AdtmSg`!kGiRb6w@&?CM{wHa*fu2MVLItb6Ubf-5vj zBV0-=`zb3cL?5Q!_5{&OvvIkm^@l1nw~*(gyEtj|zP?iM-|H2suRAY}z}hX{DLGOg zPqfO4&?L4+2Ju}xZ;$*rt5GqOJ<7x0sim-eYNBVL+vCb#r#R-*By4*Y_eL5zo&6j7 zk#{~h3Kf9aER~b7KvNgS(kz$OBWIbmzLG~Gb*WF4W{bW|1dE1u(@a=lP3W}4u;7Ou;O3aTdxH0%wb-Cdiia`qPrLWTC86Kx7hA;0nlP7pgJx01 z(Q0>0<54_zEQ3ayMaut=9x>;L${q3fH&=5mP5l5SA8)DMIPV2m`^mC-O76!Le{Tw1 zob+X1Oxx$A)9#c|yJT8BUnWOe$4dBgapv?iPsDEh`J2tE&2}UQjVb_qKSup=I8bjR zpob|W0;6yQBc%;o6GA6Mto9){E_FI+8Nmb4N!;cF#p<83j=xwg3}8T3{GynzF!}V5 zs6|7KpAl79o~)@#>h?VHTcAcJ0BAL6-QZWuyhIxq4zwP~>59>6Fms)lLxad18z1P` zx{@8kZ{!<#Rnu~=we0oDu0+ zT*x@kn|TgHP~W$yWDi$tRFI$fv}6xg+Pd$iFEnqO%&;D+|C;cxaCTl=CuJDB)dSVa zf-zf=mGo;JW?b0Kl--A3_vM>aLr-EjN;J+4s=bg={hVwG$&JAEuJi~;O8nRk=q_=W z$RuWvg&sBZBOz;|0!OR}q;Pas%pm#`mrXSFDbzal>y}lIl{=3l=(^1`Z5Mb77im^iR3VIcL4Q+qksICif5&^l5l8)RrRFSYHQ1w#MI#-2Z7FudWPf!7#{D z0rCAex(j^IPEH510izP>a?8IREz`6sTFWWxKo8+nF}Sw&rRr|b9ly(uni__%eP-N2 zoIkXSP66ehhU%#1gP+kx6bPdl8KD5S)R-R1{p4n`i}cpHRsUk)b<58-YCr6xEoJZ8khf_%R46sjSCMed zYo%$jQ$_+*Fl>1B3-QhFLy|2_Mv*Vc^kkTek4&Cp=gu!lD$TH$j~p+_>3b7=)HTif8$BzI{yf+Ybzp%wk>> zQVzml!7`v=W<~wU_d1<|?;boU%SMO%eotxb{TJ(dl5wnKld=9WwZ|kvX+#nzjH4hR zmYF7$DH&A+0iIkJ+|G-TpTfjfB3YhTA%+Ac;re7#GG~snGW*L9957{mGv9miakfjC zdB>Tv!TXb|jzZ_ULcgUS)tHjpUo3{#&J}|Ky@dYeKm_gG;A#+RzNl;lmxC+Gt&E4h zNuzQB9*>1-?s&x-SXn^17X^8LtYeUm8@}*_!iMgp?(`Iw(oQOIp^B55|AX4P8k;tu ze!%CSBC)>kLwKbJxCLCq=dqvuxnAw1Tw+J~;lSqc+0Jdo!NhY^l*?}WW~#HvZU}b9 z%W0ep@umRrwwbf^{|(;)X*Af@Cnb|8_YnHEX^T8C&x<%lDNG2pCPk_K>7DkU8$22L zUPIHe+?x8d45nhwAR4C{8OUbLt$q1?YW0vd16~u&Hp~^2K3&Wikjx&jG3uOnPhYP) zm-8d1z{5q&%NQv2ut)4Qg*LMA);eI0kZB2TEq=>hJwBGBWg3mD*+F9Mjfb8&f`p5#(}=*Vl<7Z zJg0K@IXMM=7@QLzo8ME>g-r@BdCo40rZ4F=EqOL!j(Roh4r9!8h6OeYdEY~=_d_-N zc)W*amkwnklUU&+Ke>r2qr8E?cYE}Q!BC|){Mkc#L;*gJMp}`BCw|w zFS-N!mb9My84MVv(lD^~849hR;3%)d!OrYLFUjz#O?;sOniH#7Jp&AF6342oEZTjA+^y&-;>~sn2{H zgmer5b6(z1*OmF#pTeH;`C%4^x=I^WfAZ&jFvpV+#ic@~DE92}8l=^bkz%WZv2D{} z`g`t6qHWcuIfR*{`T@}6qs5@Oe6mWvzJS7yZ*-Jpi5BMei!Db8wt?~eeS*n_)O~rO z4nMC`dQ%rpiF?Z6?kn(IgT8z_C+#5s)%8p!Q;Bx);#zEZ%I#?40d$%x#DbmP+8w{z zZ^NAK_o`=ykSOptMI`?N&&&P#{n(^DIf9NlURi%GKgG)0moe57Z?#yki>Kbcv98bL z5RLE6I2hzorPR-)R4S4X;4e5-hdi+vX;63UadWDjHSeK!9-*AHG?D&z&#C zAThks2Y!H^pa?N2rIF98)_dHm<%n7;ImVHr^=`)hGD_3NHQ_2Omn#U)RL%&y7$1IpC#w2$|_Oe6oa@vSycalbEC z!+XzWi<1YhHUuf_=@oOSOFTJBSK#~#zFTnmA!#UO#bI=;pPG93bE}FkSA2R_goqLC zLER^9>{&cEX4}<%KUD2OZ8`&mDh$ZFN3VT`z5XddrS%U*bl^Ni!|Q*8N=7V*l~^;$ z2uWeBEMq?3JlUb(R3)R;KjIM0swWLtNhsaVouvvVFjI5?!gH38mQBJK{Zk$HOSBF@ zkE%LXWwZUuamGTma4+u*dT06-Wg>UpJeG<=w}>@Ed^qkSqwBv|gxrNpwAP*o=;P>u zJSh&VM6TQSMimsVa0c?raiLywvzcBJh5h;cnDTCEvqNqNnS`+^?DG_Nv5xIyw=Wou zw+#Q7r2q0|N<~bi{5?t61X<%{&TTfaJ9$%6cC?!~I~Tc$y^pqIb%`nj*!CtRQxZjr z%?Oz1JQJh#k517p4sEf+<6SspHgfE5G7`M%?P;Te?Q?YGHyI|hz8s&?IIUN}-0Un7G z|G@7j6z>k{xkJDPVVvqMfeOhAFLZj^+obEuON0e$>w{g^sgF#uzOb;fKJBFd2ONRK z{ep7qWz3KXn_e)NcqWyiqkPig@9(=vv)8gr&{T#8;dM;@?`A$nT<8CzXjg&hPHI zWEmyDutI!&5AJ3$%=f=oaSj0wo^9&uywoHeUSgxhtV%vfc+tZ`-yvIL^APfi$g60O zv=2$rE2Jt4xS>=kkQru-K8v@M(;gcu;KLE06t1t~%YQ533DGV$!`ejE={E^rucP8* zI6Y0-UsQiX($I^OO((hcJ~Nc+Pnbb~+w6G#8`xU9luo`omEu_A@}R-PyLDMk(Yp{; z*A;%TtWkp3{LfrBN>noXTHH8#nv%-cY%9ys;y}GiZ+1xfumzh1C4Kb?NYjxR>O8}!-MyAu59!LI7Hu05i`%e zO~>F%j0#54R#!yc`^@IbRh>FSOiCpTa>yFEYee^0R0!NI*pQz3?f z8yaZcs$VVJ3uUK#bS)=>FEqsVX^v|{K-ilCI;kp6h@nxA5j9)@NoloD_{d&3=OsI> z7)^m9_!S;I?x+K8gpFq{b!8JW5p~3+&mp@>nTOa0F8r=Zsuc`&MmGhgjsilz7oS07Etwn3$s!HhP67BIjIUB83eH?7lT`rdCHsRb|Q|_MNLz)I}v_u!G_tOJN>2o<#)B_-_S2wk<&C!r67i< z?m{Oae{EfZ(ylK%|}V@AMg^9yIYJx&8Sd{OD&i%6E$+dc;!s>ZH+|ptdw=iz?)~G= z>^yVMKADr5GtWF(=h^>dcE`ihtSpFx`0B`wI6;%>_?jImPzpBY^aW;kCEmuYt9C;L_UDwVqT zhRjAR&6u+0#J}z`X;x49fV*EGg+-x7_^V9GrCBx|ni9U#@|uT$XX!5`?_E&+iB-ex zR}=l!PK}s+wu*Tgg*Vb$wVVlxD{t&Cw$fw-e0`Hr(k)|=)`TU+cz+CzTyMqy z=LYKgdl9vs$M{k()$ z%h`PHsXce7VSY_z`O2~pngjEf{W4Oqfy+C{MD^_B&^OO^&#}*pw(WXbXfd>_gXD}< z^4)my6x4*?_7%YAQ>Krp=iDAQJ%vADfMd~!2#|`IT2ywde~s=)$d5+`j%sB;c{H-M zq5IZLOXaO**p$!l>d7JW=b_*Jq2C=k(zdOIUA};M906^_Hl6LCs`S)x0nWyCr`-?# zdm?IpRB}roVI9&>Uw2ODlg&Djg{QcpDk5pw2Yuv<3k%*OETGH{q&ocM4xbt zh|R}X&=h$)Ydty3!S@ZOm=r#(gC&wVN+=tjEJQBQ zuvt*Fm0ikmjNRpma~g&^Z030@jPoG0wbnhU%yAz0j<=54q3B%cZj|AvPy)yWEtB-F zfn48O%*>r|`@@4fq0NT}UynF+D7=j+q`LAcr0*ee(qW`esq-8LK{95-AV*YQhZpoL z^*+0@3Gs+ML+S0RihIQR=eff#FIIugNZFyJlp%JajE5$We0T3$MXw1!K}^J?1>NyG z>kaGW1qTYV^{S`19uujQk7HDd*!n1^`Xvafk;jJZq{y;O54v&{=$izT%HKt`Dpdfm z7ym#Vi>4P{8hWzYrde&ZbH@T}f7<-kKPh*ii-HTp$x8FQT`>wCkS2|5H$jUx##opX zQ(J7$`&wsmi&u{cybdHbKuG5#n07cj&Org!Jd%NH-TPgGHYk{D!eU- z+;4nBbh=B($usA|E359`VbB7??w@O6-z9VyS$W>?CrY=!?{$V)9*mVQD8m?YI=3z> z!&_;lyF+J@FFWn(B*~&vW`1dn9Q)K}CFAEI&>BFpGJe0V^2^7yWSHw~QQjw%%E~9J zrw+!~M(EWrXM^tRYK+tynTIVtqGsbgQH^y`UDM&|=HZ#95#{+CmGHlr|B9DozHRDX zbIzbj5h4oxl`!%M!(a>)qtIgQ=2)Is%eA|XyzRCY?#~;$o1b#0`i1dyD@4DO#Yc2? zepSsIq(NYN@ms+~kO%MY&#*p`N6Ec_p#rIR}`#I}%09%ls!CPp!UYW|NDo zd#)t*%pPsqHD|>=c#2+sEPt!Ets(p8k{X<5fzDgBXT_Su+pDl4(zC>Rf9Y;2C_0D| zZhg)W%@qFup!)~oUT(r61>GdKa3Jlff0g;hWPI8`e>wyUl?SQL0pTsxBcn453TGaD5Ib$Q+k{>0jhty z)1`+*ac6-#E$qKHtw+ck9R4I1{JvXso11x`^`Ajo-hLE&h!SQvF-SEdnz`;ND=t7q zoU!e5pTr*cNMDy%uTSL%)RKNBwJkW>I9|GIV`<9j4u1XMCtw^I-<+W zlIHCCtXhiZ!myfX0!5jbZHsq$g`Z1)D-m&jLHcSP;h=IYcYZPO+ahYn+c{_pSp%!t^PX( z`K$0&oJwu1ccqxD>Eo~DGHQYZxSYIr^@Q|OM$?#T+QzS0QwWA3NQ^AsAS122##S*hkrUt4tAvGq53&&trDLkF zw(YQosgD`Ni)>d{`2A;aQMR8pi^;Ad@8NBf-pd~9$~5RB*6>IDj)_~4?x>%s3W#JQ4t;>2ba68=6aI9CejuL3 zWQ|$^)+?OLxkz-w17p1A)TK0w7x!O1&P^0t1w90PtVf9Fxawjs*I|Np`(FTLZhwzu`q2uPCCbYtlVd88d2%QkrloKrpTu{ z$DY1ty0bzEQp-|Of{PCb-be@qZk>GyTm=UPf@@V9!v^NgeRlV}=!>^)rv4r4O@(rr zj_Xsf@%laA($uglsA3Gd$*;pQ!`HAd{d>Kd|HSrwhr^6bj2w^*T^6SA`d24@c3V$I zo%vw$Qt`&!Gols}`{CMEyL?>lrg~e})H5i;}v!AJ2KccgrFuG^rF}t)f1vf;v(%x|p0} zsb3}3bSXYhPm+6RMM(~7vIdt^Np}B;Nkjb(B7Vw1@{#4QN@)rVYmb3@xHGu6j`l;1 z`%N5goM(Ws=BsMY9<}=%-K@W%jW&!o5O{_pu#Re);>#-Pd&J+Lk5;tt3QqOp@o6$r z1612HZViu!Y*rYfvE&6BOIjIfP4DE}8=qBgS%qlLu``=;{Z&~$`knmC>E?%}OpQK! zAeADw^Fn<*MvlR)=UFH5nF8<1z?b3~417Q%=)+ytet+4#WSgu}is6ibyu6HLN*~uG zg)rDu;^0{s+U(0Fa7g#so$OH)Rlfp9sDsek{z2QNDY=j*B~9#d2U;>WRY<S8 zbbSZD2Yc%$k64eys9l&un%|}ES@m74b7fV_^_`F(lwb|gMo11ybEgz2oITsz8?UOi zZAg+1NaUctw}-vx0^t6tay2G*R%l%jpj)-Q9`k(RjF64ymKkOaozuCV)A6y9+mw=> zytr*8G>OoxwHw*J=%Um-sMEoi($WB+6h?=Gw9FGUd$m(r}u4ALo;U?u&wxp( ztC+Kfa`J&R)AN+4$6Yd|B#C+w@z)mw-?izWSGBG6426YPocQvhXF~6JTt#2~Xhv}!g9dl`aAF`dsFEev&=*+&F3Lv}Q z$aCS{reeuFhBQ;D#|*e@SQoi}hTO0En$Z7Y@UIXM(RCQnYd;4L3;;;mq8F8ygGb-9 z`d8g}X0jT}gVHwqIr;E1tfBM(XT~HCj_{ExW?v1RtoXsxnJwr~x z+dpA}2_xfFHy_32Oy6@BprtlVc5PP8ez&LY-Uf+}5&xz+cT#&V=(K%9vZ(vKa-8fB zU03R;uG@CcbNclKq3C$bYXfJ<#6Fs&o`3eoI52i(tno%rT-FNW=zg~29>k-9#`Qee+dc_T(F%M!_Kip#HXol+JQm(r?B5HhpJNR8SSNa zMt^dqsmgsv(vKAGt#Zm-*Wu?BzCZ3`obgrC3~r3;OJy>EPp%x%zYKDNO*F;pLO4xh z$;zPX6h3r?JTk}2;^jf7yEjWMFLU}LypQ9{9W@%(4UEGtyzPxAoP*EYdN!Bta;V!e z1N(WB+1_u`E(9$3l=>D6E5@^#Xs34GZJC<89|-NxVuKwSwXwc?qBB=xc%3IwLzyC(v0Yx+D9h>3hh$c zHud9gF8RcAYVSR;^>3DeFVh>Y#rW^Ggj!EP6F@P@^bViD_Ue7J%?lTAF$EP>2g;Ir z`keggKTiLCzM_EUAPAvs@##fCJcQp^m%FQTn7_qf3p(YC-dKgW-mrZ4f9tYHO*XHzXT^Gry#1wkD0VA+!Ay1kTo5hV-x)O1*_z5OfA25t(_FEV>5q{ z(sr-yIkozf+D###7V!@10MmZC?a)Nu4 z;03{w_SF0bW7f{$%fl(!OYZPeHJ?!KY9M|h(%dI^H>t;07|>t73tGwxnqQ_;bLX&Y zhA$Mu^(oR_-q5<{rMsUr=}lJ=+l44pCdrCjJ=bE&W`0 zmFz#K5;^-v$I2&|WsQTh7Bgy#0N=88|!Y@cj-POh2{aHv!XLpHf8z~FjEn_;c zfgeX`S06$eekDyVw60}+Fn(V+?{6HVDKzcDAzk0?YKiHL>(ymnaU=ccZ4_d(m7B&{ zu){6u(&`HXM~z&d^Q|oXGA4Hwd_7`urCzOx-Tn7W_;YS%MKhUC^`ZsXIVBKpnr}t9 zj-RHUJh-_J=-nC$h+>Lbc_Sm{GqB;P#EEb zoUKol*8;Xo*r4z!XLh3UIOqQJxJUX(LJ@hiKOLC0$HXmDrLr`Ptv#(GtRJQ;f#Nu-icvHa z;CQXQie;r4F~#6@m-KVUz6e2gfaE^^&2Fe2H2*9k%{(b!Y`nYlLtSa7aZf}9yt%*Z z*-)N)ljL|?o%or#;GujLosb8wopnfq7k<5N1#z{#2E)36~^P|5I#av>hZeV;AF~q|Z#C0O9 zcqX8uO>iQzvj`d>*?30Mg!hB9h&r^Qv z=VWL2%}z0%3f$ZNYYwbyee9o^iB%_jZDRbdsS#lF{Ck(xKNo8%cLEp z#j$QVcPi)i20+#H7&|_)WR=_O887qN^7$IHFS41ty!fJLefqM?IPrCf=q`x}bScyV zPWYY9NjL~X-9_^9Nm~mq!;0u$cVpXan2gs)IlM&fP`$HyHMJ-NpJge8Ks!HwZ<=R5@!S*dKp8Y;7}j5=1BH5WPHZ*c zWy|MfqP_rrNswl_hP9m)B>0W45}rtb9FwndN!+G-zzYGFKK`gIEwryMG!xyoP7#^n zU>RCi^E+4T1E+L-uwg~75%?dBYz$9OEnsz%Iz%nUzifQGz>PV}3@MwiAGC= zoHuHZRdAw=BjO3jAEDaxQuGV2YBv{sJ}T_HgEys0_iH9aL!wF4CSFQ&e$6=V?Qik)LX3<3O z2NN#a5lA(2A4U+ls&-mo5y*sbIVbi8x~aEUOYLWDT1>XO2m54Z)8!$ORdAd%1E zP@8(AS9a+fD3%nZkPH_DqbYQJoOmy<%gar$jQII0mP!K+7R0UPUeK&UA_gm+YZg(x zuKY@v)JG}P9`2)5yh&Ypr&M5HdBT?n&*@RL;#FEHJ)_vPbs|$hb`_<@qor&dKxDHC_)TtA+EmrD~2f zo_W1ucR{N2a^n(Opm=2NF9w^c?21xdqL*|f`ZLe!2}P!5wJI`Mt^nN&%PGy*-3v$P zv4b>J^VGqT>fs}${Er!R*f>WMVWuEd`zu~uDnIXCpW3V4AK+KQ1)dUfoF$uw=asT zmB$u*M$|A0#3MK64`VtKB^MpYa(pOAu$oS?%V)$ML-J!U`p9xj!c(Fwkv$+Vg6Uj< z&?04=aR{k^>?k5D-g&ht66oI zOTY&^E;_ELG;Z)!>SS-~cW@ukX1cWV0o5;{79%tVR1Yb+o|I?RCHu2P&AQZO7GQM8N-bOoT*=&s37a4* zCHk|@>Is^*bor&ZM!}5e<$`Q`lVs$oSe#8o_v!7SEdVxyB0b!Ck!-C$&HQUR%T`L^ z_$dxFvLG}+O7N-C2W~7K0)^#({KfT19p=a|xLt3z0SCMjYp_(7LeHoyA^~BihPe}` zqR#xz!AUL+eHZp7mJowI4V_)fc)$AH*QL$76gZM+!XCWD6Bo;oUtC>JwbQih%4`)3 zeMX(iARb=kdWQZ#o+VV74JlS0M?@$0kbrST4QkDZ`41S3F~>15=EftD^(>VbY7 zvGOL&$+0pf%!%ju>W~4;0NcrwQ++vNaAXGN=Qjiuwcd01{;WnTiXUn^6gR9;dBbD9@M6ZU&M-6XKpo56mTgu>G>CqBplt&rUzg48LK z05xmnb7^f)t?4>Uh=17B^9=^zP}5f)9!{WA!Mw$heFXaf{UnUo6FqhaHN@dZ^w1cKWZ?vIlU(sfW?D++~yP8|p^ z$U|P6OU`Ez3d85VRf#67S+`y_B4R!!kd%woV1^|E_U21og{`I~$7Kr|3ao1zuURgI zRFMa(sW9jskXc@S~?S@qr)Zwwo>mf$0IW2fzJ%biH!)e&%OV(5C14{N|5pAOl zd77k#+!q3B%dC_kw-B1F`*8Fhhk({MmNvSf*x`GwSbcDBBX_&t;!5{UGuHqfS5?EM zGRLQ|cs${yU|I+<+A3z;iyO1LFh!hUwfVQ~{?AuSixcC2sH&mckwdxmXMou@s4qdV zUO3SN=3DN8Mvh&(ayp5i;} zu=Th8h?02!c$wVR6{QFDziM=LCiQefcko7D*qInwLRiRIJIgsqx%m&${3u_uIIMf6 zYUjE&>BST!%^HK-Y@XyNIi1}3h4C-}>Cq>hnB1DnL8X;xz^D*lQw`{)#%V;2jF7Yz zIe@5XjMz5z;};#4jya8V{CiSjG+=N`j(uT=GxbdLE!Vo_bECpF{tskuwPnok&^`@7 zv{kv#LN#VwX$X^G2=rV1U=IXA`nbEOu$^m4LS=S8D_J#CxPus;IRws388lzv`!)8$ z94{ea(wP*LA{OESWu*lW(MlOF*-l;~h)EbZzY-JEO8KB0*>AjNRWKFOb?s_=x}JJ* zbyWzuPkY(@^0S6O^-*&+12ly_l1&}j<&Brtdmo;&pqRgVYwZTvV#uMK^f6%444Rs7 zXh0fm;g@$@0*$)?+_(DO0j2qiT&?yCS1VF7_rGWxn?*KEc+Rop8m=P!P4J%SJ+ifT zY1RtS8M7<87W1Fe=%2z}<_wyS9+-3GNQmrV4@-3$b>e0+R)Bk?GO$dPm4(9Qs@AQ% zzntg)_kdnatgaHzztg4K*30%MSQC&2Q`*JJ6gt2l!VBCUrV^ z^Us70%YsQ9HhM^My2=!IBG{}9?F#0hI?odg?3N={SEpYz``+2t2GhZJ&@i=nWBLRu z80=mD%F3T`8-rU}d0*>|O#kn;G+kGIX8W~RW${$axU6n2J?$ z`v;@%r!N8)7j$(UuOlGPEj3)q@FpTFwdhfStG1&Q(HjXZJEep%g;{+b(ualsIbEV! zX_Wi}J$~Dax1Ous3tbQZzc)CF_KI(uBz$%Xo4MQG6zWoAv$jx5^0Dl<7D8(@0axs{ zc~gE8NGSTgu~D6m+1n4QO=KpGL2<+%IZR=R5Jem$gHm3G3Z#-5D24^{*Q@4l$NqUx zi~f)W4%!@{kv4Y=bT@K7q&L;Ogyw|3zvkVg1eM;8O&XjPUwlpG+@+0EzdmpJy6opvob6mB>7~UR)2b#5&|~D*Nr-j8A=!D_JRVmF?Ye*>e$`d zl2V3MOh5KDq1L9U@?3=@k&^lE>0Zf! z%tii+2p--w!!Y_26^D20+_sZ*MC5PARGw6j!c~MyHVruqUEyIbW>bk08@SEMNJ<^P z%cPWsX7>kN?vAy%N990F&=c>K3o-i5R%5If6~#YKSDn4O?mBtU=D?6-7xIlXS#)}^ z=(9Tf6Zyw)hU@A_X^tX|_v_OS5$U6hPx2T=UPa!2ccgtvq~0Os zBvmjYgKwd#*-spxnPQf=4PJ~43)2&^0F}1p`@g*92lD*fNylXn)X;DK`KeibVCF^9 zNoRND?2Og;0gcA(Dmw!Qj-pDX(>|d4XFm?~t9hyvj$0hz&)3~iY5L~+b)xbj9^c|_ zwCru339f_gR>STbf->JM$2y;d(VUb&d>Zt=$o>E4x&j5-hnahK5wKsatuGk$eIQuH z)GO0l(O;MS$5L1f+LdlAbQT8)gjF#s;z_)s94mR_V~#|k#U*n{+EYlyn1k3@ z{1qP52t;|bx$(jIDkTsc_4lcKHla^HdUzC_@pRQbnD!!Yv}k@51p?xJ)3 zHeX|UxLTp-i2gX>5DszO)u2kG_{++NKK~}+_E3PSk7P0S zLDTKkvs4+~Iaty?5w??Qliziqy3s6h$yB>WniM$QHYCcsHYht97ww+GygE=Qcxk`h zcQQYttUBtgto^f|XpZkINkS#?$aJvO2!UGn082NyhoOdaYBNVi9V)~5l zU4eIeBz83D?CJ{ZZfO~aSV{5C$|9jur8fA-XO#-qiv@C{bgklp&lee zzMKNOX+9p@f-BRhjkgfCl2jVHO8!o#5WzO_y-RYQZuLzUq%m2o*e=_o$D`a$^PeM6V%E-fxIK;qWzV)y66ub;<5~Rwab_YGC%W+yL^xN6#H>i&n4hX%z&k( zMQ_ET&j1RX-A5Zxw8ir57kz8?qK7Ob)K@crD*!1$8e$+Ntxjoq!-_e_TvE714ul(S zuti02_9+xLUvy^{4_=m&xaM#!)yNO}SNe{zvY)o@N&P2n+dNo5n8PgpeDVtz^&y3C zv2o|QSQEU`7#lgx$dxy{p}}}D45QAQcJ`~xD4|x;^3z-Y_b`%j_eU}F4JIl!m4&&`_&j^ap1YkXaQHnXZTPI=!=&B>fmOgghfn?> zw^~F$f82`!h0DL0K5!a45?3}4RyraXK@wx)Dhw+2XtMMeiB(%*~;%fE)# zWi8;{-5jdz9D{3&q?LmA{23k;(lxkI*`^xZLur!>v|A8Gwh}poq^{2CRMx`~DV2lj z#}Z>2j#rYrFuM(tlEh1$nJw3CZ+~f77+?!FNHcHF<*;XDLLybWAbFOV z#N)2H6n7ShT*|nXq$SFEM_uB_rDpMtr1KS3 zlh?Pb64f!!Q2%M3jC8fUVuQ0VWzGnhi~yjcq7IvKdKtKB)tth-3G;l8$(h18H1xS8B!)P` zD0Sj2Z(Kt~WE%^4{dPVbpseiyt2G)+4{kZMM2RLmKCAbNQL^1n11yU1wmI7IZwk0} z1qYlu9Qn_8KV&2=3Mtpnpe!=pT&alV*F9(EN(b2W396=>%HhG~;>i-eqpPI6=h$B0e4Uh zAD5zboTZWN5vC$wRItu`8&5OKD^X>iiU>E@wnU=vQx&(b@_8*Og;uc3oGcy$%EMjAGGW4-m|_( zcE#`}7uMkK9>l7-iEE@4_e@+$ytz7q=8tM#c4xe?%3J@|*Ba0y_iEZI%DxFiFh;xU zzO6(f+G;gY37*zja$ebwQ5IKFBHAhot6O}I3Y|f?Rmv8e1uuuF^C0ON$|9ic?o#C_ z#pL-o!}MIP(h-LAi|>&G>|~OL;0d4^B)YN2K@wx06gm3 z0vHA@F2QKkc_EwO;kPfGw6Hw)Q-EZN!VrKl>B(AWc>E*zi(J$0qh@z2>pe7x-%#|* zD@;o#El?z%3yqS@2{(vMdfzhwl;MIb1&?rsKN$b26`$&3#3 zwh%qeOOysDwv@;oE$KPRm~uxbO6JL@*ymQmpV#5dBPz5zPc>6k&0f}9lYDQozg?S= z7(o}UP~S@|zcIADF;o%mFy*>2l($xbk$hOiCSe(PRKZLVL@az(Y%CyzgQJTsF-C+UwCo05xW){ABeo>{TA0@bFS1Eth zRAQfL+`L{kD0Q;b3dv%Tu?web`IKRQc!K+@yz?a?3(%m3q!Ux48}z-wV{+E3<%P4= zXS3HuzfB!)#EA0F$8n(MrVgJ#MZ3x8B;7Upap=V9qpPvoF&zd z(;DJ3^i@TmUR!$(u!vP;Y<3~c1@GHfaa>9pHovH7Wlp{ zDGQ+do1@*Y2ZEJUUcS9vYI0jb+v$kQI+yOuvDzu=aOL(FPn3v(D{CYq1>q@Ts4)@! z>L}pY)eq|LxLw>hxWp8O#&dx?DH-Mk2F~*y@Up9A2Xotw< z8Z!fytGOv|wd~Tre$KCUXF4eCq&V*yod77stfI2a*w=t9w;BDrL;Xl z2E3TUFQvf<%#bH?T>*}`@uc$E9(6?L13Y{swJ{b1JSXJ*HV1dCdR_HCjA}F)5mn2E zs@-cDvpF(bDMXKHlw=kYh1#jmXL;{G3_HmcJipU~NgExe*ni%)NhEosGEYVAgBRvg>U+k^UfG?yJ;Ss?IZ5|q^5(Qk}oCJlE8LHyKN z3m-dnb0yWNPVSMp9D)lyvZ8!)#YIJHr-r~${;(?K(VVRWt5i(N;CmoByQ|Q z`7#>jhuZ76bbU5*yZjayBQ%Nff8|lsN6>-=DL#@jGsrYgVkylXf5`;Al(`ZenhoRL zr20-@V$0|l%HFV5-?46(PRt06M2qx}wZ1B&le&_)o&e!nDs(mKx_V)A&nPxhzXj-m zvv^yc-;c_>2uqspI-hvWG3qa>O|s%dmLggMl@;ZY;9o5NUIw_@KKO;{$$g`AH-1wS zJAOrROTkg(hox?1HK?XoG|3~v-X`cPhWF!O@}OKZa?qQ3ggzU)-jG8|X89e4IGiw! zD>@=sE_$UeSa{7SnjRlBL}4e^R~=}n*T}5nN6etGx}YR#Gj>o5lVOJI?2Wb({aw1B zbI1@?6lU~5$Wx6@)7XW#Wjdaduye00Ux#A`&mTGh(OQ|_hDS-=!Pud>Egs|4yZ9Qv zDp&{O?~vEOgDIuL&g6we?Rm9Q-8%gilluf^i-q?CM4|_9 zp?aWtKUJK)r!T#{7HvnVjzEAH<|Qun{s8xP;kNXl42ZCUjrs!h0%=EbraAoBG+#Ld zt~tI=Z4B;H=6D38lP*vzC;vM5H%wGVd)1UEVdw>Ev4g#ETN;dRd z!}WRH6+#AvD(kKfhNxhU_-k1-W50N%~u>rdde~yq-#FZ(|-VvD)V+Iz zb+KM=U~qT1OX+BvFdZdf^i=S=i=?tCb2?UrmLszBsWm&)IDE5T)rJM)gydid@{+huDD6>fiW0q zppKgcTg~<|JooL-^xdc@4YfflQDK(dFh8kjuS4VrDmkG1Kyj+0-PLDLxNKFPRq22% zEP0uQxqcu~V!!RP>W&xg)F(IF8vEGpP6lt+Ko8}}q3Al_+NJH21hj|K2lFy~DJd{u z%&309300~p8kApbV8rv4OmD{s_^z1fc;dVks!LS>c8Z>d2gsK`*_A5qZuWw7c{2Fa z9z?`mRLu(jYK;Vy>DavK>gq2Ekvt!VV0`|VfA?(o0p$yO{P8cle*O7QJv(#I2>z|D zsA8Zex@g{RAu!bV4@RdL;SfnQ(onhXSR;|=_(YhpIzH`l)GFpyU4vAhQ_Hiu^RNEt zrW-AS;wrcycHwW0J#Im-W_1qd@eP?_?918(-~V;(xojUL>=})MPs0bJQZyN98xnn! zne@}jE%3b42-Xfl5C|YDod)ho_yxea7)!)s<3qE-3ojlW*Y%G8vvTH*?}fU2cj|Sn zCgllktG=;n&)aiWu&QRgyy7XPO%JMkjKgcpkW>i!(s`$4iGD`g zZM;n314VMK(C)4ZpnL}msg4#JOl#IsjqtMoASSGwMNpd12Qt-C$@LJ)>0XVZygI1E zN_WpSxH8i4wR`GRiqWLH$)hGv(0Kzv}xP;3PutW(|9@E6$@ucdCKrc~-gK~Nj4j!w`tDw+Se2#lex zkk&OYjGCG?vX)s4^65E=)zNpEV2UDV?D-TpFhN5kvwlWslRgI|N8U|;(xV)Fk}C5k z{Ze>iEZwo(4!=6W6rAc0H*H|hVYFynIVp_JrgKTU;tOB&2_*WikkY;0LXoiwsk`IG zRjfB8tH*kxNN^?8j2At-xE)f(;=3)rS=9b_4ocoC88@oT?kSrBcXt!vf2%1ad}~cV z=hl3phsM)nN@&_)VmnBeXdws>v~T4UxJ5iJa{fVL@l3=UbQE=j-oXBuBxIDV0sUs!2w`UaTZjS|+>xj>N*I@aGG z!~p|`7hL*L&?T$OzV;V4qw8hD2r8QCh>Ukq-p-G4GKbPT zW3W)=a;YoRblMPa+S$wfnc_IX{H5UsoWu;5YL*h0x|d8^GQ?blZ-!#1-t#FC)+nb! zpOJDp`GF`7BX`y`uRQ)%@0cmO$@nVx$HB^_Pvy$_kGhMG_x@J;6pem@>!m-*L6dR= zUR=>v3qDpEjHr{E049=p$$QkE$~K#KNlh00CTP}E8^v4BLS>e{PgV3i8T1+@^I&;T z9c0tzIQwhjMEf9e)u?y-o@Mi>XTL&-l0Jo)qvJCxks;tIZq?Qf#QM!j;A%ZzvgC@! zkXH~@R5sgX{!(hgg`p)Q+P!1l~yD+qs2jY#E)`3CNM>kC7Cv4s@?u-K}d$f#^7k zcCQIWbZ96~2(E#8fK@8-349cjsHO_ILO_MG-`#!#g7q_9V_{C)bx0u>hez8@G%k?% z!S~Jp&0j92Xr}D#$0afbE@J2-8$MqChg>PXrgtxwbm=sQXq`xQo4Doo4cg$keTH!eR+^+>n{Bt3>|^@Guq>lTCN6GfuPqKa#FB` zO>20kwq;#OGW67@oh=D^s@u+%mTrceyp+J5jz#dz0p>-mRUOBU<|4T9!79J@iopt|UEDj$(?J09A7vUyoDH<*@AE>c%EtfQpo?Is2u+UPq zs-k$p$_p?^&1Bgni7V#0*m*d+&}Are)5;=hsS?BGu2dc-;NR&@4pB*TNi-K)G|_2u zn{(<@NRxSIk+T!FiCf@)7?a_f=Tul!YWUfz*xnx zSRV#mdU!5AMc3V|JM*5rL!qsd$#xp75(d8+&WV60 z%{cw*^UVy8y5QY$2mFFa(;B&@IQm5I@s|`vOd9S_UVAtj4^=Q6neX^u@-yy}g4#Kw0bq+fvbi z0v4Lor>XZsNzQ}1Q?V*Gee^Ku%)U4@#hh2wq>6MxZvjG6s(|!P=p88$q)NHJct7uZ&hz~^W1K%(d#}AlGUgs@t;{v& zbzQSy`;JNeWCZ@saZAl)P>cDvkoo8aXCCG6a9pGq-N`9-Ane3c(|rG%HVC97p@3|C zLAz0Z2pgs*bqk5GhV_{0HVyjI%qQ99RoEWnTk-i+Rrr zuUa@S{ZL$BuIjBls>` z`DNgk*gW4%QeA1rJuZePz%*Gk~exau0#MdJcDQXd2;{;&{)*rofA?K%6BC0tNdxUxyo5!LSb$z0hx} z#FxcQ8k6O1rKc0!CQL{}b>{C;H+lChQ2}!BXkN%xykFMuAi;U~*HH-c`avgfZvprx z*U5Zm=jRud+ObEXVHud889cem3S~)M=TeE5LK9+oyk(!NEu!_kj8ZKFYg16(GTrUz zSb1^H66>e23v0?=3>w%%NsDz)EDf+fi9^<8FJ5>jIx0s^*h5lHOz)XKxl%&8u7;X& zy*G5C%mVbgxuA@tS$s9W&m|&i`{-V6lopOt-m!hSY%^$s?L)Vb@HfAL6QkdeRSB?v zZu~qeXzSg&TEfpV#J(H2`eHE-P`-z~UgM(Qwum7>D@&bFHFKx@l;`irC-wuUv#Y47 z>E9ttsCLJY&LV|loGrz6Nu>Pg>o71`Bb_$zrKxbFGdw>9QgBGuN|v#A2FOS%Dt=p4 z+N*xO&yb+!b3n3?Jf=SE%y27N{)nt&d@IZ{ZI8f{&7lL)e~g$%{zHb4#5N}Udp@d zlitTQdV4yTjB@U0*;O~q1-Lte6uJzbQLJGT|GA;0z$oJ!wE8nx-!fE{DJ5)kySr;P z)1i=_ul#8lckRfBo035)Du#AT9o}j|c9}ej_kOk1FXy~n9j0E~BY=Ajt#`X71fHu+ z>e6~6ohL$*^Lyr9yhfKBXTSCOI0a@135ZI4snoBflBmmTjXl0zm|xsg(B$cT!?BV0 zorsgx*wOFn0#1;wB8Q!^vVs2X5xRoAK#vk z3v3q08_ z(6?A^+C0y~$^oc_y`aRb{0e^;a~EK7OEqWJA;)sq{)5(1`GYqu_qRn2&R)NG?a^Vu zfjc!cQ+!2PPRX0&k?Gq0rJ(#hU;Z;{ixHL!-a@9^EU$Q)-)!;Ts{&M`onKb(xN*H0 za6lk}ZmRys+W3mn#5c0H^;n~07G8HQi>u+BTh`BB`o0;dce^p4)Ir=+hq(p_9J?tj z^4eNDAJDVTJNq=9gsm?AerIQJy?VmEl5_#+IW?>5X%9eu#IEe5(942^vgh?t<2K8G zzNelp*Zb$c!Q|2X;9YFl+0l9<=Y@;$Sdf<7BntI_;6HG!9if>=K1Wlv(p%R!dAng5 zr`4}k)Rq@?yVW0Y*U5z+4t3@bgmvTe&d#H&xs%^uwH0*f)Y9JV(N=NhB`>=ksHt;d zR(?d0-17{voa zz$SdsO7d{Wl5Hm{*B2w`Cs*@%ASt1-)GEr!uj8A887>@vQs5+Mdj+ecSs1f~P2?$` zj|xg)|Gj!Ea{Dub=4&ZulTAw6 zu%rWuz*;q$tq^wT1Ygwh{ahT!!+tffF?+hIt%YY#8(iHWfj^=w_|=H|%Pj1ayFatC zE|WJg3AkF-^HY!~{U|L_wf;Wv2M%i&puYh3e-x?uFke*M>BI=v&fMxQQgc4qeA!Z; z6X-42Awd({0KB;69qLOGBblMGL&5vZ!#kqUulAd;w%)5V$%W%_%!CP^qbyo0{h&%p zY&k=H(C19*4{>)0(pAfmhtuTL8@3!c!=!fAVo7LA$70gfrR_-Df635VKy(<~(m>PB zhPJ@~Y|h?%E%2LP=x28)POfQ>Z_*z*viLddz*291Tj=Z9IF&V(D~}YE@D8)o+I#$S zBSF=-idB*=RVPyS;DMTmF0(zQ5lkB5#zu!X_FS-w?JFS!RYoDnwO0vg7V*hxeecCX zmsxl=H(yvxn1qamk%kRXzqU(!Gi<0!?=PUVrfb|7uluxt6;d8qFfOrM zfu<)jM%FV(zVG4Wbgnnl2HF*v27LI%wC-={lA~!v_dQg33QSbINU4uV`<^1qQfzN> z=G*S{^emM&^GW*ma<68+U1!l4`B??m5$lGc&Gi_lw#LGl{bzjN(uI{7Q3J<8Q`Yo)3#O@eb zpL~t{CW7U3mh`j1&>D+|7zu&c;QdY!rOTqZ`Jd(Wd3zu(>9POsDqfAdV3k9VX^m@H zn!sTCK4si1s0)6#%nPSFtLTTqx9-Sd8DPd79klRy=#SU|9h%UCa`ENBLuR`8$=h_v z5&Y??FCO|oMyPC6(#UI3cnPqr?f89(Q8x6MGOW4eB&v3oAADpB+QDp0D$lMXH!{v9 z2il5_nNp&?k5&S*DFL-a8!UhY3H6DfM~yLS9iQDT>G~m_tkv~_PYF8uJBMqn-Pk$z z*D#Z*?;G%zmZn1YVglX6Nfn=3WPdPH#!y2|QtNFX(P<1?s}WWqStRB2!N1>PC>~*e zgm6AebNhOhL)Lx$@zsted!0!GbRx91kP5peMWJv!>Z<6eDi)u*35L`z7X|}ll|ZBt z%JUIZ**qcWS9Aj6_Iu-+&As*vH1)(j&0k)g{pA0n8&i(YGYw4*hpU47!Fw<4>s`4- z*6@Lv>{4qrETu|==lne-1a>0i+0V|8_yht7mGk-9&{rDk-Y0p@B%06!iuporT%ADE za#-jI$pmBI5fL2SmwCHO-?ws49b0<(Y!Um@-C6iuWd?Fl%6HC>8 z*+_!5u$U$_j4(pn4W8?Fen2ApT#36FnrvDZh-)4#5RV!zuW!GqW^r3BUPzweb03Kf zy|6Nb?PG?~8}dR0`8z<*Fr8aIbB+ZrISXR4rm6y0D)96tg@&x*bUV7~5(4O@9JK zRQtW0CQuK){h!&r{$k9QQAiXQJdtX> zKQ3G@-}{-vqT%gi$@+X+v|dN4V{s?I)mfnc2fZ^En>hs&`!WuA11@2EfWUb}%BRRB zXXxk(!;n3S)qkxYbB{;38TSWb8 zk~-9@p4CPn;Xm=y5vlR!NcC+}R5Z$do@9;|@wjQ@u(*!DdTt~>(#RaDsN5wY#HgQm znr9~=bP>ELUcz$Vy+`q%({L9nA!y;?+IN*~nS{rAw)~n(WwW(3tDZ4<5W}V1$<9R| ztaL>?SYl<5A3^RVZB1IfNd|-O&Crxf44hQ4FCqe8y^nIU3gKN#)sb5!XF6W!b^3*8 zYG`P#JsDtt2MNx+@5NT?IMIrT4JTSyj7K%WA4W4$CeL*?YFvhg;fv|5_HcNk(PUA$ zZJy^@`0jRDm&mma_s6CpZ?&wA`WD{bLAurt)7v-zjki7PRT6$e>+_7)>i7x&O_@b& zbm8B^1O-ZDjlwDK50KN)H$A#D<`7hD z&+8?wP}R;RXKGU2ch5aBba+M?EiHz)?d1ZtkMYi)Ty@`*oXfcgcnW);e&w#gph;7i zpRyJou z*%;Ztw~Gy{vJ7RD^&@NPaZJ{-hx!5p3Y$>5Q1_P_-j%$uAU|>7gNX;9ggI4o-Eg*E z3}DyILOR1bPg2@Kmg00{PE#r##46G}jpvqsrrl>!Kj()E@zfpl6{&O_Mt19&pLn{H zPZpYP_VcGi1RLo@=&@PVX~zI&zhN%LIuSv@IkktI$d!@ml2qTbdKE+v8yi2^EUR*i zpFi=A70Q&_K!x?VA)a5!HTY3N^ONU=)T`|9L1nm?9=+9|N!lzrj z8I~iIt;@rJbor>(L{r|mQ+e?lB&n~kfci`(2&9N^>B}^4FGyT|*f#jP9O9jME6raZ z+9;XlERk;@>r12ED_<&xj?ui&{IMa0*BQS9gYs!f4F_ zE{{@)7K}ZRUNiI&THGi`*9NDk!N=k-$5uD)oXhu}2Re?dG1I@xxl{!xqf-yr*c|-2 z7Hh@+6ME?gdM;%5J>oOb3^BY~N}Pi^qb0)b5uA)>sw_G8m$wyxnB)oOa^w>zCM&@0 z6<_3{@VG?7Lu-i2kiB`k=bW4=(-iUexXgryRtr$;kz{zb7ezE&HD!{Oi*A!g z>=|diZ`($u4kerSkoK8%uKdQ%PR@nKyxQb!9pe4*%(n5SyKRftc;UA~qrDNv(NW_! z#|vOn#ET;HHimKGsU)gRz+SB6RR!fR`tg02uh9cVkQ=;YUZ&o|OQ|N9orlzQxuBm* zcyr7=i&i>>Jn;OJ?dd?EtJid*Wd=G=-kx2=dB%5SjOlgRu-p8FP!DUYY}(H6e{Ki_ z$LhTLzIejiV^m@_<=vhW$@|CbW&CrA!_r4IG3@ktM)DYe%8N9O&~`q@;^Db8A~i38 z9vfln5bKb0`vv{LWX%wUH1qa7`SGYiV(SkrQ(0=de}CTG-~Ij=qIPVr!PQy(AWIpQos~OCN?RZ4tfLv@w+UH@i6rGFFsyl2%mPj@`1}4 zaj$e+rjt~#b85KEy=W^Z6}m)eJuAy1hzKa_#BQ1sCNgWtpsx>QSRPuo`pF*%Vl z<^)9XgEjGrEqpG}Hi75rqd&gJv-|AnIEHG(OHR&AA|=$5@kSi$uk>5&5|Vyp9p|WN zuM;-2f4ez3I_r})SHL?nS~9H7hmomIA_|!Gr60&Jq1f2CWHhSh#rCgnnrgaOgl#c4 zh7)_ZS=m8-AY=D{3yu=BZ)$48P13C=zD)i=S1-`mz0K(nBxZIksLm~JUb^Js_UuHq z^Mb*yx{Ou_);HB|##vdnb!xu&tzXh8>ZffXDI7$I+CqOk=-|{=0Ly!J2JczmHzQ#a zq)tB<(7s|%l#CsVS^4Y%Ta7eXHg%hkI|=K8GYNgVOn|}`RNpkz%V0RHRMxQb>zLn0 z%?qWP<)o(_6t~w7ZW}r?Nx9O8m)H^IS(H$|9^wA|;G!tpCQ@w98BGH4{MF$O4drz{El8G$QBDEXL)C2DwdNnU>? z6(tmR-^U4?pn3w+5qZf@L+u^&&_KZ}oFT4Q3PS9ytBpFC5@){!!ul9V7BUpo7r7FO z1?M-%%?PVc)gSLdrs$W+vdd=lz4cxXIA?AyhQm>w)o({`(WSxYJ;lUdlTNLCpzF_X z+Q(clT4p-wysBWeM>+@+e1PpT2>6AT~V`RSb!H0dvR(Hptz_^=Pw@$VA z4phtwygUwy3X;&fyr#OJ@O4-|#N-sFn=sSyy6ax~)1S#5ZR--wWJAMGSEpcXSVe`V zhWJkhmVoCh{1$|QHSw>-LJSWgR)pCNqDF~_220)P|s8`qYqnt zcTDy3tnF&v{-Z#CMOUc}RCpA#v^0tn4iC`uyDv}$vKtjdiXp}Hoz8`S<+?Q+`5E