def to_flow(self, fl): spec = self.spec # Specify the encoder. lstm_embeddings = [e.weight.data.numpy() for e in self.lstm_embeddings] lex = LexicalEncoder(fl, spec, lstm_embeddings, self.lr_lstm, self.rl_lstm) # Write the specification to the flow. spec.to_flow(fl) # Adds a flow variable that will store raw indices for the given feature. def index_vars(bldr, feature_spec): return bldr.var(name=feature.name, dtype="int32", shape=[1, feature.num]) # Adds flow variables and ops for the given fixed feature. # The output variable of the feature is added as an input to 'concat_op'. def write_fixed_feature(feature, bag, bldr, concat_op): indices = index_vars(bldr, feature) s = bag.weight.size() embedding = bldr.var(name=feature.name + "_embedding", shape=[s[0], s[1]]) embedding.data = bag.weight.data.numpy() name = feature.name + '/GatherSum' embedded = bldr.gather_sum(embedding, indices, name=name) concat_op.add_input(embedded) # Finishes the concatenation op assuming all inputs have been added. def finish_concat_op(bldr, op): op.add_attr("N", len(op.inputs)) axis = bldr.const(1, "int32") op.add_input(axis) # Specify the FF trunk = FF feature vector + hidden layer computation. ff = builder.Builder(fl, "ff_trunk") ff_input = ff.var(name="input", shape=[1, spec.ff_input_dim]) flow_ff = flownn.FF( ff, \ input=ff_input, \ layers=[spec.ff_hidden_dim], hidden=0) flow_ff.set_layer_data(0, self.ff_layer.weight.data.numpy(), \ self.ff_layer.bias.data.numpy()) ff_concat_op = ff.rawop(optype="ConcatV2", name="concat") ff_concat_op.add_output(ff_input) # Add link variable to the given connector. def link(bldr, name, dim, cnx, prefix=True): if prefix: name = "link/" + name l = bldr.var(name, shape=[-1, dim]) l.ref = True cnx.add(l) return l # Add links to the two LSTMs. ff_lr = link(ff, "lr_lstm", spec.lstm_hidden_dim, lex.lr_lstm.cnx_hidden) ff_rl = link(ff, "rl_lstm", spec.lstm_hidden_dim, lex.rl_lstm.cnx_hidden) # Add link and connector for previous FF steps. ff_cnx = ff.cnx("step", args=[]) ff_steps = link(ff, "steps", spec.ff_hidden_dim, ff_cnx, False) ff_cnx.add(flow_ff.hidden_out) # Add FF's input variables. for feature in spec.ff_fixed_features: write_fixed_feature(feature, feature.bag, ff, ff_concat_op) for feature in spec.ff_link_features: indices = index_vars(ff, feature) activations = None n = feature.name if n == "frame-end-lr" or n == "lr" or n == "mark-lr": activations = ff_lr elif n == "frame-end-rl" or n == "rl" or n == "mark-rl": activations = ff_rl elif n in ["frame-creation-steps", "frame-focus-steps", \ "history", "mark-step"]: activations = ff_steps else: raise ValueError("Unknown feature %r" % n) activation_dim = activations.shape[1] name = feature.name + "/Gather" oov_var = ff.var(name=name + "/oov", shape=[1, activation_dim]) oov_var.data = feature.transform.oov.data.numpy() gathered = ff.gather(activations, indices, oov_var, name=name) projection = feature.transform.projection.weight sz = projection.size() transform = ff.var(name=feature.name + "/transform", shape=[sz[0], sz[1]]) transform.data = projection.data.numpy() name = feature.name + "/MatMul" output = ff.matmul(gathered, transform, name=name) ff_concat_op.add_input(output) finish_concat_op(ff, ff_concat_op) # Specify one cell per FF head (= delegate). ff_trunk_width = flow_ff.hidden_out.shape[1] delegate_cell_prefix = "delegate" for i, head in enumerate(self.ff_heads): delegate = spec.cascade.delegates[i] assert_softmax_delegate(delegate) d = builder.Builder(fl, delegate_cell_prefix + str(i)) head_input = link(d, "input", ff_trunk_width, ff_cnx, False) W = d.var("W", shape=[ff_trunk_width, delegate.size()]) W.data = head.softmax.weight.data.numpy() output = d.matmul(head_input, W) output.type = W.type output.shape = [1, delegate.size()] b = d.var("b", shape=[1, delegate.size()]) b.data = head.softmax.bias.data.numpy() logits = d.add(output, b) logits.type = b.type logits.shape = [1, delegate.size()] best_op = d.rawop(optype="ArgMax") best_op.add_input(logits) best = d.var("output") best.type = builder.DT_INT best.shape = [1] best_op.add_output(best) best.producer.add_attr("output", 1)
def __init__(self, flow, spec, lstm_feature_embeddings, lr_lstm, rl_lstm): # Add blobs for the lexical resources. lexicon = flow.blob("lexicon") lexicon.type = "dict" lexicon.add_attr("delimiter", 10) lexicon.add_attr("oov", spec.words.oov_index) normalization = "" if spec.words.normalize_digits: normalization = "d" lexicon.add_attr("normalization", normalization) lexicon.data = str(spec.words) + "\n" self.lexicon_blob = lexicon def read_file(filename): fin = open(filename, "rb") data = fin.read() fin.close() return data f = tempfile.NamedTemporaryFile(delete=False) fname = f.name spec.commons.save(fname, binary=True) f.close() commons = flow.blob("commons") commons.type = "frames" commons.data = read_file(fname) os.unlink(fname) self.commons_blob = commons suffix = flow.blob("suffixes") suffix.type = "affix" suffix.data = str(spec.write_suffix_table()) self.suffix_blob = suffix # Add feature extraction related ops. bldr = builder.Builder(flow, "features") self.feature_ids = [] concat_args = [] for f, e in zip(spec.lstm_features, lstm_feature_embeddings): shape = [f.vocab_size, f.dim] embedding = bldr.var(name=f.name + "_embeddings", shape=shape) embedding.data = e ids_input = bldr.var(name=f.name, dtype="int32", shape=[1, f.num]) self.feature_ids.append(ids_input) gather_op_type = "Gather" if f.num > 1: gather_op_type = "GatherSum" gather_op = bldr.rawop(gather_op_type) gather_op.dtype = "float32" gather_op.add_input(embedding) gather_op.add_input(ids_input) gather_output = bldr.var(gather_op.name + ":0", "float32", [1, f.dim]) gather_op.add_output(gather_output) concat_args.append(gather_output) self.feature_vector = bldr.concat(concat_args) bldr.rename(self.feature_vector, "feature_vector") self.feature_vector.ref = True self.feature_vector.input = True self.feature_vector.output = True # Add BiLSTM. lr = builder.Builder(flow, "lstm/lr") lr_input = lr.var(name="input", shape=[1, spec.lstm_input_dim]) lr_input.ref = True flow_lr_lstm = nn.LSTM(lr, input=lr_input, size=spec.lstm_hidden_dim) lr_lstm.copy_to_flow_lstm(flow_lr_lstm) self.lr_lstm = flow_lr_lstm rl = builder.Builder(flow, "lstm/rl") rl_input = rl.var(name="input", shape=[1, spec.lstm_input_dim]) rl_input.ref = True flow_rl_lstm = nn.LSTM(rl, input=rl_input, size=spec.lstm_hidden_dim) rl_lstm.copy_to_flow_lstm(flow_rl_lstm) self.rl_lstm = flow_rl_lstm cnxin = flow.cnx("features") cnxin.add(self.feature_vector) cnxin.add(lr_input) cnxin.add(rl_input)