import tensorflow as tf

        rel_embedding_shape = [rel_cnt, self.embedding_size * self.embedding_size]
        entity_init = tf.truncated_normal(entity_embedding_shape, stddev=init_sd)
        rel_init = tf.truncated_normal(rel_embedding_shape, stddev=init_sd)
        if self.maxnorm is not None:
            # Ensure maxnorm constraints are initially satisfied
            entity_init = dense_maxnorm(entity_init, self.maxnorm)
            rel_init = dense_maxnorm(rel_init, self.maxnorm)
        self.entity_embedding_vars = tf.Variable(entity_init)
        self.rel_embedding_vars = tf.Variable(rel_init)
        # Embedding layer for each (head, rel, tail) triple being fed in as input
        head_embed = tf.nn.embedding_lookup(self.entity_embedding_vars, self.head_input)
        tail_embed = tf.nn.embedding_lookup(self.entity_embedding_vars, self.tail_input)
        rel_embed = tf.nn.embedding_lookup(self.rel_embedding_vars, self.rel_input)
        # Reshape rel_embed into square D x D matrices
        rel_embed_square = tf.reshape(rel_embed, (-1, self.embedding_size, self.embedding_size))
        # Reshape head_embed and tail_embed to be suitable for the matrix multiplication
        head_embed_row = tf.expand_dims(head_embed, 1) # embeddings as row vectors
        tail_embed_col = tf.expand_dims(tail_embed, 2) # embeddings as column vectors
        head_rel_mult = tf.batch_matmul(head_embed_row, rel_embed_square)
        # Output needs a squeeze into a 1d vector
        raw_output = tf.squeeze(tf.batch_matmul(head_rel_mult, tail_embed_col)) 
        self.output, self.loss = self._create_output_and_loss(raw_output)
        # Optimization
        self.train_step = self.opt.minimize(self.loss)
