mirror of
https://github.com/explosion/spaCy.git
synced 2024-11-10 19:57:17 +03:00
cython fixes and cleanup
This commit is contained in:
parent
846472129c
commit
96f2e30c4b
|
@ -158,7 +158,6 @@ cdef class PhraseMatcher:
|
||||||
del self._callbacks[key]
|
del self._callbacks[key]
|
||||||
del self._docs[key]
|
del self._docs[key]
|
||||||
|
|
||||||
|
|
||||||
def _add_from_arrays(self, key, specs, *, on_match=None):
|
def _add_from_arrays(self, key, specs, *, on_match=None):
|
||||||
"""Add a preprocessed list of specs, with an optional callback.
|
"""Add a preprocessed list of specs, with an optional callback.
|
||||||
|
|
||||||
|
@ -194,7 +193,6 @@ cdef class PhraseMatcher:
|
||||||
result = internal_node
|
result = internal_node
|
||||||
map_set(self.mem, <MapStruct*>result, self.vocab.strings[key], NULL)
|
map_set(self.mem, <MapStruct*>result, self.vocab.strings[key], NULL)
|
||||||
|
|
||||||
|
|
||||||
def add(self, key, docs, *, on_match=None):
|
def add(self, key, docs, *, on_match=None):
|
||||||
"""Add a match-rule to the phrase-matcher. A match-rule consists of: an ID
|
"""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, a list of one or more patterns, and (optionally) an on_match callback.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# cython: infer_types=True, cdivision=True, boundscheck=False
|
# cython: infer_types=True, cdivision=True, boundscheck=False
|
||||||
from typing import Any, List, Optional, Tuple, TypeVar, cast
|
from typing import Any, List, Optional, Tuple, cast
|
||||||
|
|
||||||
from libc.stdlib cimport calloc, free, realloc
|
from libc.stdlib cimport calloc, free, realloc
|
||||||
from libc.string cimport memcpy, memset
|
from libc.string cimport memcpy, memset
|
||||||
|
@ -23,7 +23,7 @@ from thinc.api import (
|
||||||
|
|
||||||
from thinc.backends.cblas cimport CBlas, saxpy, sgemm
|
from thinc.backends.cblas cimport CBlas, saxpy, sgemm
|
||||||
|
|
||||||
from thinc.types import Floats1d, Floats2d, Floats3d, Floats4d, Ints1d, Ints2d
|
from thinc.types import Floats2d, Floats3d, Floats4d, Ints1d, Ints2d
|
||||||
|
|
||||||
from ..errors import Errors
|
from ..errors import Errors
|
||||||
from ..pipeline._parser_internals import _beam_utils
|
from ..pipeline._parser_internals import _beam_utils
|
||||||
|
@ -136,7 +136,7 @@ def init(
|
||||||
Y: Optional[Tuple[List[State], List[Floats2d]]] = None,
|
Y: Optional[Tuple[List[State], List[Floats2d]]] = None,
|
||||||
):
|
):
|
||||||
if X is not None:
|
if X is not None:
|
||||||
docs, moves = X
|
docs, _ = X
|
||||||
model.get_ref("tok2vec").initialize(X=docs)
|
model.get_ref("tok2vec").initialize(X=docs)
|
||||||
else:
|
else:
|
||||||
model.get_ref("tok2vec").initialize()
|
model.get_ref("tok2vec").initialize()
|
||||||
|
@ -145,7 +145,7 @@ def init(
|
||||||
current_nO = model.maybe_get_dim("nO")
|
current_nO = model.maybe_get_dim("nO")
|
||||||
if current_nO is None or current_nO != inferred_nO:
|
if current_nO is None or current_nO != inferred_nO:
|
||||||
model.attrs["resize_output"](model, inferred_nO)
|
model.attrs["resize_output"](model, inferred_nO)
|
||||||
nO = model.get_dim("nO")
|
# nO = model.get_dim("nO")
|
||||||
nP = model.get_dim("nP")
|
nP = model.get_dim("nP")
|
||||||
nH = model.get_dim("nH")
|
nH = model.get_dim("nH")
|
||||||
nI = model.get_dim("nI")
|
nI = model.get_dim("nI")
|
||||||
|
@ -192,9 +192,10 @@ class TransitionModelInputs:
|
||||||
self,
|
self,
|
||||||
docs: List[Doc],
|
docs: List[Doc],
|
||||||
moves: TransitionSystem,
|
moves: TransitionSystem,
|
||||||
actions: Optional[List[Ints1d]]=None,
|
actions: Optional[List[Ints1d]] = None,
|
||||||
max_moves: int=0,
|
max_moves: int = 0,
|
||||||
states: Optional[List[State]]=None):
|
states: Optional[List[State]] = None,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
actions (Optional[List[Ints1d]]): actions to apply for each Doc.
|
actions (Optional[List[Ints1d]]): actions to apply for each Doc.
|
||||||
docs (List[Doc]): Docs to predict transition sequences for.
|
docs (List[Doc]): Docs to predict transition sequences for.
|
||||||
|
@ -234,12 +235,12 @@ def forward(model, inputs: TransitionModelInputs, is_train: bool):
|
||||||
return _forward_greedy_cpu(model, moves, states, feats, seen_mask, actions=actions)
|
return _forward_greedy_cpu(model, moves, states, feats, seen_mask, actions=actions)
|
||||||
else:
|
else:
|
||||||
return _forward_fallback(model, moves, states, tokvecs, backprop_tok2vec,
|
return _forward_fallback(model, moves, states, tokvecs, backprop_tok2vec,
|
||||||
feats, backprop_feats, seen_mask, is_train, actions=actions,
|
feats, backprop_feats, seen_mask, is_train, actions=actions,
|
||||||
max_moves=inputs.max_moves)
|
max_moves=inputs.max_moves)
|
||||||
|
|
||||||
|
|
||||||
def _forward_greedy_cpu(model: Model, TransitionSystem moves, states: List[StateClass], np.ndarray feats,
|
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):
|
np.ndarray[np.npy_bool, ndim = 1] seen_mask, actions: Optional[List[Ints1d]] = None):
|
||||||
cdef vector[StateC*] c_states
|
cdef vector[StateC*] c_states
|
||||||
cdef StateClass state
|
cdef StateClass state
|
||||||
for state in states:
|
for state in states:
|
||||||
|
@ -257,9 +258,10 @@ def _forward_greedy_cpu(model: Model, TransitionSystem moves, states: List[State
|
||||||
|
|
||||||
return (states, scores), backprop
|
return (states, scores), backprop
|
||||||
|
|
||||||
|
|
||||||
cdef list _parse_batch(CBlas cblas, TransitionSystem moves, StateC** states,
|
cdef list _parse_batch(CBlas cblas, TransitionSystem moves, StateC** states,
|
||||||
WeightsC weights, SizesC sizes, actions: Optional[List[Ints1d]]=None):
|
WeightsC weights, SizesC sizes, actions: Optional[List[Ints1d]]=None):
|
||||||
cdef int i, j
|
cdef int i
|
||||||
cdef vector[StateC *] unfinished
|
cdef vector[StateC *] unfinished
|
||||||
cdef ActivationsC activations = _alloc_activations(sizes)
|
cdef ActivationsC activations = _alloc_activations(sizes)
|
||||||
cdef np.ndarray step_scores
|
cdef np.ndarray step_scores
|
||||||
|
@ -276,7 +278,7 @@ cdef list _parse_batch(CBlas cblas, TransitionSystem moves, StateC** states,
|
||||||
if actions is None:
|
if actions is None:
|
||||||
# Validate actions, argmax, take action.
|
# Validate actions, argmax, take action.
|
||||||
c_transition_batch(moves, states, <const float*>step_scores.data, sizes.classes,
|
c_transition_batch(moves, states, <const float*>step_scores.data, sizes.classes,
|
||||||
sizes.states)
|
sizes.states)
|
||||||
else:
|
else:
|
||||||
c_apply_actions(moves, states, <const int*>step_actions.data, sizes.states)
|
c_apply_actions(moves, states, <const int*>step_actions.data, sizes.states)
|
||||||
for i in range(sizes.states):
|
for i in range(sizes.states):
|
||||||
|
@ -302,8 +304,8 @@ def _forward_fallback(
|
||||||
backprop_feats,
|
backprop_feats,
|
||||||
seen_mask,
|
seen_mask,
|
||||||
is_train: bool,
|
is_train: bool,
|
||||||
actions: Optional[List[Ints1d]]=None,
|
actions: Optional[List[Ints1d]] = None,
|
||||||
max_moves: int=0):
|
max_moves: int = 0):
|
||||||
nF = model.get_dim("nF")
|
nF = model.get_dim("nF")
|
||||||
output = model.get_ref("output")
|
output = model.get_ref("output")
|
||||||
hidden_b = model.get_param("hidden_b")
|
hidden_b = model.get_param("hidden_b")
|
||||||
|
@ -371,7 +373,7 @@ def _forward_fallback(
|
||||||
for clas in set(model.attrs["unseen_classes"]):
|
for clas in set(model.attrs["unseen_classes"]):
|
||||||
if (d_scores[:, clas] < 0).any():
|
if (d_scores[:, clas] < 0).any():
|
||||||
model.attrs["unseen_classes"].remove(clas)
|
model.attrs["unseen_classes"].remove(clas)
|
||||||
d_scores *= seen_mask == False
|
d_scores *= seen_mask == False # no-cython-lint
|
||||||
# Calculate the gradients for the parameters of the output layer.
|
# Calculate the gradients for the parameters of the output layer.
|
||||||
# The weight gemm is (nS, nO) @ (nS, nH).T
|
# The weight gemm is (nS, nO) @ (nS, nH).T
|
||||||
output.inc_grad("b", d_scores.sum(axis=0))
|
output.inc_grad("b", d_scores.sum(axis=0))
|
||||||
|
@ -571,13 +573,13 @@ cdef void _resize_activations(ActivationsC* A, SizesC n) nogil:
|
||||||
A._max_size = n.states
|
A._max_size = n.states
|
||||||
else:
|
else:
|
||||||
A.token_ids = <int*>realloc(A.token_ids,
|
A.token_ids = <int*>realloc(A.token_ids,
|
||||||
n.states * n.feats * sizeof(A.token_ids[0]))
|
n.states * n.feats * sizeof(A.token_ids[0]))
|
||||||
A.unmaxed = <float*>realloc(A.unmaxed,
|
A.unmaxed = <float*>realloc(A.unmaxed,
|
||||||
n.states * n.hiddens * n.pieces * sizeof(A.unmaxed[0]))
|
n.states * n.hiddens * n.pieces * sizeof(A.unmaxed[0]))
|
||||||
A.hiddens = <float*>realloc(A.hiddens,
|
A.hiddens = <float*>realloc(A.hiddens,
|
||||||
n.states * n.hiddens * sizeof(A.hiddens[0]))
|
n.states * n.hiddens * sizeof(A.hiddens[0]))
|
||||||
A.is_valid = <int*>realloc(A.is_valid,
|
A.is_valid = <int*>realloc(A.is_valid,
|
||||||
n.states * n.classes * sizeof(A.is_valid[0]))
|
n.states * n.classes * sizeof(A.is_valid[0]))
|
||||||
A._max_size = n.states
|
A._max_size = n.states
|
||||||
A._curr_size = n.states
|
A._curr_size = n.states
|
||||||
|
|
||||||
|
@ -599,9 +601,9 @@ cdef void _predict_states(CBlas cblas, ActivationsC* A, float* scores, StateC**
|
||||||
else:
|
else:
|
||||||
# Compute hidden-to-output
|
# Compute hidden-to-output
|
||||||
sgemm(cblas)(False, True, n.states, n.classes, n.hiddens,
|
sgemm(cblas)(False, True, n.states, n.classes, n.hiddens,
|
||||||
1.0, <const float *>A.hiddens, n.hiddens,
|
1.0, <const float *>A.hiddens, n.hiddens,
|
||||||
<const float *>W.hidden_weights, n.hiddens,
|
<const float *>W.hidden_weights, n.hiddens,
|
||||||
0.0, scores, n.classes)
|
0.0, scores, n.classes)
|
||||||
# Add bias
|
# Add bias
|
||||||
for i in range(n.states):
|
for i in range(n.states):
|
||||||
saxpy(cblas)(n.classes, 1., W.hidden_bias, 1, &scores[i*n.classes], 1)
|
saxpy(cblas)(n.classes, 1., W.hidden_bias, 1, &scores[i*n.classes], 1)
|
||||||
|
@ -617,12 +619,12 @@ cdef void _predict_states(CBlas cblas, ActivationsC* A, float* scores, StateC**
|
||||||
scores[i*n.classes+j] = min_
|
scores[i*n.classes+j] = min_
|
||||||
|
|
||||||
|
|
||||||
cdef void _sum_state_features(CBlas cblas, float* output,
|
cdef void _sum_state_features(CBlas cblas, float* output, const float* cached,
|
||||||
const float* cached, const int* token_ids, SizesC n) nogil:
|
const int* token_ids, SizesC n) nogil:
|
||||||
cdef int idx, b, f, i
|
cdef int idx, b, f
|
||||||
cdef const float* feature
|
cdef const float* feature
|
||||||
cdef int B = n.states
|
cdef int B = n.states
|
||||||
cdef int O = n.hiddens * n.pieces
|
cdef int O = n.hiddens * n.pieces # no-cython-lint
|
||||||
cdef int F = n.feats
|
cdef int F = n.feats
|
||||||
cdef int T = n.tokens
|
cdef int T = n.tokens
|
||||||
padding = cached + (T * F * O)
|
padding = cached + (T * F * O)
|
||||||
|
@ -637,4 +639,3 @@ cdef void _sum_state_features(CBlas cblas, float* output,
|
||||||
feature = &cached[idx]
|
feature = &cached[idx]
|
||||||
saxpy(cblas)(O, one, <const float*>feature, 1, &output[b*O], 1)
|
saxpy(cblas)(O, one, <const float*>feature, 1, &output[b*O], 1)
|
||||||
token_ids += F
|
token_ids += F
|
||||||
|
|
||||||
|
|
|
@ -80,15 +80,13 @@ cdef class Morphology:
|
||||||
out.sort(key=lambda x: x[0])
|
out.sort(key=lambda x: x[0])
|
||||||
return dict(out)
|
return dict(out)
|
||||||
|
|
||||||
|
|
||||||
def _normalized_feat_dict_to_str(self, feats: Dict[str, str]) -> str:
|
def _normalized_feat_dict_to_str(self, feats: Dict[str, str]) -> str:
|
||||||
norm_feats_string = self.FEATURE_SEP.join([
|
norm_feats_string = self.FEATURE_SEP.join([
|
||||||
self.FIELD_SEP.join([field, self.VALUE_SEP.join(values) if isinstance(values, list) else values])
|
self.FIELD_SEP.join([field, self.VALUE_SEP.join(values) if isinstance(values, list) else values])
|
||||||
for field, values in feats.items()
|
for field, values in feats.items()
|
||||||
])
|
])
|
||||||
return norm_feats_string or self.EMPTY_MORPH
|
return norm_feats_string or self.EMPTY_MORPH
|
||||||
|
|
||||||
|
|
||||||
cdef hash_t _add(self, features):
|
cdef hash_t _add(self, features):
|
||||||
"""Insert a morphological analysis in the morphology table, if not
|
"""Insert a morphological analysis in the morphology table, if not
|
||||||
already present. The morphological analysis may be provided in the UD
|
already present. The morphological analysis may be provided in the UD
|
||||||
|
|
|
@ -8,7 +8,7 @@ cpdef enum univ_pos_t:
|
||||||
ADV = symbols.ADV
|
ADV = symbols.ADV
|
||||||
AUX = symbols.AUX
|
AUX = symbols.AUX
|
||||||
CONJ = symbols.CONJ
|
CONJ = symbols.CONJ
|
||||||
CCONJ = symbols.CCONJ # U20
|
CCONJ = symbols.CCONJ # U20
|
||||||
DET = symbols.DET
|
DET = symbols.DET
|
||||||
INTJ = symbols.INTJ
|
INTJ = symbols.INTJ
|
||||||
NOUN = symbols.NOUN
|
NOUN = symbols.NOUN
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from cymem.cymem cimport Pool
|
from cymem.cymem cimport Pool
|
||||||
from libc.stdint cimport int32_t
|
|
||||||
from libcpp.memory cimport shared_ptr
|
from libcpp.memory cimport shared_ptr
|
||||||
from libcpp.vector cimport vector
|
from libcpp.vector cimport vector
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,6 @@ cdef class Beam:
|
||||||
cdef int advance(self, trans_func_t transition_func, hash_func_t hash_func,
|
cdef int advance(self, trans_func_t transition_func, hash_func_t hash_func,
|
||||||
void* extra_args) except -1
|
void* extra_args) except -1
|
||||||
cdef int check_done(self, finish_func_t finish_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:
|
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.scores[i][j] = score
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
# cython: profile=True, experimental_cpp_class_def=True, cdivision=True, infer_types=True
|
# cython: profile=True, experimental_cpp_class_def=True, cdivision=True, infer_types=True
|
||||||
cimport cython
|
cimport cython
|
||||||
from libc.math cimport exp, log
|
|
||||||
from libc.string cimport memcpy, memset
|
|
||||||
|
|
||||||
import math
|
|
||||||
|
|
||||||
from cymem.cymem cimport Pool
|
from cymem.cymem cimport Pool
|
||||||
|
from libc.math cimport exp
|
||||||
|
from libc.string cimport memcpy, memset
|
||||||
from preshed.maps cimport PreshMap
|
from preshed.maps cimport PreshMap
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,7 +67,7 @@ cdef class Beam:
|
||||||
self.costs[i][j] = costs[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 set_table(self, weight_t** scores, int** is_valid, weight_t** costs) except -1:
|
||||||
cdef int i, j
|
cdef int i
|
||||||
for i in range(self.width):
|
for i in range(self.width):
|
||||||
memcpy(self.scores[i], scores[i], sizeof(weight_t) * self.nr_class)
|
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.is_valid[i], is_valid[i], sizeof(bint) * self.nr_class)
|
||||||
|
@ -176,7 +173,6 @@ cdef class Beam:
|
||||||
beam-width, and n is the number of classes.
|
beam-width, and n is the number of classes.
|
||||||
"""
|
"""
|
||||||
cdef Entry entry
|
cdef Entry entry
|
||||||
cdef weight_t score
|
|
||||||
cdef _State* s
|
cdef _State* s
|
||||||
cdef int i, j, move_id
|
cdef int i, j, move_id
|
||||||
assert self.size >= 1
|
assert self.size >= 1
|
||||||
|
@ -269,7 +265,7 @@ cdef class MaxViolation:
|
||||||
# This can happen from non-monotonic actions
|
# This can happen from non-monotonic actions
|
||||||
# If we find a better gold analysis this way, be sure to keep it.
|
# If we find a better gold analysis this way, be sure to keep it.
|
||||||
elif pred._states[i].loss <= 0 \
|
elif pred._states[i].loss <= 0 \
|
||||||
and tuple(pred.histories[i]) not in seen_golds:
|
and tuple(pred.histories[i]) not in seen_golds:
|
||||||
g_scores.append(pred._states[i].score)
|
g_scores.append(pred._states[i].score)
|
||||||
g_hist.append(list(pred.histories[i]))
|
g_hist.append(list(pred.histories[i]))
|
||||||
for i in range(gold.size):
|
for i in range(gold.size):
|
||||||
|
|
|
@ -60,7 +60,7 @@ cdef class TransitionSystem:
|
||||||
|
|
||||||
|
|
||||||
cdef void c_apply_actions(TransitionSystem moves, StateC** states, const int* actions,
|
cdef void c_apply_actions(TransitionSystem moves, StateC** states, const int* actions,
|
||||||
int batch_size) nogil
|
int batch_size) nogil
|
||||||
|
|
||||||
cdef void c_transition_batch(TransitionSystem moves, StateC** states, const float* scores,
|
cdef void c_transition_batch(TransitionSystem moves, StateC** states, const float* scores,
|
||||||
int nr_class, int batch_size) nogil
|
int nr_class, int batch_size) nogil
|
||||||
|
|
|
@ -291,19 +291,19 @@ cdef class TransitionSystem:
|
||||||
|
|
||||||
|
|
||||||
cdef void c_apply_actions(TransitionSystem moves, StateC** states, const int* actions,
|
cdef void c_apply_actions(TransitionSystem moves, StateC** states, const int* actions,
|
||||||
int batch_size) nogil:
|
int batch_size) nogil:
|
||||||
cdef int i
|
cdef int i
|
||||||
cdef Transition action
|
cdef Transition action
|
||||||
cdef StateC* state
|
cdef StateC* state
|
||||||
for i in range(batch_size):
|
for i in range(batch_size):
|
||||||
state = states[i]
|
state = states[i]
|
||||||
action = moves.c[actions[i]]
|
action = moves.c[actions[i]]
|
||||||
action.do(state, action.label)
|
action.do(state, action.label)
|
||||||
state.history.push_back(action.clas)
|
state.history.push_back(action.clas)
|
||||||
|
|
||||||
|
|
||||||
cdef void c_transition_batch(TransitionSystem moves, StateC** states, const float* scores,
|
cdef void c_transition_batch(TransitionSystem moves, StateC** states, const float* scores,
|
||||||
int nr_class, int batch_size) nogil:
|
int nr_class, int batch_size) nogil:
|
||||||
is_valid = <int*>calloc(moves.n_moves, sizeof(int))
|
is_valid = <int*>calloc(moves.n_moves, sizeof(int))
|
||||||
cdef int i, guess
|
cdef int i, guess
|
||||||
cdef Transition action
|
cdef Transition action
|
||||||
|
@ -319,4 +319,3 @@ cdef void c_transition_batch(TransitionSystem moves, StateC** states, const floa
|
||||||
action.do(states[i], action.label)
|
action.do(states[i], action.label)
|
||||||
states[i].history.push_back(guess)
|
states[i].history.push_back(guess)
|
||||||
free(is_valid)
|
free(is_valid)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# cython: infer_types=True, profile=True, binding=True
|
# cython: infer_types=True, profile=True, binding=True
|
||||||
from itertools import islice
|
from itertools import islice
|
||||||
from typing import Callable, Dict, Iterable, List, Optional, Union
|
from typing import Callable, Dict, Iterable, Optional, Union
|
||||||
|
|
||||||
import srsly
|
|
||||||
from thinc.api import Config, Model
|
from thinc.api import Config, Model
|
||||||
from thinc.legacy import LegacySequenceCategoricalCrossentropy
|
from thinc.legacy import LegacySequenceCategoricalCrossentropy
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
# cython: infer_types=True, profile=True, binding=True
|
# cython: infer_types=True, profile=True, binding=True
|
||||||
import warnings
|
|
||||||
from typing import Callable, Dict, Iterable, Iterator, Tuple, Union
|
from typing import Callable, Dict, Iterable, Iterator, Tuple, Union
|
||||||
|
|
||||||
import srsly
|
import srsly
|
||||||
|
|
||||||
from ..tokens.doc cimport Doc
|
from ..tokens.doc cimport Doc
|
||||||
|
|
||||||
from ..errors import Errors, Warnings
|
from ..errors import Errors
|
||||||
from ..language import Language
|
from ..language import Language
|
||||||
from ..training import Example
|
from ..training import Example
|
||||||
from ..util import raise_error
|
from ..util import raise_error
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# cython: infer_types=True, profile=True, binding=True
|
# cython: infer_types=True, profile=True, binding=True
|
||||||
import warnings
|
|
||||||
from typing import Callable, Dict, Iterable, Iterator, Optional, Tuple
|
from typing import Callable, Dict, Iterable, Iterator, Optional, Tuple
|
||||||
|
|
||||||
import srsly
|
import srsly
|
||||||
|
@ -8,7 +7,7 @@ from thinc.api import Model, Optimizer, set_dropout_rate
|
||||||
from ..tokens.doc cimport Doc
|
from ..tokens.doc cimport Doc
|
||||||
|
|
||||||
from .. import util
|
from .. import util
|
||||||
from ..errors import Errors, Warnings
|
from ..errors import Errors
|
||||||
from ..language import Language
|
from ..language import Language
|
||||||
from ..training import Example, validate_distillation_examples, validate_examples
|
from ..training import Example, validate_distillation_examples, validate_examples
|
||||||
from ..vocab import Vocab
|
from ..vocab import Vocab
|
||||||
|
@ -56,14 +55,14 @@ cdef class TrainablePipe(Pipe):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_handler(self.name, self, [doc], e)
|
error_handler(self.name, self, [doc], e)
|
||||||
|
|
||||||
|
|
||||||
def distill(self,
|
def distill(self,
|
||||||
teacher_pipe: Optional["TrainablePipe"],
|
teacher_pipe: Optional["TrainablePipe"],
|
||||||
examples: Iterable["Example"],
|
examples: Iterable["Example"],
|
||||||
*,
|
*,
|
||||||
drop: float=0.0,
|
drop: float = 0.0,
|
||||||
sgd: Optional[Optimizer]=None,
|
sgd: Optional[Optimizer] = None,
|
||||||
losses: Optional[Dict[str, float]]=None) -> Dict[str, float]:
|
losses: Optional[Dict[str, float]] = None
|
||||||
|
) -> Dict[str, float]:
|
||||||
"""Train a pipe (the student) on the predictions of another pipe
|
"""Train a pipe (the student) on the predictions of another pipe
|
||||||
(the teacher). The student is typically trained on the probability
|
(the teacher). The student is typically trained on the probability
|
||||||
distribution of the teacher, but details may differ per pipe.
|
distribution of the teacher, but details may differ per pipe.
|
||||||
|
|
|
@ -222,12 +222,13 @@ class Parser(TrainablePipe):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def distill(self,
|
def distill(self,
|
||||||
teacher_pipe: Optional[TrainablePipe],
|
teacher_pipe: Optional[TrainablePipe],
|
||||||
examples: Iterable["Example"],
|
examples: Iterable["Example"],
|
||||||
*,
|
*,
|
||||||
drop: float=0.0,
|
drop: float = 0.0,
|
||||||
sgd: Optional[Optimizer]=None,
|
sgd: Optional[Optimizer] = None,
|
||||||
losses: Optional[Dict[str, float]]=None):
|
losses: Optional[Dict[str, float]] = None
|
||||||
|
):
|
||||||
"""Train a pipe (the student) on the predictions of another pipe
|
"""Train a pipe (the student) on the predictions of another pipe
|
||||||
(the teacher). The student is trained on the transition probabilities
|
(the teacher). The student is trained on the transition probabilities
|
||||||
of the teacher.
|
of the teacher.
|
||||||
|
@ -277,11 +278,13 @@ class Parser(TrainablePipe):
|
||||||
# teacher's distributions.
|
# teacher's distributions.
|
||||||
|
|
||||||
student_inputs = TransitionModelInputs(docs=student_docs,
|
student_inputs = TransitionModelInputs(docs=student_docs,
|
||||||
states=[state.copy() for state in states], moves=self.moves, max_moves=max_moves)
|
states=[state.copy() for state in states],
|
||||||
|
moves=self.moves,
|
||||||
|
max_moves=max_moves)
|
||||||
(student_states, student_scores), backprop_scores = self.model.begin_update(student_inputs)
|
(student_states, student_scores), backprop_scores = self.model.begin_update(student_inputs)
|
||||||
actions = _states_diff_to_actions(states, student_states)
|
actions = _states_diff_to_actions(states, student_states)
|
||||||
teacher_inputs = TransitionModelInputs(docs=[eg.reference for eg in examples],
|
teacher_inputs = TransitionModelInputs(docs=[eg.reference for eg in examples],
|
||||||
states=states, moves=teacher_pipe.moves, actions=actions)
|
states=states, moves=teacher_pipe.moves, actions=actions)
|
||||||
(_, teacher_scores) = teacher_pipe.model.predict(teacher_inputs)
|
(_, teacher_scores) = teacher_pipe.model.predict(teacher_inputs)
|
||||||
|
|
||||||
loss, d_scores = self.get_teacher_student_loss(teacher_scores, student_scores)
|
loss, d_scores = self.get_teacher_student_loss(teacher_scores, student_scores)
|
||||||
|
@ -294,10 +297,9 @@ class Parser(TrainablePipe):
|
||||||
|
|
||||||
return losses
|
return losses
|
||||||
|
|
||||||
|
|
||||||
def get_teacher_student_loss(
|
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,
|
normalize: bool = False,
|
||||||
) -> Tuple[float, List[Floats2d]]:
|
) -> Tuple[float, List[Floats2d]]:
|
||||||
"""Calculate the loss and its gradient for a batch of student
|
"""Calculate the loss and its gradient for a batch of student
|
||||||
scores, relative to teacher scores.
|
scores, relative to teacher scores.
|
||||||
|
@ -320,9 +322,9 @@ class Parser(TrainablePipe):
|
||||||
# ourselves.
|
# ourselves.
|
||||||
|
|
||||||
teacher_scores = self.model.ops.softmax(self.model.ops.xp.vstack(teacher_scores),
|
teacher_scores = self.model.ops.softmax(self.model.ops.xp.vstack(teacher_scores),
|
||||||
axis=-1, inplace=True)
|
axis=-1, inplace=True)
|
||||||
student_scores = self.model.ops.softmax(self.model.ops.xp.vstack(student_scores),
|
student_scores = self.model.ops.softmax(self.model.ops.xp.vstack(student_scores),
|
||||||
axis=-1, inplace=True)
|
axis=-1, inplace=True)
|
||||||
|
|
||||||
assert teacher_scores.shape == student_scores.shape
|
assert teacher_scores.shape == student_scores.shape
|
||||||
|
|
||||||
|
@ -436,13 +438,15 @@ class Parser(TrainablePipe):
|
||||||
else:
|
else:
|
||||||
init_states, gold_states, _ = self.moves.init_gold_batch(examples)
|
init_states, gold_states, _ = self.moves.init_gold_batch(examples)
|
||||||
|
|
||||||
inputs = TransitionModelInputs(docs=docs, moves=self.moves,
|
inputs = TransitionModelInputs(docs=docs,
|
||||||
max_moves=max_moves, states=[state.copy() for state in init_states])
|
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)
|
(pred_states, scores), backprop_scores = self.model.begin_update(inputs)
|
||||||
if sum(s.shape[0] for s in scores) == 0:
|
if sum(s.shape[0] for s in scores) == 0:
|
||||||
return losses
|
return losses
|
||||||
d_scores = self.get_loss((gold_states, init_states, pred_states, scores),
|
d_scores = self.get_loss((gold_states, init_states, pred_states, scores),
|
||||||
examples, max_moves)
|
examples, max_moves)
|
||||||
backprop_scores((pred_states, d_scores))
|
backprop_scores((pred_states, d_scores))
|
||||||
if sgd not in (None, False):
|
if sgd not in (None, False):
|
||||||
self.finish_update(sgd)
|
self.finish_update(sgd)
|
||||||
|
@ -483,9 +487,7 @@ class Parser(TrainablePipe):
|
||||||
cdef TransitionSystem moves = self.moves
|
cdef TransitionSystem moves = self.moves
|
||||||
cdef StateClass state
|
cdef StateClass state
|
||||||
cdef int clas
|
cdef int clas
|
||||||
cdef int nF = self.model.get_dim("nF")
|
|
||||||
cdef int nO = moves.n_moves
|
cdef int nO = moves.n_moves
|
||||||
cdef int nS = sum([len(history) for history in histories])
|
|
||||||
cdef Pool mem = Pool()
|
cdef Pool mem = Pool()
|
||||||
cdef np.ndarray costs_i
|
cdef np.ndarray costs_i
|
||||||
is_valid = <int*>mem.alloc(nO, sizeof(int))
|
is_valid = <int*>mem.alloc(nO, sizeof(int))
|
||||||
|
@ -552,8 +554,8 @@ class Parser(TrainablePipe):
|
||||||
|
|
||||||
return losses
|
return losses
|
||||||
|
|
||||||
def update_beam(self, examples, *, beam_width,
|
def update_beam(self, examples, *, beam_width, drop=0.,
|
||||||
drop=0., sgd=None, losses=None, beam_density=0.0):
|
sgd=None, losses=None, beam_density=0.0):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def set_output(self, nO):
|
def set_output(self, nO):
|
||||||
|
@ -678,9 +680,10 @@ class Parser(TrainablePipe):
|
||||||
return states
|
return states
|
||||||
|
|
||||||
# Parse the states that are too long with the teacher's parsing model.
|
# Parse the states that are too long with the teacher's parsing model.
|
||||||
teacher_inputs = TransitionModelInputs(docs=docs, moves=moves,
|
teacher_inputs = TransitionModelInputs(docs=docs,
|
||||||
states=[state.copy() for state in to_cut])
|
moves=moves,
|
||||||
(teacher_states, _ ) = teacher_pipe.model.predict(teacher_inputs)
|
states=[state.copy() for state in to_cut])
|
||||||
|
(teacher_states, _) = teacher_pipe.model.predict(teacher_inputs)
|
||||||
|
|
||||||
# Step through the teacher's actions and store every state after
|
# Step through the teacher's actions and store every state after
|
||||||
# each multiple of max_length.
|
# each multiple of max_length.
|
||||||
|
@ -778,6 +781,7 @@ def _states_to_actions(states: List[StateClass]) -> List[Ints1d]:
|
||||||
|
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
|
||||||
def _states_diff_to_actions(
|
def _states_diff_to_actions(
|
||||||
before_states: List[StateClass],
|
before_states: List[StateClass],
|
||||||
after_states: List[StateClass]
|
after_states: List[StateClass]
|
||||||
|
@ -798,8 +802,9 @@ def _states_diff_to_actions(
|
||||||
c_state_before = before_state.c
|
c_state_before = before_state.c
|
||||||
c_state_after = after_state.c
|
c_state_after = after_state.c
|
||||||
|
|
||||||
assert equal(c_state_before.history.begin(), c_state_before.history.end(),
|
assert equal(c_state_before.history.begin(),
|
||||||
c_state_after.history.begin())
|
c_state_before.history.end(),
|
||||||
|
c_state_after.history.begin())
|
||||||
|
|
||||||
actions = []
|
actions = []
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# cython: infer_types=True
|
# cython: infer_types=True
|
||||||
from typing import Any, Callable, Iterable, Iterator, List, Optional, Tuple, Union
|
from typing import Iterable, Iterator, List, Optional, Tuple, Union
|
||||||
|
|
||||||
cimport cython
|
|
||||||
from libc.stdint cimport uint32_t
|
from libc.stdint cimport uint32_t
|
||||||
from libc.string cimport memcpy
|
from libc.string cimport memcpy
|
||||||
from murmurhash.mrmr cimport hash64
|
from murmurhash.mrmr cimport hash64
|
||||||
|
@ -243,7 +242,6 @@ cdef class StringStore:
|
||||||
cdef int n_length_bytes
|
cdef int n_length_bytes
|
||||||
cdef int i
|
cdef int i
|
||||||
cdef Utf8Str* string = <Utf8Str*>self.mem.alloc(1, sizeof(Utf8Str))
|
cdef Utf8Str* string = <Utf8Str*>self.mem.alloc(1, sizeof(Utf8Str))
|
||||||
cdef uint32_t ulength = length
|
|
||||||
if length < sizeof(string.s):
|
if length < sizeof(string.s):
|
||||||
string.s[0] = <unsigned char>length
|
string.s[0] = <unsigned char>length
|
||||||
memcpy(&string.s[1], chars, length)
|
memcpy(&string.s[1], chars, length)
|
||||||
|
@ -301,7 +299,7 @@ cpdef hash_t get_string_id(object string_or_hash) except -1:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return hash_string(string_or_hash)
|
return hash_string(string_or_hash)
|
||||||
except:
|
except: # no-cython-lint
|
||||||
if _try_coerce_to_hash(string_or_hash, &str_hash):
|
if _try_coerce_to_hash(string_or_hash, &str_hash):
|
||||||
# Coerce the integral key to the expected primitive hash type.
|
# Coerce the integral key to the expected primitive hash type.
|
||||||
# This ensures that custom/overloaded "primitive" data types
|
# This ensures that custom/overloaded "primitive" data types
|
||||||
|
@ -318,6 +316,5 @@ cdef inline bint _try_coerce_to_hash(object key, hash_t* out_hash):
|
||||||
try:
|
try:
|
||||||
out_hash[0] = key
|
out_hash[0] = key
|
||||||
return True
|
return True
|
||||||
except:
|
except: # no-cython-lint
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from cymem.cymem cimport Pool
|
from cymem.cymem cimport Pool
|
||||||
|
|
||||||
from spacy.pipeline._parser_internals.search cimport Beam, MaxViolation
|
from spacy.pipeline._parser_internals.search cimport Beam, MaxViolation
|
||||||
from spacy.typedefs cimport class_t, weight_t
|
from spacy.typedefs cimport class_t
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -42,32 +42,35 @@ cdef int destroy(Pool mem, void* state, void* extra_args) except -1:
|
||||||
state = <TestState*>state
|
state = <TestState*>state
|
||||||
mem.free(state)
|
mem.free(state)
|
||||||
|
|
||||||
|
|
||||||
@cytest
|
@cytest
|
||||||
@pytest.mark.parametrize("nr_class,beam_width",
|
@pytest.mark.parametrize("nr_class,beam_width",
|
||||||
[
|
[
|
||||||
(2, 3),
|
(2, 3),
|
||||||
(3, 6),
|
(3, 6),
|
||||||
(4, 20),
|
(4, 20),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_init(nr_class, beam_width):
|
def test_init(nr_class, beam_width):
|
||||||
b = Beam(nr_class, beam_width)
|
b = Beam(nr_class, beam_width)
|
||||||
assert b.size == 1
|
assert b.size == 1
|
||||||
assert b.width == beam_width
|
assert b.width == beam_width
|
||||||
assert b.nr_class == nr_class
|
assert b.nr_class == nr_class
|
||||||
|
|
||||||
|
|
||||||
@cytest
|
@cytest
|
||||||
def test_init_violn():
|
def test_init_violn():
|
||||||
MaxViolation()
|
MaxViolation()
|
||||||
|
|
||||||
|
|
||||||
@cytest
|
@cytest
|
||||||
@pytest.mark.parametrize("nr_class,beam_width,length",
|
@pytest.mark.parametrize("nr_class,beam_width,length",
|
||||||
[
|
[
|
||||||
(2, 3, 3),
|
(2, 3, 3),
|
||||||
(3, 6, 15),
|
(3, 6, 15),
|
||||||
(4, 20, 32),
|
(4, 20, 32),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_initialize(nr_class, beam_width, length):
|
def test_initialize(nr_class, beam_width, length):
|
||||||
b = Beam(nr_class, beam_width)
|
b = Beam(nr_class, beam_width)
|
||||||
b.initialize(initialize, destroy, length, NULL)
|
b.initialize(initialize, destroy, length, NULL)
|
||||||
|
@ -79,11 +82,11 @@ def test_initialize(nr_class, beam_width, length):
|
||||||
|
|
||||||
@cytest
|
@cytest
|
||||||
@pytest.mark.parametrize("nr_class,beam_width,length,extra",
|
@pytest.mark.parametrize("nr_class,beam_width,length,extra",
|
||||||
[
|
[
|
||||||
(2, 3, 4, None),
|
(2, 3, 4, None),
|
||||||
(3, 6, 15, u"test beam 1"),
|
(3, 6, 15, u"test beam 1"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_initialize_extra(nr_class, beam_width, length, extra):
|
def test_initialize_extra(nr_class, beam_width, length, extra):
|
||||||
b = Beam(nr_class, beam_width)
|
b = Beam(nr_class, beam_width)
|
||||||
if extra is None:
|
if extra is None:
|
||||||
|
@ -97,11 +100,11 @@ def test_initialize_extra(nr_class, beam_width, length, extra):
|
||||||
|
|
||||||
@cytest
|
@cytest
|
||||||
@pytest.mark.parametrize("nr_class,beam_width,length",
|
@pytest.mark.parametrize("nr_class,beam_width,length",
|
||||||
[
|
[
|
||||||
(3, 6, 15),
|
(3, 6, 15),
|
||||||
(4, 20, 32),
|
(4, 20, 32),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_transition(nr_class, beam_width, length):
|
def test_transition(nr_class, beam_width, length):
|
||||||
b = Beam(nr_class, beam_width)
|
b = Beam(nr_class, beam_width)
|
||||||
b.initialize(initialize, destroy, length, NULL)
|
b.initialize(initialize, destroy, length, NULL)
|
||||||
|
|
|
@ -1759,7 +1759,7 @@ cdef class Doc:
|
||||||
data["underscore_span"] = {}
|
data["underscore_span"] = {}
|
||||||
if attr not in data["underscore_span"]:
|
if attr not in data["underscore_span"]:
|
||||||
data["underscore_span"][attr] = []
|
data["underscore_span"][attr] = []
|
||||||
data["underscore_span"][attr].append({"start": start, "end": end, "value": value, "label": _label, "kb_id": _kb_id, "id":_span_id})
|
data["underscore_span"][attr].append({"start": start, "end": end, "value": value, "label": _label, "kb_id": _kb_id, "id": _span_id})
|
||||||
|
|
||||||
for attr in underscore:
|
for attr in underscore:
|
||||||
if attr not in user_keys:
|
if attr not in user_keys:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
cimport numpy as np
|
cimport numpy as np
|
||||||
from libc.string cimport memset
|
|
||||||
|
|
||||||
from ..errors import Errors
|
from ..errors import Errors
|
||||||
from ..morphology import Morphology
|
from ..morphology import Morphology
|
||||||
|
|
|
@ -225,8 +225,8 @@ cdef class Span:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _(self):
|
def _(self):
|
||||||
cdef SpanC* span_c = self.span_c()
|
|
||||||
"""Custom extension attributes registered via `set_extension`."""
|
"""Custom extension attributes registered via `set_extension`."""
|
||||||
|
cdef SpanC* span_c = self.span_c()
|
||||||
return Underscore(Underscore.span_extensions, self,
|
return Underscore(Underscore.span_extensions, self,
|
||||||
start=span_c.start_char, end=span_c.end_char, label=self.label, kb_id=self.kb_id, span_id=self.id)
|
start=span_c.start_char, end=span_c.end_char, label=self.label, kb_id=self.kb_id, span_id=self.id)
|
||||||
|
|
||||||
|
@ -933,7 +933,6 @@ cdef class Span:
|
||||||
self.id_ = ent_id_
|
self.id_ = ent_id_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cdef int _count_words_to_root(const TokenC* token, int sent_length) except -1:
|
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
|
# Don't allow spaces to be the root, if there are
|
||||||
# better candidates
|
# better candidates
|
||||||
|
|
Loading…
Reference in New Issue
Block a user