//  [python]
def forward(self):
        # out1_norm = tf.sqrt(tf.reduce_sum(tf.square(self.out1), 1))
        # out2_norm = tf.sqrt(tf.reduce_sum(tf.square(self.out2), 1))
        # self.distance = tf.sqrt(tf.reduce_sum(tf.square(self.out1 - self.out2), 1, keepdims=False))
        distance = tf.norm(self.out1-self.out2, ord='euclidean', axis=1, keepdims=False, name='euc-distance')
        distance = tf.divide(distance, tf.add(tf.norm(self.out1, 2, axis=1), tf.norm(self.out2, 2, axis=1)))
        self.sim_euc = tf.subtract(1.0, distance, name="euc")

        # self.sim = tf.reduce_sum(tf.multiply(self.out1, self.out2), 1) / tf.multiply(out1_norm, out2_norm)
        out1_norm = tf.nn.l2_normalize(self.out1, 1)  # output = x / sqrt(max(sum(x**2), epsilon))
        out2_norm = tf.nn.l2_normalize(self.out2, 1)
        self.sim_cos = tf.reduce_sum(tf.multiply(out1_norm, out2_norm), axis=1, name="cosine")
        # sim = exp(-||x1-x2||) range (0, 1]
        # self.sim_ma = tf.exp(-tf.reduce_sum(tf.abs(self.out1 - self.out2), 1), name="manhattan")
        self.sim_ma = tf.exp(-tf.norm(self.out1-self.out2, 1, 1), name="manhattan")

        if self._energy_func == 'euclidean':
            self.sim = self.sim_euc
        elif self._energy_func == 'cosine':
            self.sim = self.sim_cos
        elif self._energy_func == 'exp_manhattan':
            self.sim = self.sim_ma
        elif self._energy_func == 'combine':
            w = tf.Variable(1, dtype=tf.float32)
            self.sim = w * self.sim_euc + (1 - w) * self.sim_cos
        else:
            raise ValueError("Invalid energy function name.")
        self.y_pred = tf.cast(tf.greater(self.sim, self._pred_threshold), dtype=tf.float32, name="y_pred")

        with tf.name_scope("loss"):
            if self._loss_func == 'contrasive':
                self.loss = self.contrastive_loss(self.input_y, self.sim)
            elif self._loss_func == 'cross_entrophy':
                self.loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=self.input_y, logits=self.sim))
            # add l2 reg except bias anb BN variables.
            self.l2 = self._l2_reg_lambda * tf.reduce_sum(
                [tf.nn.l2_loss(v) for v in tf.trainable_variables() if not ("noreg" in v.name or "bias" in v.name)])
            self.loss += self.l2
            if self._encoder_type != 'cnn' and self._rnn_encoder._use_attention:
                self.loss += tf.reduce_mean(self._rnn_encoder.P)

        # Accuracy computation is outside of this class.
        # self.accuracy = tf.reduce_mean(tf.cast(tf.equal(self.y_pred, self.input_y), tf.float32), name="accuracy")
        TP = tf.count_nonzero(self.input_y * self.y_pred, dtype=tf.float32)
        TN = tf.count_nonzero((self.input_y - 1) * (self.y_pred - 1), dtype=tf.float32)
        FP = tf.count_nonzero(self.y_pred * (self.input_y - 1), dtype=tf.float32)
        FN = tf.count_nonzero((self.y_pred - 1) * self.input_y, dtype=tf.float32)
        # tf.div like python2 division, tf.divide like python3
        self.acc = tf.divide(TP + TN, TP + TN + FP + FN, name="accuracy")
        self.precision = tf.divide(TP, TP + FP, name="precision")
        self.recall = tf.divide(TP, TP + FN, name="recall")
        self.cm = tf.confusion_matrix(self.input_y, self.y_pred, name="confusion_matrix")
        # tf.assert_equal(self.acc, self.acc_)
        # https://github.com/tensorflow/tensorflow/issues/15115, be careful!
        # _, self.acc = tf.metrics.accuracy(self.input_y, self.y_pred)
        # _, self.precision = tf.metrics.precision(self.input_y, self.y_pred, name='precision')
        # _, self.recall = tf.metrics.recall(self.input_y, self.y_pred, name='recall')
        self.f1 = tf.divide(2 * self.precision * self.recall, self.precision + self.recall, name="F1_score")