def strip_functional_tags(tree: Tree) -> None: """ Removes all functional tags from constituency labels in an NLTK tree. We also strip off anything after a =, - or | character, because these are functional tags which we don't want to use. This modification is done in-place. """ clean_label = tree.label().split("=")[0].split("-")[0].split("|")[0] tree.set_label(clean_label) for child in tree: if not isinstance(child[0], str): strip_functional_tags(child)
def _strip_functional_tags(self, tree: Tree) -> None: """ Removes all functional tags from constituency labels in an NLTK tree. We also strip off anything after a =, - or | character, because these are functional tags which we don't want to use. This modification is done in-place. """ clean_label = tree.label().split("=")[0].split("-")[0].split("|")[0] tree.set_label(clean_label) for child in tree: if not isinstance(child[0], str): self._strip_functional_tags(child)
def build_tree(node,chain): # -> handle function tags """ -> PS tree of node's projection chain """ preterminal = node['tag'] if 'lemma' in node: # not a trace-node if (node['lemma'].lower() in wh_lemmas) and \ node['tag']!='CONJ': #WH feature preterminal += '-WH' output = Tree(preterminal,[node['word']]) for l in chain[0][::-1]: for i in range(l[1]): output = Tree(l[0],[output]) if chain[1]: if chain[1]=='PRN': output = Tree(chain[1],[output]) else: output.set_label(output.label()+'-'+chain[1]) return output
def forward(self, word_list, gold_op_list, unary_limit): is_training = gold_op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, _ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not OP_FINISH.') # initial values EMBED_ZEROS = XP.fzeros((1, self.n_embed)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) SRSTATE_ZEROS = XP.fzeros((1, self.n_srstate)) NEG_INF = -1e20 # queue encoding xq_list = [] qc = QUEUE_ZEROS q = QUEUE_ZEROS for text, wid in reversed(word_list): x = self.net_embed(XP.iarray([wid])) qc, q = self.net_encoder(qc, x, q) xq_list.insert(0, (text, x, q)) # estimate s_list = [] zc = SRSTATE_ZEROS z = SRSTATE_ZEROS unary_chain = 0 if is_training: loss = XP.fzeros(()) for i in itertools.count(): text, x, q = xq_list[0] if xq_list else ('', EMBED_ZEROS, QUEUE_ZEROS) t1, sc1, s1 = s_list[-1] if s_list else (None, STACK_ZEROS, STACK_ZEROS) t2, sc2, s2 = s_list[-2] if len(s_list) >= 2 else (None, STACK_ZEROS, STACK_ZEROS) t3, sc3, s3 = s_list[-3] if len(s_list) >= 3 else (None, STACK_ZEROS, STACK_ZEROS) zc, z = self.net_sr(zc, q, s1, z) o = self.net_operation(z) if is_training: loss += functions.softmax_cross_entropy(o, XP.iarray([gold_op_list[i][0]])) o_argmax = gold_op_list[i][0] else: o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not xq_list: o_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = NEG_INF filtered += 1 if xq_list or len(s_list) > 1: o_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (STACK_ZEROS, self.net_shift(x, q, s1, z)) xq_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, q, s1, s2, z) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, q, s1, s2, s3, z) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break if is_training: loss += functions.softmax_cross_entropy(label, XP.iarray([gold_op_list[i][1]])) label_argmax = gold_op_list[i][1] else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0)) ''' if is_training: o_est = int(cuda.to_cpu(o.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if o_est == gold_op_list[i][0] else ' ', '*' if label_est == gold_op_list[i][1] else ' ', gold_op_list[i][0], gold_op_list[i][1], o_est, label_est, len(s_list), len(xq_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, _, __ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward(self, word_list, gold_op_list, unary_limit): is_training = gold_op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, _ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not OP_FINISH.') # default values EMBED_ZEROS = XP.fzeros((1, self.n_embed)) CEMBED_ZEROS = XP.fzeros((1, self.n_char_embed)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) SRSTATE_ZEROS = XP.fzeros((1, self.n_srstate)) QUEUE_DEFAULT = ('', EMBED_ZEROS, CEMBED_ZEROS, CEMBED_ZEROS, QUEUE_ZEROS, QUEUE_ZEROS) STACK_DEFAULT = (None, STACK_ZEROS, STACK_ZEROS) NEG_INF = -1e20 # word embedding x_list = [self.net_embed(XP.iarray([wid])) for _, wid in word_list] jk_list = [self.net_cembed(text) for text, _ in word_list] # forward encoding a_list = [] ac = QUEUE_ZEROS a = QUEUE_ZEROS for x, (j, k) in zip(x_list, jk_list): ac, a = self.net_forward(ac, x, j, k, a) a_list.append(a) # backward encoding b_list = [] bc = QUEUE_ZEROS b = QUEUE_ZEROS for x, (j, k) in zip(reversed(x_list), reversed(jk_list)): bc, b = self.net_backward(bc, x, j, k, b) b_list.insert(0, b) q_list = [ (text, x, j, k, a, b) \ for (text, _), x, (j, k), a, b \ in zip(word_list, x_list, jk_list, a_list, b_list)] # estimate s_list = [] zc = SRSTATE_ZEROS z = SRSTATE_ZEROS unary_chain = 0 if is_training: loss = XP.fzeros(()) for i in itertools.count(): text, x, j, k, a, b = q_list[0] if q_list else QUEUE_DEFAULT t1, sc1, s1 = s_list[-1] if s_list else STACK_DEFAULT t2, sc2, s2 = s_list[-2] if len(s_list) >= 2 else STACK_DEFAULT t3, sc3, s3 = s_list[-3] if len(s_list) >= 3 else STACK_DEFAULT zc, z = self.net_sr(zc, a, b, s1, s2, z) o = self.net_operation(z) if is_training: loss += functions.softmax_cross_entropy( o, XP.iarray([gold_op_list[i][0]])) o_argmax = gold_op_list[i][0] else: o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not q_list: o_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = NEG_INF filtered += 1 if q_list or len(s_list) > 1: o_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (STACK_ZEROS, self.net_shift(x, j, k, a, b, s1, z)) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(a, b, s1, s2) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, a, b, s1, s2, z) s_list.pop() unary_chain += 1 label = self.net_phrase(a, b, s1, s2) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, a, b, s1, s2, s3, z) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(a, b, s1, s2) else: # OP_FINISH break if is_training: loss += functions.softmax_cross_entropy( label, XP.iarray([gold_op_list[i][1]])) label_argmax = gold_op_list[i][1] else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0)) ''' if is_training: o_est = int(cuda.to_cpu(o.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if o_est == gold_op_list[i][0] else ' ', '*' if label_est == gold_op_list[i][1] else ' ', gold_op_list[i][0], gold_op_list[i][1], o_est, label_est, len(s_list), len(q_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, _, __ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward(self, word_list, gold_op_list, unary_limit): is_training = gold_op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, _ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not OP_FINISH.') # initial values OP_ZEROS = XP.fzeros((1, NUM_OP)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) NEG_INF = -1e20 # queue encoding q_list = [] qc = QUEUE_ZEROS q = QUEUE_ZEROS for text, wid in reversed(word_list): qc, q = self.net_encoder(qc, XP.iarray([wid]), q) q_list.insert(0, (text, q)) # estimate s_list = [] oc = OP_ZEROS o = OP_ZEROS unary_chain = 0 if is_training: loss = XP.fzeros(()) for i in itertools.count(): text, q = q_list[0] if q_list else ('', QUEUE_ZEROS) t1, sc1, s1 = s_list[-1] if s_list else (None, STACK_ZEROS, STACK_ZEROS) t2, sc2, s2 = s_list[-2] if len(s_list) >= 2 else (None, STACK_ZEROS, STACK_ZEROS) t3, sc3, s3 = s_list[-3] if len(s_list) >= 3 else (None, STACK_ZEROS, STACK_ZEROS) oc, o = self.net_operation(oc, q, s1, o) if is_training: loss += functions.softmax_cross_entropy(o, XP.iarray([gold_op_list[i][0]])) o_argmax = gold_op_list[i][0] else: o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not q_list: o_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = NEG_INF filtered += 1 if q_list or len(s_list) > 1: o_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = self.net_shift(sc1, q, s1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc2, s1, s2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc3, s1, s2, s3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break if is_training: loss += functions.softmax_cross_entropy(label, XP.iarray([gold_op_list[i][1]])) label_argmax = gold_op_list[i][1] else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0)) ''' if is_training: o_est = int(cuda.to_cpu(o.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if o_est == gold_op_list[i][0] else ' ', '*' if label_est == gold_op_list[i][1] else ' ', gold_op_list[i][0], gold_op_list[i][1], o_est, label_est, len(s_list), len(q_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, _, __ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward(self, word_list, gold_op_list, unary_limit, embed_cache): is_training = gold_op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, *_ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1][0] != OP_FINISH: raise ValueError('Last operation is not OP_FINISH.') # word embedding x_list = [] jk_list = [] for text, wid in word_list: if text in embed_cache: x, jk = embed_cache[text] else: x = self.net_embed(wid) jk = self.net_cembed(text) embed_cache[text] = (x, jk) x_list.append(x) jk_list.append(jk) # forward encoding a_list = [] ac = self.QUEUE_ZEROS a = self.QUEUE_ZEROS for x, (j, k) in zip(x_list, jk_list): ac, a = self.net_forward(ac, x, j, k, a) a_list.append(a) # backward encoding b_list = [] bc = self.QUEUE_ZEROS b = self.QUEUE_ZEROS for x, (j, k) in zip(reversed(x_list), reversed(jk_list)): bc, b = self.net_backward(bc, x, j, k, b) b_list.insert(0, b) q_list = [ (text, x, j, k, a, b) \ for (text, _), x, (j, k), a, b \ in zip(word_list, x_list, jk_list, a_list, b_list)] # estimate s_list = [] zc = self.SRSTATE_ZEROS z = self.SRSTATE_ZEROS unary_chain = 0 if is_training: loss = XP.fzeros(()) for i in itertools.count(): if is_training: gold_op, gold_label, gold_op_vram, gold_label_vram = gold_op_list[i] text, x, j, k, a, b = q_list[0] if q_list else self.QUEUE_DEFAULT t1, sc1, s1, rc1, r1 = s_list[-1] if s_list else self.STACK_DEFAULT t2, sc2, s2, rc2, r2 = s_list[-2] if len(s_list) >= 2 else self.STACK_DEFAULT t3, sc3, s3, rc3, r3 = s_list[-3] if len(s_list) >= 3 else self.STACK_DEFAULT zc, z = self.net_sr(zc, a, b, s1, r1, s2, r2, z) o = self.net_operation(z) if is_training: loss += functions.softmax_cross_entropy(o, gold_op_vram) o_argmax = gold_op else: o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not q_list: o_filter[OP_SHIFT] = self.NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = self.NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = self.NEG_INF filtered += 1 if q_list or len(s_list) > 1: o_filter[OP_FINISH] = self.NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (self.STACK_ZEROS, self.net_shift(x, j, k, a, b, s1)) rc0, r0 = self.net_stack(rc1, s0, r1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, a, b, s1, s2) rc0, r0 = self.net_stack(rc2, s0, r2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, a, b, s1, s2, s3) rc0, r0 = self.net_stack(rc3, s0, r3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break if is_training: loss += functions.softmax_cross_entropy(label, gold_label_vram) label_argmax = gold_label else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0, rc0, r0)) ''' if is_training: o_est = int(cuda.to_cpu(o.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if o_est == gold_op else ' ', '*' if label_est == gold_label else ' ', gold_op, gold_label, o_est, label_est, len(s_list), len(q_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, *_ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward(self, word_list, op_list, unary_limit): is_training = op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, _ in op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not OP_FINISH.') # initial values EMBED_ZEROS = my_zeros((1, self.n_embed), np.float32) QUEUE_ZEROS = my_zeros((1, self.n_queue_state), np.float32) STACK_ZEROS = my_zeros((1, self.n_stack_state), np.float32) NEG_INF = -1e20 # queue encoding xq_list = [] c = QUEUE_ZEROS q = QUEUE_ZEROS for text, wid in reversed(word_list): x = self.net_embed(my_array([wid], np.int32)) c, q = self.net_encoder(c, x, q) xq_list.insert(0, (text, x, q)) s_list = [] unary_chain = 0 if is_training: loss = my_zeros((), np.float32) # estimate for i in itertools.count(): text, x, q = xq_list[0] if xq_list else ('', EMBED_ZEROS, QUEUE_ZEROS) t1, s1 = s_list[-1] if s_list else (None, STACK_ZEROS) t2, s2 = s_list[-2] if len(s_list) > 1 else (None, STACK_ZEROS) t3, s3 = s_list[-3] if len(s_list) > 2 else (None, STACK_ZEROS) op = self.net_operation(x, q, s1, s2, s3) if is_training: loss += functions.softmax_cross_entropy( op, my_array([op_list[i][0]], np.int32)) op_argmax = op_list[i][0] else: op_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not xq_list: op_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: op_filter[OP_UNARY] = NEG_INF filtered += 1 if len(s_list) < 2: op_filter[OP_BINARY] = NEG_INF filtered += 1 if xq_list or len(s_list) > 1: op_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') op += my_array([op_filter], np.float32) op_argmax = int(cuda.to_cpu(op.data.argmax(1))) if op_argmax == OP_SHIFT: t0 = Tree(None, [text]) s0 = self.net_shift(x, q, s1) xq_list.pop(0) unary_chain = 0 label = self.net_semi_label(s0) elif op_argmax == OP_UNARY: t0 = Tree(None, [t1]) s0 = self.net_unary(q, s1, s2) s_list.pop() unary_chain += 1 label = self.net_phrase_label(s0) elif op_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) s0 = self.net_binary(q, s1, s2, s3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase_label(s0) else: # OP_FINISH break if is_training: loss += functions.softmax_cross_entropy( label, my_array([op_list[i][1]], np.int32)) label_argmax = op_list[i][1] else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, s0)) ''' if is_training: op_est = int(cuda.to_cpu(op.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if op_est == op_list[i][0] else ' ', '*' if label_est == op_list[i][1] else ' ', op_list[i][0], op_list[i][1], op_est, label_est, len(s_list), len(xq_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, _ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward_train(self, word_list, gold_op_list): # check args if not isinstance(word_list, list) or len(word_list) < 1: raise ValueError('Word list is empty.') n_shift = 0 n_binary = 0 for op, _ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not OP_FINISH.') # default values EMBED_ZEROS = XP.fzeros((1, self.n_embed)) CEMBED_ZEROS = XP.fzeros((1, self.n_char_embed)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) SRSTATE_ZEROS = XP.fzeros((1, self.n_srstate)) QUEUE_DEFAULT = ('', EMBED_ZEROS, CEMBED_ZEROS, CEMBED_ZEROS, QUEUE_ZEROS, QUEUE_ZEROS) STACK_DEFAULT = (None, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS) NEG_INF = -1e20 q_list = make_queue(word_list, QUEUE_ZEROS) # estimate s_list = [] zc = SRSTATE_ZEROS z = SRSTATE_ZEROS unary_chain = 0 loss = XP.fzeros(()) for i in itertools.count(): text, x, j, k, a, b = q_list[0] if q_list else QUEUE_DEFAULT t1, sc1, s1, rc1, r1 = s_list[-1] if s_list else STACK_DEFAULT t2, sc2, s2, rc2, r2 = s_list[-2] if len(s_list) >= 2 else STACK_DEFAULT t3, sc3, s3, rc3, r3 = s_list[-3] if len(s_list) >= 3 else STACK_DEFAULT zc, z = self.net_sr(zc, a, b, s1, r1, s2, r2, z) o = self.net_operation(z) loss += functions.softmax_cross_entropy(o, XP.iarray([gold_op_list[i][0]])) o_argmax = gold_op_list[i][0] if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (STACK_ZEROS, self.net_shift(x, j, k, a, b, s1)) rc0, r0 = self.net_stack(rc1, s0, r1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, a, b, s1, s2) rc0, r0 = self.net_stack(rc2, s0, r2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, a, b, s1, s2, s3) rc0, r0 = self.net_stack(rc3, s0, r3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break loss += functions.softmax_cross_entropy(label, XP.iarray([gold_op_list[i][1]])) label_argmax = gold_op_list[i][1] t0.set_label(label_argmax) s_list.append((t0, sc0, s0, rc0, r0)) return loss
def forward(self, word_list, gold_op_list, unary_limit, embed_cache): is_training = gold_op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, *_ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1][0] != OP_FINISH: raise ValueError('Last operation is not OP_FINISH.') # word embedding x_list = [] jk_list = [] for text, wid in word_list: if text in embed_cache: x, jk = embed_cache[text] else: x = self.net_embed(wid) jk = self.net_cembed(text) embed_cache[text] = (x, jk) x_list.append(x) jk_list.append(jk) # forward encoding a_list = [] ac = self.QUEUE_ZEROS a = self.QUEUE_ZEROS for x, (j, k) in zip(x_list, jk_list): ac, a = self.net_forward(ac, x, j, k, a) a_list.append(a) # backward encoding b_list = [] bc = self.QUEUE_ZEROS b = self.QUEUE_ZEROS for x, (j, k) in zip(reversed(x_list), reversed(jk_list)): bc, b = self.net_backward(bc, x, j, k, b) b_list.insert(0, b) q_list = [ (text, x, j, k, a, b) \ for (text, _), x, (j, k), a, b \ in zip(word_list, x_list, jk_list, a_list, b_list)] # estimate s_list = [] zc = self.SRSTATE_ZEROS z = self.SRSTATE_ZEROS unary_chain = 0 if is_training: loss = XP.fzeros(()) for i in itertools.count(): if is_training: gold_op, gold_label, gold_op_vram, gold_label_vram = gold_op_list[ i] text, x, j, k, a, b = q_list[0] if q_list else self.QUEUE_DEFAULT t1, sc1, s1, rc1, r1 = s_list[-1] if s_list else self.STACK_DEFAULT t2, sc2, s2, rc2, r2 = s_list[-2] if len( s_list) >= 2 else self.STACK_DEFAULT t3, sc3, s3, rc3, r3 = s_list[-3] if len( s_list) >= 3 else self.STACK_DEFAULT zc, z = self.net_sr(zc, a, b, s1, r1, s2, r2, z) o = self.net_operation(z) if is_training: loss += functions.softmax_cross_entropy(o, gold_op_vram) o_argmax = gold_op else: o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not q_list: o_filter[OP_SHIFT] = self.NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = self.NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = self.NEG_INF filtered += 1 if q_list or len(s_list) > 1: o_filter[OP_FINISH] = self.NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (self.STACK_ZEROS, self.net_shift(x, j, k, a, b, s1)) rc0, r0 = self.net_stack(rc1, s0, r1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, a, b, s1, s2) rc0, r0 = self.net_stack(rc2, s0, r2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, a, b, s1, s2, s3) rc0, r0 = self.net_stack(rc3, s0, r3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break if is_training: loss += functions.softmax_cross_entropy(label, gold_label_vram) label_argmax = gold_label else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0, rc0, r0)) ''' if is_training: o_est = int(cuda.to_cpu(o.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if o_est == gold_op else ' ', '*' if label_est == gold_label else ' ', gold_op, gold_label, o_est, label_est, len(s_list), len(q_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, *_ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward(self, word_list, op_list, unary_limit): is_training = op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, _ in op_list: if op == OP_SHIFT: n_shift += 1 if op in [OP_PARTIAL, OP_REDUCE]: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), PARTIAL+REDUCE=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not FINISH.') # initial values EMBED_ZEROS = my_zeros((1, self.n_embed), np.float32) QUEUE_ZEROS = my_zeros((1, self.n_queue_state), np.float32) STACK_ZEROS = my_zeros((1, self.n_stack_state), np.float32) NEG_INF = -1e20 # queue encoding xq_list = [] c = QUEUE_ZEROS q = QUEUE_ZEROS for text, wid in reversed(word_list): x = self.net_embed(my_array([wid], np.int32)) c, q = self.net_encoder(c, x, q) xq_list.insert(0, (text, x, q)) s_list = [] # [(tree, state)] unary_chain = 0 if is_training: loss = my_zeros((), np.float32) # estimate for i in itertools.count(): text, x, q = xq_list[0] if xq_list else ('', EMBED_ZEROS, QUEUE_ZEROS) t1, s1 = s_list[-1] if s_list else (None, STACK_ZEROS) t2, s2 = s_list[-2] if len(s_list) > 1 else (None, STACK_ZEROS) t3, s3 = s_list[-3] if len(s_list) > 2 else (None, STACK_ZEROS) p1 = (t1.label() == -1) if t1 is not None else False p2 = (t2.label() == -1) if t2 is not None else False op = self.net_operation(x, q, s1, s2, s3) if is_training: loss += functions.softmax_cross_entropy(op, my_array([op_list[i][0]], np.int32)) op_argmax = op_list[i][0] else: op_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not xq_list or p2: op_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit or p1: op_filter[OP_UNARY] = NEG_INF filtered += 1 if not xq_list or len(s_list) < 2 or p1: op_filter[OP_PARTIAL] = NEG_INF filtered += 1 if len(s_list) < 2 or p1: op_filter[OP_REDUCE] = NEG_INF filtered += 1 if xq_list or len(s_list) > 1: op_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') op += my_array([op_filter], np.float32) op_argmax = int(cuda.to_cpu(op.data.argmax(1))) if op_argmax == OP_SHIFT: t0 = Tree(None, [text]) s0 = self.net_shift(x, q, s1) xq_list.pop(0) unary_chain = 0 label = self.net_semi_label(s0) elif op_argmax == OP_UNARY: t0 = Tree(None, [t1]) s0 = self.net_unary(q, s1, s2) s_list.pop() unary_chain += 1 label = self.net_phrase_label(s0) elif op_argmax == OP_PARTIAL: t0 = Tree(None, [t2, t1]) s0 = self.net_partial(q, s1, s2, s3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_partial_label(s0) elif op_argmax == OP_REDUCE: t0 = Tree(None, [t2, t1]) s0 = self.net_reduce(q, s1, s2, s3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase_label(s0) else: # OP_FINISH break if is_training: loss += functions.softmax_cross_entropy(label, my_array([op_list[i][1]], np.int32)) label_argmax = op_list[i][1] if op_argmax != OP_PARTIAL else -1 else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) if op_argmax != OP_PARTIAL else -1 t0.set_label(label_argmax) s_list.append((t0, s0)) ''' if is_training: op_est = int(cuda.to_cpu(op.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) if op_argmax != OP_PARTIAL else -1 trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if op_est == op_list[i][0] else ' ', '*' if label_est == op_list[i][1] else ' ', op_list[i][0], op_list[i][1], op_est, label_est, len(s_list), len(xq_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, _ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return unbinarize(t0)
def _strip_functional_tags(self, tree: Tree) -> None: clean_label = tree.label().split("=")[0].split("-")[0].split("|")[0] tree.set_label(clean_label) for child in tree: if not isinstance(child[0], str): self._strip_functional_tags(child)
def CYK(self, sentence, verbose=False): """ Parse a sentence or a table of words to get the more likely graph :param sentence: list of words :param verbose: bool print data """ if isinstance(sentence, str): words = sentence.split(" ") else: words = sentence if verbose: print("Original sentence :") print(sentence) self.dic_replacement = {} new_sentence = "" back = [[{} for i in range(len(words) - i)] for i in range(len(words))] log_pr = [[{} for i in range(len(words) - i)] for i in range(len(words))] for k in range(0, len(words)): # Treating OOV : if words[k] not in self.lexicon: liste = closest(words[k], self.lexicon, self.embeddings, self.word_id, self.id_word) if verbose: print(f"{words[k]} is replaced by {liste}") else: liste = [(words[k], 1.0)] if words[k][0].isupper() and words[k].lower() in self.lexicon: liste.append( (words[k].lower(), 0.5)) # Try the lowercase with lower probability # Create the auxiliary sentence that will be treated for i, element in enumerate(liste): word = element[0] if i == 0: new_sentence += word else: new_sentence += "/" + word # Create the first line with self.lexicon for element in liste: proba = element[1] word = element[0] for s in self.lexicon[word]: currentProb = np.log(self.lexicon[word][s]) + np.log(proba) self.dic_replacement[k, word] = words[k] if s not in back[0][k]: log_pr[0][k][s] = (currentProb, 0, k, word) back[0][k][s] = (0, k, word) elif currentProb > log_pr[0][k][s][0]: log_pr[0][k][s] = (currentProb, 0, k, word) back[0][k][s] = (0, k, word) new_sentence += " " if verbose: print("Auxiliary sentence :") print(new_sentence) # If only one words, we reconstruct the tree : if len(words) == 1: result, element = check_Sent(log_pr[0][0]) if result: origin, pos = str(element[0]).split("&", 1) tree = Tree(origin, [Tree(pos, [back[0][0][element][2]])]) return tree else: elementTrue = None proba = -float("inf") for element in back[0][0].keys(): if back[0][0][element][0] > proba: proba = back[0][0][element][0] elementTrue = element tree = Tree( "SENT", [Tree(str(elementTrue[0]), [back[0][0][element][2]])]) return tree # Check the upper cells of the pyramid for i in range( 1, len(words)): # Place in the row of the pyramid (lenght is i+1) for init in range(len(words) - i): # Place in the column of the pyramid for length_init in range(1, i + 1): # Where to split in the sentence length_end = (i + 1) - length_init init_list = back[length_init - 1][init].keys() end_list = back[length_end - 1][init + length_init].keys() for element1 in init_list: for element2 in end_list: inputElement = element1 + element2 if inputElement in self.rules: for s in self.rules[inputElement]: if self.rules[inputElement][ s] == 0: # There should be no element here currentProb = -float("inf") else: currentProb = log_pr[length_init-1][init][element1][0] \ + log_pr[length_end-1][init+length_init][element2][0] \ + np.log(self.rules[inputElement][s]) if s not in back[i][init]: log_pr[i][init][s] = (currentProb, length_init - 1, init, element1, length_end - 1, init + length_init, element2) back[i][init][s] = (length_init - 1, init, element1, length_end - 1, init + length_init, element2) elif currentProb > log_pr[i][init][s][0]: log_pr[i][init][s] = (currentProb, length_init - 1, init, element1, length_end - 1, init + length_init, element2) back[i][init][s] = (length_init - 1, init, element1, length_end - 1, init + length_init, element2) resultParsable, element = check_Sent(log_pr[-1][0]) if not resultParsable: return False else: tree = self.build_tree(back, i, 0, element) tree.set_label("SENT") return tree
def forward_test(self, word_list, unary_limit): # check args if not isinstance(word_list, list) or len(word_list) < 1: raise ValueError('Word list is empty.') if not isinstance(unary_limit, int) or unary_limit < 0: raise ValueError('unary_limit must be non-negative integer.') # default values EMBED_ZEROS = XP.fzeros((1, self.n_embed)) CEMBED_ZEROS = XP.fzeros((1, self.n_char_embed)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) SRSTATE_ZEROS = XP.fzeros((1, self.n_srstate)) QUEUE_DEFAULT = ('', EMBED_ZEROS, CEMBED_ZEROS, CEMBED_ZEROS, QUEUE_ZEROS, QUEUE_ZEROS) STACK_DEFAULT = (None, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS) NEG_INF = -1e20 q_list = make_queue(word_list, QUEUE_ZEROS) # estimate s_list = [] zc = SRSTATE_ZEROS z = SRSTATE_ZEROS unary_chain = 0 for i in itertools.count(): text, x, j, k, a, b = q_list[0] if q_list else QUEUE_DEFAULT t1, sc1, s1, rc1, r1 = s_list[-1] if s_list else STACK_DEFAULT t2, sc2, s2, rc2, r2 = s_list[-2] if len(s_list) >= 2 else STACK_DEFAULT t3, sc3, s3, rc3, r3 = s_list[-3] if len(s_list) >= 3 else STACK_DEFAULT zc, z = self.net_sr(zc, a, b, s1, r1, s2, r2, z) o = self.net_operation(z) o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not q_list: o_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = NEG_INF filtered += 1 if q_list or len(s_list) > 1: o_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (STACK_ZEROS, self.net_shift(x, j, k, a, b, s1)) rc0, r0 = self.net_stack(rc1, s0, r1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, a, b, s1, s2) rc0, r0 = self.net_stack(rc2, s0, r2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, a, b, s1, s2, s3) rc0, r0 = self.net_stack(rc3, s0, r3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0, rc0, r0)) # combine multiple trees if they exists, and return the result. t0, *_ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward_train(self, word_list, gold_op_list): # check args if not isinstance(word_list, list) or len(word_list) < 1: raise ValueError('Word list is empty.') n_shift = 0 n_binary = 0 for op, _ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not OP_FINISH.') # default values EMBED_ZEROS = XP.fzeros((1, self.n_embed)) CEMBED_ZEROS = XP.fzeros((1, self.n_char_embed)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) SRSTATE_ZEROS = XP.fzeros((1, self.n_srstate)) QUEUE_DEFAULT = ('', EMBED_ZEROS, CEMBED_ZEROS, CEMBED_ZEROS, QUEUE_ZEROS, QUEUE_ZEROS) STACK_DEFAULT = (None, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS) NEG_INF = -1e20 q_list = make_queue(word_list, QUEUE_ZEROS) # estimate s_list = [] zc = SRSTATE_ZEROS z = SRSTATE_ZEROS unary_chain = 0 loss = XP.fzeros(()) for i in itertools.count(): text, x, j, k, a, b = q_list[0] if q_list else QUEUE_DEFAULT t1, sc1, s1, rc1, r1 = s_list[-1] if s_list else STACK_DEFAULT t2, sc2, s2, rc2, r2 = s_list[-2] if len( s_list) >= 2 else STACK_DEFAULT t3, sc3, s3, rc3, r3 = s_list[-3] if len( s_list) >= 3 else STACK_DEFAULT zc, z = self.net_sr(zc, a, b, s1, r1, s2, r2, z) o = self.net_operation(z) loss += functions.softmax_cross_entropy( o, XP.iarray([gold_op_list[i][0]])) o_argmax = gold_op_list[i][0] if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (STACK_ZEROS, self.net_shift(x, j, k, a, b, s1)) rc0, r0 = self.net_stack(rc1, s0, r1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, a, b, s1, s2) rc0, r0 = self.net_stack(rc2, s0, r2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, a, b, s1, s2, s3) rc0, r0 = self.net_stack(rc3, s0, r3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break loss += functions.softmax_cross_entropy( label, XP.iarray([gold_op_list[i][1]])) label_argmax = gold_op_list[i][1] t0.set_label(label_argmax) s_list.append((t0, sc0, s0, rc0, r0)) return loss
def forward_test(self, word_list, unary_limit): # check args if not isinstance(word_list, list) or len(word_list) < 1: raise ValueError('Word list is empty.') if not isinstance(unary_limit, int) or unary_limit < 0: raise ValueError('unary_limit must be non-negative integer.') # default values EMBED_ZEROS = XP.fzeros((1, self.n_embed)) CEMBED_ZEROS = XP.fzeros((1, self.n_char_embed)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) SRSTATE_ZEROS = XP.fzeros((1, self.n_srstate)) QUEUE_DEFAULT = ('', EMBED_ZEROS, CEMBED_ZEROS, CEMBED_ZEROS, QUEUE_ZEROS, QUEUE_ZEROS) STACK_DEFAULT = (None, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS) NEG_INF = -1e20 q_list = make_queue(word_list, QUEUE_ZEROS) # estimate s_list = [] zc = SRSTATE_ZEROS z = SRSTATE_ZEROS unary_chain = 0 for i in itertools.count(): text, x, j, k, a, b = q_list[0] if q_list else QUEUE_DEFAULT t1, sc1, s1, rc1, r1 = s_list[-1] if s_list else STACK_DEFAULT t2, sc2, s2, rc2, r2 = s_list[-2] if len( s_list) >= 2 else STACK_DEFAULT t3, sc3, s3, rc3, r3 = s_list[-3] if len( s_list) >= 3 else STACK_DEFAULT zc, z = self.net_sr(zc, a, b, s1, r1, s2, r2, z) o = self.net_operation(z) o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not q_list: o_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = NEG_INF filtered += 1 if q_list or len(s_list) > 1: o_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (STACK_ZEROS, self.net_shift(x, j, k, a, b, s1)) rc0, r0 = self.net_stack(rc1, s0, r1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, a, b, s1, s2) rc0, r0 = self.net_stack(rc2, s0, r2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, a, b, s1, s2, s3) rc0, r0 = self.net_stack(rc3, s0, r3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0, rc0, r0)) # combine multiple trees if they exists, and return the result. t0, *_ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0
def forward(self, word_list, gold_op_list, unary_limit): is_training = gold_op_list is not None # check args if len(word_list) < 1: raise ValueError('Word list is empty.') if is_training: n_shift = 0 n_binary = 0 for op, _ in gold_op_list: if op == OP_SHIFT: n_shift += 1 if op == OP_BINARY: n_binary += 1 if n_shift != len(word_list) or n_binary != len(word_list) - 1: raise ValueError( 'Invalid operation number: SHIFT=%d (required: %d), BINARY=%d (required: %d)' % (n_shift, n_binary, len(word_list), len(word_list) - 1)) if gold_op_list[-1] != (OP_FINISH, None): raise ValueError('Last operation is not OP_FINISH.') # default values EMBED_ZEROS = XP.fzeros((1, self.n_embed)) CEMBED_ZEROS = XP.fzeros((1, self.n_char_embed)) QUEUE_ZEROS = XP.fzeros((1, self.n_queue)) QUEUE_ONES = XP.fones((1, self.n_queue)) STACK_ZEROS = XP.fzeros((1, self.n_stack)) STACK_ONES = XP.fzeros((1, self.n_stack)) SRSTATE_ZEROS = XP.fzeros((1, self.n_srstate)) QUEUE_DEFAULT = ('', EMBED_ZEROS, CEMBED_ZEROS, CEMBED_ZEROS, QUEUE_ZEROS) STACK_DEFAULT = (None, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS, STACK_ZEROS) NEG_INF = -1e20 # word embedding x_list = [self.net_embed(XP.iarray([wid])) for _, wid in word_list] jk_list = [self.net_cembed(text) for text, _ in word_list] # backward encoding b_list = [] bc = QUEUE_ZEROS b = QUEUE_ZEROS bf = XP.dropout(QUEUE_ONES) for x, (j, k) in zip(reversed(x_list), reversed(jk_list)): bc, b = self.net_backward(bc, x, j, k, b) b *= bf b_list.insert(0, b) q_list = [ (text, x, j, k, b) \ for (text, _), x, (j, k), b \ in zip(word_list, x_list, jk_list, b_list)] # estimate s_list = [] zc = SRSTATE_ZEROS z = SRSTATE_ZEROS rf = XP.dropout(STACK_ONES) unary_chain = 0 if is_training: loss = XP.fzeros(()) for i in itertools.count(): text, x, j, k, b = q_list[0] if q_list else QUEUE_DEFAULT t1, sc1, s1, rc1, r1 = s_list[-1] if s_list else STACK_DEFAULT t2, sc2, s2, rc2, r2 = s_list[-2] if len(s_list) >= 2 else STACK_DEFAULT t3, sc3, s3, rc3, r3 = s_list[-3] if len(s_list) >= 3 else STACK_DEFAULT zc, z = self.net_sr(zc, b, r1, z) o = self.net_operation(z) if is_training: loss += functions.softmax_cross_entropy(o, XP.iarray([gold_op_list[i][0]])) o_argmax = gold_op_list[i][0] else: o_filter = [0.0 for _ in range(NUM_OP)] filtered = 0 if not q_list: o_filter[OP_SHIFT] = NEG_INF filtered += 1 if not s_list or unary_chain >= unary_limit: o_filter[OP_UNARY] = NEG_INF filtered += 1 if len(s_list) < 2: o_filter[OP_BINARY] = NEG_INF filtered += 1 if q_list or len(s_list) > 1: o_filter[OP_FINISH] = NEG_INF if filtered == NUM_OP: raise RuntimeError('No possible operation!') o += XP.farray([o_filter]) o_argmax = int(cuda.to_cpu(o.data.argmax(1))) if o_argmax == OP_SHIFT: t0 = Tree(None, [text]) sc0, s0 = (STACK_ZEROS, self.net_shift(x, j, k, b, s1)) rc0, r0 = self.net_stack(rc1, s0, r1) q_list.pop(0) unary_chain = 0 label = self.net_semiterminal(s0) elif o_argmax == OP_UNARY: t0 = Tree(None, [t1]) sc0, s0 = self.net_unary(sc1, b, s1, s2) rc0, r0 = self.net_stack(rc2, s0, r2) s_list.pop() unary_chain += 1 label = self.net_phrase(s0) elif o_argmax == OP_BINARY: t0 = Tree(None, [t2, t1]) sc0, s0 = self.net_binary(sc1, sc2, b, s1, s2, s3) rc0, r0 = self.net_stack(rc3, s0, r3) s_list.pop() s_list.pop() unary_chain = 0 label = self.net_phrase(s0) else: # OP_FINISH break r0 *= rf if is_training: loss += functions.softmax_cross_entropy(label, XP.iarray([gold_op_list[i][1]])) label_argmax = gold_op_list[i][1] else: label_argmax = int(cuda.to_cpu(label.data.argmax(1))) t0.set_label(label_argmax) s_list.append((t0, sc0, s0, rc0, r0)) ''' if is_training: o_est = int(cuda.to_cpu(o.data.argmax(1))) label_est = int(cuda.to_cpu(label.data.argmax(1))) trace('%c %c gold=%d-%2d, est=%d-%2d, stack=%2d, queue=%2d' % ( '*' if o_est == gold_op_list[i][0] else ' ', '*' if label_est == gold_op_list[i][1] else ' ', gold_op_list[i][0], gold_op_list[i][1], o_est, label_est, len(s_list), len(q_list))) ''' if is_training: return loss else: # combine multiple trees if they exists, and return the result. t0, *_ = s_list.pop() if s_list: raise RuntimeError('There exist multiple subtrees!') return t0