mirror of
https://github.com/explosion/spaCy.git
synced 2025-04-28 21:03:41 +03:00
Unhack beam parsing, moving it under options instead of global flags
This commit is contained in:
parent
0209a06b4e
commit
f75420ae79
|
@ -49,7 +49,7 @@ cdef class ParserBeam(object):
|
||||||
cdef public object dones
|
cdef public object dones
|
||||||
|
|
||||||
def __init__(self, TransitionSystem moves, states, golds,
|
def __init__(self, TransitionSystem moves, states, golds,
|
||||||
int width=4, float density=0.001):
|
int width, float density):
|
||||||
self.moves = moves
|
self.moves = moves
|
||||||
self.states = states
|
self.states = states
|
||||||
self.golds = golds
|
self.golds = golds
|
||||||
|
@ -89,7 +89,10 @@ cdef class ParserBeam(object):
|
||||||
self._set_scores(beam, scores[i])
|
self._set_scores(beam, scores[i])
|
||||||
if self.golds is not None:
|
if self.golds is not None:
|
||||||
self._set_costs(beam, self.golds[i], follow_gold=follow_gold)
|
self._set_costs(beam, self.golds[i], follow_gold=follow_gold)
|
||||||
beam.advance(_transition_state, _hash_state, <void*>self.moves.c)
|
if follow_gold:
|
||||||
|
beam.advance(_transition_state, NULL, <void*>self.moves.c)
|
||||||
|
else:
|
||||||
|
beam.advance(_transition_state, _hash_state, <void*>self.moves.c)
|
||||||
beam.check_done(_check_final_state, NULL)
|
beam.check_done(_check_final_state, NULL)
|
||||||
if beam.is_done and self.golds is not None:
|
if beam.is_done and self.golds is not None:
|
||||||
for j in range(beam.size):
|
for j in range(beam.size):
|
||||||
|
@ -145,15 +148,16 @@ def get_token_ids(states, int n_tokens):
|
||||||
nr_update = 0
|
nr_update = 0
|
||||||
def update_beam(TransitionSystem moves, int nr_feature, int max_steps,
|
def update_beam(TransitionSystem moves, int nr_feature, int max_steps,
|
||||||
states, tokvecs, golds,
|
states, tokvecs, golds,
|
||||||
state2vec, vec2scores, drop=0., sgd=None,
|
state2vec, vec2scores,
|
||||||
losses=None, int width=4, float density=0.001):
|
int width, float density,
|
||||||
|
sgd=None, losses=None, drop=0.):
|
||||||
global nr_update
|
global nr_update
|
||||||
cdef MaxViolation violn
|
cdef MaxViolation violn
|
||||||
nr_update += 1
|
nr_update += 1
|
||||||
pbeam = ParserBeam(moves, states, golds,
|
pbeam = ParserBeam(moves, states, golds,
|
||||||
width=width, density=density)
|
width=width, density=density)
|
||||||
gbeam = ParserBeam(moves, states, golds,
|
gbeam = ParserBeam(moves, states, golds,
|
||||||
width=width, density=density)
|
width=width, density=0.0)
|
||||||
cdef StateClass state
|
cdef StateClass state
|
||||||
beam_maps = []
|
beam_maps = []
|
||||||
backprops = []
|
backprops = []
|
||||||
|
@ -194,13 +198,13 @@ def update_beam(TransitionSystem moves, int nr_feature, int max_steps,
|
||||||
violn.check_crf(pbeam[i], gbeam[i])
|
violn.check_crf(pbeam[i], gbeam[i])
|
||||||
histories = []
|
histories = []
|
||||||
losses = []
|
losses = []
|
||||||
for i, violn in enumerate(violns):
|
for violn in violns:
|
||||||
if violn.cost < 1:
|
if violn.p_hist:
|
||||||
histories.append([])
|
|
||||||
losses.append([])
|
|
||||||
else:
|
|
||||||
histories.append(violn.p_hist + violn.g_hist)
|
histories.append(violn.p_hist + violn.g_hist)
|
||||||
losses.append(violn.p_probs + violn.g_probs)
|
losses.append(violn.p_probs + violn.g_probs)
|
||||||
|
else:
|
||||||
|
histories.append([])
|
||||||
|
losses.append([])
|
||||||
states_d_scores = get_gradient(moves.n_moves, beam_maps, histories, losses)
|
states_d_scores = get_gradient(moves.n_moves, beam_maps, histories, losses)
|
||||||
return states_d_scores, backprops[:len(states_d_scores)]
|
return states_d_scores, backprops[:len(states_d_scores)]
|
||||||
|
|
||||||
|
@ -215,10 +219,6 @@ def get_states(pbeams, gbeams, beam_map, nr_update):
|
||||||
for eg_id, (pbeam, gbeam) in enumerate(zip(pbeams, gbeams)):
|
for eg_id, (pbeam, gbeam) in enumerate(zip(pbeams, gbeams)):
|
||||||
p_indices.append([])
|
p_indices.append([])
|
||||||
g_indices.append([])
|
g_indices.append([])
|
||||||
if pbeam.loss > 0 and pbeam.min_score > (gbeam.score + numpy.sqrt(nr_update)):
|
|
||||||
pbeams.dones[eg_id] = True
|
|
||||||
gbeams.dones[eg_id] = True
|
|
||||||
continue
|
|
||||||
for i in range(pbeam.size):
|
for i in range(pbeam.size):
|
||||||
state = <StateClass>pbeam.at(i)
|
state = <StateClass>pbeam.at(i)
|
||||||
if not state.is_final():
|
if not state.is_final():
|
||||||
|
@ -269,9 +269,12 @@ def get_gradient(nr_class, beam_maps, histories, losses):
|
||||||
assert len(histories) == len(losses)
|
assert len(histories) == len(losses)
|
||||||
for eg_id, hists in enumerate(histories):
|
for eg_id, hists in enumerate(histories):
|
||||||
for loss, hist in zip(losses[eg_id], hists):
|
for loss, hist in zip(losses[eg_id], hists):
|
||||||
if abs(loss) == 0.0 or numpy.isnan(loss):
|
if loss == 0.0 or numpy.isnan(loss):
|
||||||
continue
|
continue
|
||||||
key = tuple([eg_id])
|
key = tuple([eg_id])
|
||||||
|
# Adjust loss for length
|
||||||
|
avg_loss = loss / len(hist)
|
||||||
|
loss += avg_loss * (nr_step - len(hist))
|
||||||
for j, clas in enumerate(hist):
|
for j, clas in enumerate(hist):
|
||||||
i = beam_maps[j][key]
|
i = beam_maps[j][key]
|
||||||
# In step j, at state i action clas
|
# In step j, at state i action clas
|
||||||
|
|
|
@ -67,7 +67,6 @@ from ..attrs cimport ID, TAG, DEP, ORTH, NORM, PREFIX, SUFFIX, TAG
|
||||||
from . import _beam_utils
|
from . import _beam_utils
|
||||||
|
|
||||||
USE_FINE_TUNE = True
|
USE_FINE_TUNE = True
|
||||||
BEAM_PARSE = True
|
|
||||||
|
|
||||||
def get_templates(*args, **kwargs):
|
def get_templates(*args, **kwargs):
|
||||||
return []
|
return []
|
||||||
|
@ -299,6 +298,10 @@ cdef class Parser:
|
||||||
self.moves = self.TransitionSystem(self.vocab.strings, {})
|
self.moves = self.TransitionSystem(self.vocab.strings, {})
|
||||||
else:
|
else:
|
||||||
self.moves = moves
|
self.moves = moves
|
||||||
|
if 'beam_width' not in cfg:
|
||||||
|
cfg['beam_width'] = util.env_opt('beam_width', 1)
|
||||||
|
if 'beam_density' not in cfg:
|
||||||
|
cfg['beam_density'] = util.env_opt('beam_density', 0.0)
|
||||||
self.cfg = cfg
|
self.cfg = cfg
|
||||||
if 'actions' in self.cfg:
|
if 'actions' in self.cfg:
|
||||||
for action, labels in self.cfg.get('actions', {}).items():
|
for action, labels in self.cfg.get('actions', {}).items():
|
||||||
|
@ -321,9 +324,7 @@ cdef class Parser:
|
||||||
if beam_width is None:
|
if beam_width is None:
|
||||||
beam_width = self.cfg.get('beam_width', 1)
|
beam_width = self.cfg.get('beam_width', 1)
|
||||||
if beam_density is None:
|
if beam_density is None:
|
||||||
beam_density = self.cfg.get('beam_density', 0.001)
|
beam_density = self.cfg.get('beam_density', 0.0)
|
||||||
if BEAM_PARSE:
|
|
||||||
beam_width = 16
|
|
||||||
cdef Beam beam
|
cdef Beam beam
|
||||||
if beam_width == 1:
|
if beam_width == 1:
|
||||||
states = self.parse_batch([doc], [doc.tensor])
|
states = self.parse_batch([doc], [doc.tensor])
|
||||||
|
@ -339,7 +340,7 @@ cdef class Parser:
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def pipe(self, docs, int batch_size=1000, int n_threads=2,
|
def pipe(self, docs, int batch_size=1000, int n_threads=2,
|
||||||
beam_width=1, beam_density=0.001):
|
beam_width=None, beam_density=None):
|
||||||
"""
|
"""
|
||||||
Process a stream of documents.
|
Process a stream of documents.
|
||||||
|
|
||||||
|
@ -351,8 +352,10 @@ cdef class Parser:
|
||||||
The number of threads with which to work on the buffer in parallel.
|
The number of threads with which to work on the buffer in parallel.
|
||||||
Yields (Doc): Documents, in order.
|
Yields (Doc): Documents, in order.
|
||||||
"""
|
"""
|
||||||
if BEAM_PARSE:
|
if beam_width is None:
|
||||||
beam_width = 16
|
beam_width = self.cfg.get('beam_width', 1)
|
||||||
|
if beam_density is None:
|
||||||
|
beam_density = self.cfg.get('beam_density', 0.0)
|
||||||
cdef Doc doc
|
cdef Doc doc
|
||||||
cdef Beam beam
|
cdef Beam beam
|
||||||
for docs in cytoolz.partition_all(batch_size, docs):
|
for docs in cytoolz.partition_all(batch_size, docs):
|
||||||
|
@ -430,7 +433,7 @@ cdef class Parser:
|
||||||
next_step.push_back(st)
|
next_step.push_back(st)
|
||||||
return states
|
return states
|
||||||
|
|
||||||
def beam_parse(self, docs, tokvecses, int beam_width=16, float beam_density=0.001):
|
def beam_parse(self, docs, tokvecses, int beam_width=3, float beam_density=0.001):
|
||||||
cdef Beam beam
|
cdef Beam beam
|
||||||
cdef np.ndarray scores
|
cdef np.ndarray scores
|
||||||
cdef Doc doc
|
cdef Doc doc
|
||||||
|
@ -480,9 +483,10 @@ cdef class Parser:
|
||||||
return beams
|
return beams
|
||||||
|
|
||||||
def update(self, docs_tokvecs, golds, drop=0., sgd=None, losses=None):
|
def update(self, docs_tokvecs, golds, drop=0., sgd=None, losses=None):
|
||||||
if BEAM_PARSE and numpy.random.random() >= 0.5:
|
if self.cfg.get('beam_width', 1) >= 2 and numpy.random.random() >= 0.5:
|
||||||
return self.update_beam(docs_tokvecs, golds, drop=drop, sgd=sgd,
|
return self.update_beam(docs_tokvecs, golds,
|
||||||
losses=losses)
|
self.cfg['beam_width'], self.cfg['beam_density'],
|
||||||
|
drop=drop, sgd=sgd, losses=losses)
|
||||||
if losses is not None and self.name not in losses:
|
if losses is not None and self.name not in losses:
|
||||||
losses[self.name] = 0.
|
losses[self.name] = 0.
|
||||||
docs, tokvec_lists = docs_tokvecs
|
docs, tokvec_lists = docs_tokvecs
|
||||||
|
@ -548,7 +552,12 @@ cdef class Parser:
|
||||||
bp_my_tokvecs(d_tokvecs, sgd=sgd)
|
bp_my_tokvecs(d_tokvecs, sgd=sgd)
|
||||||
return d_tokvecs
|
return d_tokvecs
|
||||||
|
|
||||||
def update_beam(self, docs_tokvecs, golds, drop=0., sgd=None, losses=None):
|
def update_beam(self, docs_tokvecs, golds, width=None, density=None,
|
||||||
|
drop=0., sgd=None, losses=None):
|
||||||
|
if width is None:
|
||||||
|
width = self.cfg.get('beam_width', 2)
|
||||||
|
if density is None:
|
||||||
|
density = self.cfg.get('beam_density', 0.0)
|
||||||
if losses is not None and self.name not in losses:
|
if losses is not None and self.name not in losses:
|
||||||
losses[self.name] = 0.
|
losses[self.name] = 0.
|
||||||
docs, tokvecs = docs_tokvecs
|
docs, tokvecs = docs_tokvecs
|
||||||
|
@ -570,8 +579,8 @@ cdef class Parser:
|
||||||
states_d_scores, backprops = _beam_utils.update_beam(self.moves, self.nr_feature, 500,
|
states_d_scores, backprops = _beam_utils.update_beam(self.moves, self.nr_feature, 500,
|
||||||
states, tokvecs, golds,
|
states, tokvecs, golds,
|
||||||
state2vec, vec2scores,
|
state2vec, vec2scores,
|
||||||
drop, sgd, losses,
|
width, density,
|
||||||
width=16)
|
sgd=sgd, drop=drop, losses=losses)
|
||||||
backprop_lower = []
|
backprop_lower = []
|
||||||
for i, d_scores in enumerate(states_d_scores):
|
for i, d_scores in enumerate(states_d_scores):
|
||||||
if losses is not None:
|
if losses is not None:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user