//  [python]
def _build_loss(self):
        """Build our cross entropy loss."""

        with tf.variable_scope("Loss", reuse=tf.AUTO_REUSE):

            x_shp = tf.shape(self.x_in)
            # The groundtruth epi sqr
            gt_geod_d = self.y_in[:, :, 0]
            # tf.summary.histogram("gt_geod_d", gt_geod_d)

            # Get groundtruth Essential matrix
            e_gt_unnorm = tf.reshape(tf.matmul(
                tf.reshape(tf_skew_symmetric(self.t_in), (x_shp[0], 3, 3)),
                tf.reshape(self.R_in, (x_shp[0], 3, 3))
            ), (x_shp[0], 9))
            e_gt = e_gt_unnorm / tf.norm(e_gt_unnorm, axis=1, keep_dims=True)

            # e_hat = tf.reshape(tf.matmul(
            #     tf.reshape(t_hat, (-1, 3, 3)),
            #     tf.reshape(r_hat, (-1, 3, 3))
            # ), (-1, 9))

            # Essential matrix loss
            essential_loss = tf.reduce_mean(tf.minimum(
                tf.reduce_sum(tf.square(self.e_hat - e_gt), axis=1),
                tf.reduce_sum(tf.square(self.e_hat + e_gt), axis=1)
            ))
            tf.summary.scalar("essential_loss", essential_loss)

            # Classification loss
            is_pos = tf.cast(
                gt_geod_d < self.config.obj_geod_th, tf.float32
            )
            is_neg = tf.cast(
                gt_geod_d >= self.config.obj_geod_th, tf.float32
            )
            c = is_pos - is_neg
            classif_losses = -tf.log(tf.nn.sigmoid(c * self.logits))

            # balance
            num_pos = tf.nn.relu(tf.reduce_sum(is_pos, axis=1) - 1.0) + 1.0
            num_neg = tf.nn.relu(tf.reduce_sum(is_neg, axis=1) - 1.0) + 1.0
            classif_loss_p = tf.reduce_sum(
                classif_losses * is_pos, axis=1
            )
            classif_loss_n = tf.reduce_sum(
                classif_losses * is_neg, axis=1
            )
            classif_loss = tf.reduce_mean(
                classif_loss_p * 0.5 / num_pos +
                classif_loss_n * 0.5 / num_neg
            )
            tf.summary.scalar("classif_loss", classif_loss)
            tf.summary.scalar(
                "classif_loss_p",
                tf.reduce_mean(classif_loss_p * 0.5 / num_pos))
            tf.summary.scalar(
                "classif_loss_n",
                tf.reduce_mean(classif_loss_n * 0.5 / num_neg))
            precision = tf.reduce_mean(
                tf.reduce_sum(tf.cast(self.logits > 0, tf.float32) * is_pos, axis=1) /
                tf.reduce_sum(tf.cast(self.logits > 0, tf.float32) *
                              (is_pos + is_neg), axis=1)
            )
            tf.summary.scalar("precision", precision)
            recall = tf.reduce_mean(
                tf.reduce_sum(tf.cast(self.logits > 0, tf.float32) * is_pos, axis=1) /
                tf.reduce_sum(is_pos, axis=1)
            )
            tf.summary.scalar("recall", recall)

            # L2 loss
            for var in tf.trainable_variables():
                if "weights" in var.name:
                    tf.add_to_collection("l2_losses", tf.reduce_sum(var**2))
            l2_loss = tf.add_n(tf.get_collection("l2_losses"))
            tf.summary.scalar("l2_loss", l2_loss)

            # Check global_step and add essential loss
            self.loss = self.config.loss_decay * l2_loss
            if self.config.loss_essential > 0:
                self.loss += (
                    self.config.loss_essential * essential_loss * tf.cast(
                        self.global_step >= tf.to_int64(
                            self.config.loss_essential_init_iter), tf.float32))
            if self.config.loss_classif > 0:
                self.loss += self.config.loss_classif * classif_loss

            tf.summary.scalar("loss", self.loss)