mirror of https://github.com/explosion/spaCy.git
* Do non-monotonic Unshift. Every word can be shifted at most 1 time. When the Reduce move is used, if S0 has no head, we put the word back on the buffer. Gets 86.4 on nw 1k with gold pre-proc. Break transition not yet implemented for this.
This commit is contained in:
parent
7bf6b7de3e
commit
aa9625f688
|
@ -19,7 +19,7 @@ from .stateclass cimport StateClass
|
||||||
|
|
||||||
|
|
||||||
DEF NON_MONOTONIC = True
|
DEF NON_MONOTONIC = True
|
||||||
DEF USE_BREAK = True
|
DEF USE_BREAK = False
|
||||||
|
|
||||||
cdef weight_t MIN_SCORE = -90000
|
cdef weight_t MIN_SCORE = -90000
|
||||||
|
|
||||||
|
@ -70,12 +70,14 @@ cdef int pop_cost(StateClass stcls, const GoldParseC* gold, int target) nogil:
|
||||||
break
|
break
|
||||||
return cost
|
return cost
|
||||||
|
|
||||||
|
|
||||||
cdef int arc_cost(StateClass stcls, const GoldParseC* gold, int head, int child) nogil:
|
cdef int arc_cost(StateClass stcls, const GoldParseC* gold, int head, int child) nogil:
|
||||||
if arc_is_gold(gold, head, child):
|
if arc_is_gold(gold, head, child):
|
||||||
return 0
|
return 0
|
||||||
elif stcls.H(child) == gold.heads[child]:
|
elif stcls.H(child) == gold.heads[child]:
|
||||||
return 1
|
return 1
|
||||||
elif gold.heads[child] >= stcls.B(0):
|
# Head in buffer
|
||||||
|
elif gold.heads[child] >= stcls.B(0) and stcls.B(1) != -1:
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
@ -110,13 +112,10 @@ cdef bint _is_gold_root(const GoldParseC* gold, int word) nogil:
|
||||||
cdef class Shift:
|
cdef class Shift:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef bint is_valid(StateClass st, int label) nogil:
|
cdef bint is_valid(StateClass st, int label) nogil:
|
||||||
return not st.eol()
|
return st.buffer_length() >= 2 and not st.shifted[st.B(0)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int transition(StateClass state, int label) nogil:
|
cdef int transition(StateClass state, int label) nogil:
|
||||||
# Set the dep label, in case we need it after we reduce
|
|
||||||
if NON_MONOTONIC:
|
|
||||||
state._sent[state.B(0)].dep = label
|
|
||||||
state.push()
|
state.push()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -135,27 +134,25 @@ cdef class Shift:
|
||||||
cdef class Reduce:
|
cdef class Reduce:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef bint is_valid(StateClass st, int label) nogil:
|
cdef bint is_valid(StateClass st, int label) nogil:
|
||||||
if NON_MONOTONIC:
|
return st.stack_depth() >= 2
|
||||||
return st.stack_depth() >= 2 #and not missing_brackets(s)
|
|
||||||
else:
|
|
||||||
return st.stack_depth() >= 2 and st.has_head(st.S(0))
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int transition(StateClass st, int label) nogil:
|
cdef int transition(StateClass st, int label) nogil:
|
||||||
if NON_MONOTONIC and not st.has_head(st.S(0)) and st.stack_depth() >= 2:
|
if st.has_head(st.S(0)):
|
||||||
st.add_arc(st.S(1), st.S(0), st.S_(0).dep)
|
st.pop()
|
||||||
st.pop()
|
else:
|
||||||
|
st.unshift()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
cdef int cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
||||||
return Reduce.move_cost(s, gold) + Reduce.label_cost(s, gold, label)
|
return Reduce.move_cost(s, gold) + Reduce.label_cost(s, gold, label)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef inline int move_cost(StateClass s, const GoldParseC* gold) nogil:
|
cdef inline int move_cost(StateClass st, const GoldParseC* gold) nogil:
|
||||||
if NON_MONOTONIC:
|
if st.shifted[st.S(0)]:
|
||||||
return pop_cost(s, gold, s.S(0))
|
return pop_cost(st, gold, st.S(0))
|
||||||
else:
|
else:
|
||||||
return children_in_buffer(s, s.S(0), gold.heads)
|
return 0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef inline int label_cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
cdef inline int label_cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
||||||
|
@ -166,18 +163,16 @@ cdef class LeftArc:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef bint is_valid(StateClass st, int label) nogil:
|
cdef bint is_valid(StateClass st, int label) nogil:
|
||||||
if NON_MONOTONIC:
|
if NON_MONOTONIC:
|
||||||
return st.stack_depth() >= 1 #and not missing_brackets(s)
|
return st.stack_depth() >= 1 and st.buffer_length() >= 1 #and not missing_brackets(s)
|
||||||
else:
|
else:
|
||||||
return st.stack_depth() >= 1 and not st.has_head(st.S(0))
|
return st.stack_depth() >= 1 and st.buffer_length() >= 1 and not st.has_head(st.S(0))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int transition(StateClass st, int label) nogil:
|
cdef int transition(StateClass st, int label) nogil:
|
||||||
# Interpret left-arcs from EOL as attachment to root
|
st.add_arc(st.B(0), st.S(0), label)
|
||||||
if st.eol():
|
|
||||||
st.add_arc(st.S(0), st.S(0), label)
|
|
||||||
else:
|
|
||||||
st.add_arc(st.B(0), st.S(0), label)
|
|
||||||
st.pop()
|
st.pop()
|
||||||
|
if st.empty():
|
||||||
|
st.push()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
cdef int cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
||||||
|
@ -198,7 +193,7 @@ cdef class LeftArc:
|
||||||
cdef class RightArc:
|
cdef class RightArc:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef bint is_valid(StateClass st, int label) nogil:
|
cdef bint is_valid(StateClass st, int label) nogil:
|
||||||
return st.stack_depth() >= 1 and not st.eol()
|
return st.stack_depth() >= 1 and st.buffer_length() >= 1
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int transition(StateClass st, int label) nogil:
|
cdef int transition(StateClass st, int label) nogil:
|
||||||
|
@ -213,6 +208,8 @@ cdef class RightArc:
|
||||||
cdef inline int move_cost(StateClass s, const GoldParseC* gold) nogil:
|
cdef inline int move_cost(StateClass s, const GoldParseC* gold) nogil:
|
||||||
if arc_is_gold(gold, s.S(0), s.B(0)):
|
if arc_is_gold(gold, s.S(0), s.B(0)):
|
||||||
return 0
|
return 0
|
||||||
|
elif s.shifted[s.B(0)]:
|
||||||
|
return push_cost(s, gold, s.B(0))
|
||||||
else:
|
else:
|
||||||
return push_cost(s, gold, s.B(0)) + arc_cost(s, gold, s.S(0), s.B(0))
|
return push_cost(s, gold, s.B(0)) + arc_cost(s, gold, s.S(0), s.B(0))
|
||||||
|
|
||||||
|
@ -231,30 +228,13 @@ cdef class Break:
|
||||||
return False
|
return False
|
||||||
elif st.stack_depth() < 1:
|
elif st.stack_depth() < 1:
|
||||||
return False
|
return False
|
||||||
elif NON_MONOTONIC:
|
|
||||||
return True
|
|
||||||
else:
|
else:
|
||||||
# In the Break transition paper, they have this constraint that prevents
|
|
||||||
# Break if stack is disconnected. But, if we're doing non-monotonic parsing,
|
|
||||||
# we prefer to relax this constraint. This is helpful in parsing whole
|
|
||||||
# documents, because then we don't get stuck with words on the stack.
|
|
||||||
seen_headless = False
|
|
||||||
for i in range(st.stack_depth()):
|
|
||||||
if not st.has_head(st.S(i)):
|
|
||||||
if seen_headless:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
seen_headless = True
|
|
||||||
# TODO: Constituency constraints
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int transition(StateClass st, int label) nogil:
|
cdef int transition(StateClass st, int label) nogil:
|
||||||
st.set_sent_end(st.B(0)-1)
|
#st.set_sent_end()
|
||||||
while not st.empty():
|
pass
|
||||||
if not st.has_head(st.S(0)):
|
|
||||||
st._sent[st.S(0)].dep = label
|
|
||||||
st.pop()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef int cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
cdef int cost(StateClass s, const GoldParseC* gold, int label) nogil:
|
||||||
|
@ -262,9 +242,9 @@ cdef class Break:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef inline int move_cost(StateClass s, const GoldParseC* gold) nogil:
|
cdef inline int move_cost(StateClass s, const GoldParseC* gold) nogil:
|
||||||
# When we break, we Reduce all of the words on the stack.
|
# When we break, we can't reach any arcs between stack and buffer
|
||||||
|
# So cost is number of deps between S0...Sn and B0...Nn
|
||||||
cdef int cost = 0
|
cdef int cost = 0
|
||||||
# Number of deps between S0...Sn and N0...Nn
|
|
||||||
cdef int i, j, B_i, S_i
|
cdef int i, j, B_i, S_i
|
||||||
for i in range(s.buffer_length()):
|
for i in range(s.buffer_length()):
|
||||||
B_i = s.B(i)
|
B_i = s.B(i)
|
||||||
|
@ -432,7 +412,7 @@ cdef class ArcEager(TransitionSystem):
|
||||||
best = self.c[i]
|
best = self.c[i]
|
||||||
score = scores[i]
|
score = scores[i]
|
||||||
assert best.clas < self.n_moves
|
assert best.clas < self.n_moves
|
||||||
assert score > MIN_SCORE
|
assert score > MIN_SCORE, (stcls.stack_depth(), stcls.buffer_length())
|
||||||
# Label Shift moves with the best Right-Arc label, for non-monotonic
|
# Label Shift moves with the best Right-Arc label, for non-monotonic
|
||||||
# actions
|
# actions
|
||||||
if best.move == SHIFT:
|
if best.move == SHIFT:
|
||||||
|
|
Loading…
Reference in New Issue