//  [python]
def build_traininig_model(self):
        """
        Neural network that is used for training. Along with the evaluation of a triplet,
        the evaluation of a corrupted triplet is calculated as well so that we can calulcate
        the contrastive max margin loss.

        Returns:
            train_predictions: concatenation of correct output in
                1st column and corrupted output in the 2nd column
        """
        log.info('Building the network to be used for training...')

        # lookup word embeddings
        pred_emb, entity_emb = self._lookup_embeddings()

        # split the input
        sub, pred, obj, corrupt = tf.split(tf.cast(self.train_triplets, tf.int32), 4, 1)

        # for each term of each sample, select the required embedding
        # and remove the extra dimension caused by the selection
        sub_emb = tf.squeeze(tf.nn.embedding_lookup(entity_emb, sub))
        pred_emb = tf.squeeze(tf.nn.embedding_lookup(pred_emb, pred))
        obj_emb = tf.squeeze(tf.nn.embedding_lookup(entity_emb, obj))
        corrupt_emb = tf.squeeze(tf.nn.embedding_lookup(entity_emb, corrupt))
        sub_correct_emb = sub_emb
        obj_correct_emb = obj_emb

        # create a corrupt triplet, either corrupting the head or tail entity based on flip boolean
        sub_corrupted_emb, obj_corrupt_emb = tf.cond(
            self.flip_placeholder,
            lambda: (sub_emb, corrupt_emb),
            lambda: (corrupt_emb, obj_emb))

        # calculation of the first layer involves concatenating the three
        # embeddings for each sample and multipling it by the weight vector
        correct_pre_act = tf.add(
            tf.matmul(
                tf.concat([sub_correct_emb, pred_emb, obj_correct_emb], 1),
                self.weights['C']),
            self.biases['b'])
        corrupted_pre_act = tf.add(
            tf.matmul(
                tf.concat([sub_corrupted_emb, pred_emb, obj_corrupt_emb], 1),
                self.weights['C']),
            self.biases['b'])

        # add more layers if necessary
        if self.params['add_layers'] > 0:
            for i in range(1, self.params['add_layers'] + 1):
                correct_post_act = tf.nn.relu(correct_pre_act)
                corrupted_post_act = tf.nn.relu(corrupted_pre_act)

                correct_dropout = tf.nn.dropout(
                    correct_post_act,
                    self.params['drop_out_percent'])
                corrupted_dropout = tf.nn.dropout(
                    corrupted_post_act,
                    self.params['drop_out_percent'])

                correct_pre_act = tf.add(
                    tf.matmul(correct_dropout, self.weights['C{}'.format(i)]),
                    self.biases['b{}'.format(i)])
                corrupted_pre_act = tf.add(
                    tf.matmul(corrupted_dropout, self.weights['C{}'.format(i)]),
                    self.biases['b{}'.format(i)])

        if self.params['act_function'] == 0:
            # tanh
            log.debug('Using tanh for pre-final layer activation')
            pre_final_correct = tf.tanh(correct_pre_act)
            pre_final_corrupted = tf.tanh(corrupted_pre_act)
        else:
            # sigmoid
            log.debug('Using sigmoid for pre-final layer activation')
            pre_final_correct = tf.sigmoid(correct_pre_act)
            pre_final_corrupted = tf.sigmoid(corrupted_pre_act)

        if self.params['add_layers'] > 0:
            pre_final_correct = tf.nn.dropout(pre_final_correct, self.params['drop_out_percent'])
            pre_final_corrupted = tf.nn.dropout(
                pre_final_corrupted, self.params['drop_out_percent'])

        out_correct_pre_act = tf.matmul(pre_final_correct, self.weights['B'])
        out_corrupted_pre_act = tf.matmul(pre_final_corrupted, self.weights['B'])

        out_correct = tf.sigmoid(out_correct_pre_act)
        out_corrupted = tf.sigmoid(out_corrupted_pre_act)

        # given batch_size = 5,000 and corrupt_size = 100
        # self.train_predictions will have shape (500,000 x 2)
        self.train_predictions = tf.concat(
            [out_correct, out_corrupted],
            axis=1,
            name='build_traininig_model')

        return self.train_predictions