//  [python]
def _loss(self, preds, labels):
        """ Get loss

        Args:
            preds:  [BATCH_SIZE, CELL_SIZE, CELL_SIZE, 5 * BOX_PER_CELL + CLASS_NUM]
            labels: [BATCH_SIZE, CELL_SIZE, CELL_SIZE, 5 + CLASS_NUM]

        Returns:

        """

        mask_obj = labels[:, :, :, 0, tf.newaxis]  # [None, CELL_SIZE, CELL_SIZE, 1]
        mask_obj = tf.tile(mask_obj, [1, 1, 1, cfg.BOX_PER_CELL])

        boxes = tf.tile(labels[..., :5], [1, 1, 1, cfg.BOX_PER_CELL])  # [None, CELL_SIZE, CELL_SIZE, 5 * BOX_PER_CELL]

        iou = self._calc_iou(preds[:, :, :, :5 * cfg.BOX_PER_CELL], boxes[:, :, :, :5 * cfg.BOX_PER_CELL]) # [None, CELL_SIZE, CELL_SIZE, BOX_PER_CELL]

        max_iou = tf.reduce_max(iou, [3], keepdims=True)

        response = tf.cast(iou >= max_iou, tf.float32) * mask_obj

        avg_iou = tf.reduce_sum(iou * response) / tf.reduce_sum(response)
        tf.summary.scalar('avg iou', avg_iou)

        # Compute first line
        x_index = np.arange(1, 5 * cfg.BOX_PER_CELL, 5)
        y_index = np.arange(2, 5 * cfg.BOX_PER_CELL, 5)
        coord_loss = cfg.COORD_SCALE * tf.reduce_mean(
            tf.reduce_sum(
                response * (
                        tf.square(preds[..., 1:5*cfg.BOX_PER_CELL:5] - boxes[..., 1:5*cfg.BOX_PER_CELL:5]) +
                        tf.square(preds[..., 2:5*cfg.BOX_PER_CELL:5] - boxes[..., 2:5*cfg.BOX_PER_CELL:5])
                ),
                axis=[1, 2, 3]
            )
        )

        # coord_loss = tf.Print(coord_loss, [coord_loss], "Coord Loss:")

        tf.summary.scalar('coord loss', coord_loss)
        tf.losses.add_loss(coord_loss)


        # Compute second line
        # w_index = np.arange(3, 5 * cfg.BOX_PER_CELL, 5)
        # h_index = np.arange(4, 5 * cfg.BOX_PER_CELL, 5)
        size_loss = cfg.COORD_SCALE * tf.reduce_mean(
            tf.reduce_sum(
                response * (
                    tf.square(preds[..., 3:5*cfg.BOX_PER_CELL:5] - tf.sqrt(boxes[..., 3:5*cfg.BOX_PER_CELL:5])) +
                    tf.square(preds[..., 4:5*cfg.BOX_PER_CELL:5] - tf.sqrt(boxes[..., 4:5*cfg.BOX_PER_CELL:5]))
                    ),
                axis=[1, 2, 3]
            )
        )

        # size_loss = tf.Print(size_loss, [size_loss], "Size Loss:")

        tf.summary.scalar('size loss', size_loss)
        tf.losses.add_loss(size_loss)


        # Compute third line
        # c_index = np.arange(0, 5 * cfg.BOX_PER_CELL, 5)
        obj_loss = tf.reduce_mean(
            tf.reduce_sum(
                response * tf.square(preds[..., 0:5*cfg.BOX_PER_CELL:5] - iou),
                axis=[1, 2, 3]
            )
        )

        # obj_loss = tf.Print(obj_loss, [obj_loss], "Object Loss:")

        tf.summary.scalar('object loss', obj_loss)
        tf.losses.add_loss(obj_loss)


        # Compute forth line
        noobj_loss = cfg.NOOBJ_SCALE * tf.reduce_mean(
            tf.reduce_sum(
                (1 - mask_obj) * tf.square(preds[..., 0:5*cfg.BOX_PER_CELL:5] - 0),
                axis=[1, 2, 3]
            )
        )

        # noobj_loss = tf.Print(noobj_loss, [noobj_loss], "No-Object Loss:")

        tf.summary.scalar('no-object loss', noobj_loss)
        tf.losses.add_loss(noobj_loss)


        # Compute fifth line
        mask_obj = labels[:, :, :, 0, np.newaxis]  # [BATCH_SIZE, CELL_SIZE, CELL_SIZE, 1]
        class_loss = tf.reduce_mean(
            tf.reduce_sum(
                mask_obj * tf.reduce_sum(tf.square(preds[..., -cfg.CLASS_NUM:] - labels[..., -cfg.CLASS_NUM:]), axis=[3], keepdims=True),
                axis=[1, 2, 3]
            )
        )

        # class_loss = tf.Print(class_loss, [class_loss], "Class Loss:")

        tf.summary.scalar('class loss', class_loss)
        tf.losses.add_loss(class_loss)

        return tf.losses.get_total_loss()