Guest User

Untitled

a guest
Mar 29th, 2017
835
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.97 KB | None | 0 0
  1. import tensorflow as tf
  2. import numpy as np
  3. import dio
  4. import seq2seq
  5.  
  6.  
  7. OPTIMIZERS = {"rmsprop": tf.train.RMSPropOptimizer,
  8.               "adadelta": tf.train.AdadeltaOptimizer,
  9.               "adagrad": tf.train.AdagradOptimizer,
  10.               "momentum": tf.train.MomentumOptimizer,
  11.               "adam": tf.train.AdamOptimizer,
  12.               "sgd": tf.train.GradientDescentOptimizer}
  13.  
  14. ACTIVATIONS = {"sigmoid": tf.sigmoid,
  15.                "relu": tf.nn.relu,
  16.                "tanh": tf.nn.tanh,
  17.                "none": lambda x: x}
  18.  
  19.  
  20. def bilstm(inputs, n_hidden, sequence_lengths, activation, dropout_rate=None):
  21.     """
  22.    Creates intermediate biLSTM layer with specified properties. In Tensorflow
  23.    lingo, it creates the ops needed to run input through this layer (especially
  24.    the `outputs` and `dropouts` ops
  25.    :param inputs:
  26.    :param n_hidden:
  27.    :param sequence_lengths:
  28.    :param activation:
  29.    :param dropout_rate:
  30.    :return:
  31.    """
  32.     if type(inputs) == tuple:  # output from lower biLSTM
  33.         inputs = tf.concat(inputs, axis=2, name="concatenated_input")
  34.  
  35.     with tf.variable_scope('forward'):
  36.         cell_fw = tf.contrib.rnn.LSTMCell(n_hidden, state_is_tuple=True,
  37.                                           activation=activation)
  38.     with tf.variable_scope('backward'):
  39.         cell_bw = tf.contrib.rnn.LSTMCell(n_hidden, state_is_tuple=True,
  40.                                           activation=activation)
  41.     # get layer output op
  42.     outputs, states = tf.nn.bidirectional_dynamic_rnn(
  43.                                         cell_fw, cell_bw, inputs,
  44.                                         dtype=tf.float32,
  45.                                         sequence_length=sequence_lengths)
  46.     dropouts = outputs
  47.     # wrap dropout operation around
  48.     if dropout_rate is not None:
  49.         if type(outputs) == tuple:  # in case of bidirectional LSTM
  50.             dropouts = tuple([tf.nn.dropout(o, keep_prob=1-dropout_rate,
  51.                                             name="dropouts") for o in outputs])
  52.         else:
  53.             dropouts = tf.nn.dropout(outputs, keep_prob=1-dropout_rate,
  54.                                      name="dropouts")
  55.     return dropouts, states
  56.  
  57.  
  58.  
  59. def projection(inputs, y, sequence_lengths, class_weights):
  60.     """
  61.    Used for sequence labeling tasks, makes a dense projection of inputs to
  62.    labels
  63.    :param inputs:
  64.    :param y:
  65.    :param sequence_lengths:
  66.    :param class_weights:
  67.    :return:
  68.    """
  69.     if type(inputs) == tuple:  # concat fw and bw states
  70.         inputs = tf.concat(inputs, axis=2, name="input_concat")
  71.     batch_size, timesteps, n_hidden = [int(d) for d in inputs.get_shape()]
  72.     n_classes = len(class_weights)
  73.     # output projection, projects from hidden states to outputs
  74.     w = tf.get_variable("weights", [n_hidden, n_classes],
  75.                         initializer=xavier_init(n_hidden, n_classes))
  76.     b = tf.get_variable("biases", [n_classes],
  77.                         initializer=xavier_init(1, n_classes))
  78.  
  79.     # Generate predictions
  80.     inputs_flat = tf.reshape(inputs, [-1, n_hidden])
  81.     logits_flat = tf.nn.xw_plus_b(inputs_flat, w, b)
  82.     preds_flat = tf.nn.softmax(logits_flat, name="preds_flat")
  83.     # Return predictions as [batch, timesteps, classes]
  84.     preds = tf.reshape(preds_flat, [batch_size, timesteps, n_classes],
  85.                        name="preds")
  86.  
  87.     # Computing masked cross-entropy loss
  88.     y_flat = tf.reshape(y, [-1], name="y_flat")
  89.     y_onehot = tf.one_hot(y_flat, depth=n_classes, name="y_flat_onehot")
  90.     losses = tf.nn.softmax_cross_entropy_with_logits(
  91.         logits=logits_flat, labels=y_onehot)
  92.  
  93.     # preds, losses = tf.contrib.learn.ops.softmax_classifier(
  94.     #     inputs, y_onehot, w, b, class_weight=class_weights)
  95.  
  96.     mask = tf.sign(tf.to_float(y_flat))  # 0 for PAD (PAD = 0), 1 for all others
  97.     masked_losses = mask * losses  # make loss for all PAD zero
  98.     # Bring back to [batch_size, timesteps] shape
  99.     masked_losses = tf.reshape(masked_losses, [batch_size, timesteps],
  100.                                name="masked_losses")
  101.     # Calculate mean loss per example in batch
  102.     mean_loss_by_example = tf.truediv(  # divide timestep-loss sum by seq_lens
  103.         tf.reduce_sum(masked_losses, axis=1),
  104.         tf.cast(sequence_lengths, tf.float32), name="mean_loss_by_ex"
  105.     )
  106.     # Finally, average loss over examples in batch
  107.     loss = tf.reduce_mean(mean_loss_by_example, name="batch_mean_loss")
  108.     return preds, loss
  109.  
  110.  
  111.  
  112. class SeqMtlModel:
  113.     """
  114.    Model for sequence multitask learning.
  115.    """
  116.     def __init__(self, tasks, input_size, num_layers, hid_dims, optimizer,
  117.                  actfunc, timesteps=50, dropout_rate=0.1, learning_rate=0.1,
  118.                  batch_size=64, embed_size=0, device='/cpu:0',
  119.                  pretrained_embeddings=None, weighted_costs=False):
  120.         """
  121.        :param tasks:
  122.        :param input_size: only relevant if not embed
  123.        :param num_layers:
  124.        :param hid_dims:
  125.        :param optimizer:
  126.        :param actfunc:
  127.        :param timesteps:
  128.        :param dropout_rate:
  129.        :param learning_rate:
  130.        :param batch_size:
  131.        :param embed_size:
  132.        """
  133.         # The input placeholder, expects either IDs (if embed==True) or
  134.         # vectors (pre-trained embeddings or one-hots)
  135.         if embed_size > 0 or pretrained_embeddings is not None:
  136.             self.X_in = tf.placeholder(tf.int32, (batch_size, timesteps),
  137.                                        name="X_in")
  138.         else:
  139.             self.X_in = tf.placeholder(
  140.                 tf.float32, (batch_size, timesteps, input_size), name="X_in")
  141.         # The following are registries for different operations per task
  142.         # Each dict maps tasks to appropriate tf operations as registered below
  143.         self.preds = {}
  144.         self.losses = {}
  145.         self.ys = {}
  146.  
  147.         # Some utilities
  148.         self.optimizers = {}
  149.         self.task2layer = {}
  150.         self.task2tasktype = {}
  151.         self.layer_states = []  # holds states for each intermediate layer
  152.         self.layer_outputs = []  # holds output ops for each intermediate layer
  153.         self.global_step = tf.Variable(0, trainable=False, name="global_step")
  154.         self.dropout_rate_val = dropout_rate
  155.         self.dropout_rate_op = tf.placeholder(tf.float32, name="dropout_rate")
  156.         self.sequence_lengths = tf.placeholder(tf.int32, batch_size,
  157.                                                name="sequence_lengths")
  158.  
  159.         print("=====================================")
  160.         with tf.device(device):
  161.             # # # INPUT LAYER # # #
  162.             if pretrained_embeddings is not None:
  163.                 print("Creating trainable embedding layer initialized with "
  164.                       "provided pretrained embeddings.")
  165.                 emb_matrix = tf.get_variable(
  166.                     name="embed_matrix",
  167.                     shape=pretrained_embeddings.shape,
  168.                     initializer=tf.constant_initializer(pretrained_embeddings),
  169.                     trainable=True)  # allow updating embeddings task-specifically
  170.                 output = tf.nn.embedding_lookup(emb_matrix, self.X_in,
  171.                                                 name="X_embedded")
  172.             elif embed_size > 0:  # learn embed matrix from indices to embeddings
  173.                 print("Creating embedding layer mapping inputs to embeddings "
  174.                       "of length {}.".format(embed_size))
  175.                 emb_matrix = tf.get_variable(
  176.                     name="embed_matrix",
  177.                     shape=[input_size, embed_size], dtype=tf.float32,
  178.                     initializer=xavier_init(input_size, embed_size))
  179.                 output = tf.nn.embedding_lookup(emb_matrix, self.X_in,
  180.                                                 name="X_embedded")
  181.             else:  # use provided vectors (pre-trained embeddings or one-hots)
  182.                 output = self.X_in
  183.             self.layer_states.append(None)
  184.             self.layer_outputs.append(output)
  185.  
  186.             # # # INTERMEDIATE LAYERS # # #
  187.             print("Creating stacked biLSTM of {} layers with {} hidden units."
  188.                   .format(num_layers, hid_dims))
  189.             for i in range(num_layers):
  190.                 activation = ACTIVATIONS.get(actfunc)
  191.                 layer_input = self.layer_outputs[-1]
  192.                 with tf.variable_scope("layer_{}".format(i+1), reuse=None):
  193.                     output, states = bilstm(layer_input, hid_dims,
  194.                                             self.sequence_lengths, activation,
  195.                                             self.dropout_rate_op)
  196.                 self.layer_states.append(states)
  197.                 self.layer_outputs.append(output)
  198.                 # dropouts from previous layer are input to next layer
  199.                 # layer_input = dropouts
  200.  
  201.             # # # TASK OUTPUTS # # #
  202.             # Register tasks at layers
  203.             for task_id, task in tasks.items():
  204.                 layer = task.layer
  205.                 if layer > num_layers:
  206.                     print("Warning! Task was to be registered at layer {}, but "
  207.                           "model only has {} layers. Using top layer instead.".
  208.                           format(layer, num_layers))
  209.                     layer = num_layers
  210.                 print("Registering task '{}' (type '{}', {} classes) at LSTM "
  211.                       "layer {}.".format(task_id, task.task_type,
  212.                                          task.get_num_labels(), layer))
  213.                 try:
  214.                     layer_input = self.layer_outputs[layer]
  215.                 except IndexError:
  216.                     import sys
  217.                     sys.stderr.write("Error: Trying trying to register task, not "
  218.                                      "enough hidden layers (expected at least {}, "
  219.                                      "only {} present.)".format(layer, num_layers))
  220.                 layer_y, pred, loss, opt = None, None, None, None
  221.                 loss = None
  222.                 n_classes = task.get_num_labels()
  223.                 with tf.variable_scope("output_{}".format(task_id), reuse=None):
  224.                     if task.task_type == "lbl":
  225.                         class_weights = task.get_class_weights() if weighted_costs \
  226.                             else np.ones(n_classes)
  227.                         # print("  Class weights: ", class_weights)
  228.                         layer_y = tf.placeholder(tf.int32,
  229.                                                  (batch_size, timesteps),
  230.                                                  name="labels")
  231.                         pred, loss = projection(layer_input, layer_y,
  232.                                                 self.sequence_lengths,
  233.                                                 class_weights)
  234.                     elif task.task_type == "seq":
  235.                         init_state = self.layer_states[layer]
  236.                         layer_y = tf.placeholder(tf.int32,
  237.                                                  (batch_size, timesteps),
  238.                                                  name="labels")
  239.                         pred_tr, pred, loss = decoder_seq2seq(
  240.                             layer_input, init_state, layer_y, hid_dims, n_classes,
  241.                             self.sequence_lengths, batch_size, None)
  242.                     elif task.task_type == "cls":
  243.                         layer_y = tf.placeholder(tf.int32, (batch_size, 1),
  244.                                                  name="labels")
  245.                         pred, loss = classifier(layer_input, layer_y, n_classes)
  246.                     else:
  247.                         raise ValueError("Illegal task type '{}'. Only 'lbl' and "
  248.                                          "'seq' supported.".format(task.task_type))
  249.                 optmzr = OPTIMIZERS.get(optimizer)(learning_rate=learning_rate)
  250.                 opt = optmzr.minimize(loss)
  251.                 # Register operations for tasks
  252.                 self.ys[task_id] = layer_y
  253.                 self.preds[task_id] = pred
  254.                 self.losses[task_id] = loss
  255.                 self.optimizers[task_id] = opt
  256.         print("=====================================")
  257.         self.saver = tf.train.Saver(tf.global_variables())
  258.  
  259.     def step(self, session, task, x, input_lengths, y=None, mode="train"):
  260.         """
  261.        Performs a model step. Performs different sequence of operations
  262.        (computing predictions/loss, optimizing) depending on mode.
  263.        :param session:
  264.        :param task:
  265.        :param x:
  266.        :param input_lengths:
  267.        :param y:
  268.        :param mode: any of 'train', 'eval', 'decode'.
  269.        :return:
  270.        """
  271.         pred = self.preds[task.task_id]
  272.         optimizer = self.optimizers[task.task_id]
  273.         loss = self.losses[task.task_id]
  274.         gold = self.ys[task.task_id]
  275.  
  276.         l = None
  277.         if mode == "decode":
  278.             feed = {self.X_in: x, self.sequence_lengths: input_lengths,
  279.                     self.dropout_rate_op: 0}
  280.             p = session.run(pred, feed_dict=feed)
  281.         elif mode == "eval":
  282.             assert (y is not None), "Need to provide gold sequence y " \
  283.                                     "when evaluating"
  284.             feed = {self.X_in: x, gold: y, self.sequence_lengths: input_lengths,
  285.                     self.dropout_rate_op: 0}
  286.             p, l = session.run([pred, loss], feed_dict=feed)
  287.         elif mode == "train":
  288.             assert (y is not None), "Need to provide gold sequence y " \
  289.                                     "when training"
  290.             step_incr = tf.assign_add(self.global_step, 1)
  291.             feed = {self.X_in: x, gold: y, self.sequence_lengths: input_lengths,
  292.                     self.dropout_rate_op: self.dropout_rate_val}
  293.             p, l, _, _ = session.run([pred, loss, optimizer, step_incr],
  294.                                      feed_dict=feed)
  295.         else:
  296.             raise ValueError("Illegal step mode '{}'. Valid modes are 'train', "
  297.                              "'decode' and 'eval'.")
  298.         return p, l
Advertisement
Add Comment
Please, Sign In to add comment