loss.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import os
  2. import sys
  3. import tensorflow as tf
  4. import keras.backend as K
  5. from tensorflow.python.ops.control_flow_ops import while_loop
  6. sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../")
  7. sys.path.append(os.path.dirname(os.path.abspath(__file__)))
  8. from click_captcha.utils import box_iou
  9. from click_captcha.post_process import yolo_head
  10. def contrastive_loss(y_true, y_pred):
  11. """Contrastive loss from Hadsell-et-al.'06
  12. http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf
  13. """
  14. margin = 1
  15. square_pred = K.square(y_pred)
  16. margin_square = K.square(K.maximum(margin - y_pred, 0))
  17. return K.mean(y_true * square_pred + (1 - y_true) * margin_square)
  18. def focal_loss(gamma=3., alpha=.5, only_tf=True):
  19. def focal_loss_fixed(y_true, y_pred):
  20. pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
  21. pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred))
  22. if only_tf:
  23. return - tf.reduce_sum(alpha * tf.pow(1. - pt_1, gamma) * tf.math.log(1e-07 + pt_1)) \
  24. - tf.reduce_sum((1 - alpha) * tf.pow(pt_0, gamma) * tf.math.log(1. - pt_0 + 1e-07))
  25. else:
  26. return - K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(K.epsilon()+pt_1)) \
  27. - K.sum((1 - alpha) * K.pow(pt_0, gamma) * K.log(1. - pt_0 + K.epsilon()))
  28. return focal_loss_fixed
  29. def l1_loss():
  30. def mae(y_true, y_pred):
  31. return tf.reduce_mean(tf.abs(y_pred-y_true)) * 100
  32. return mae
  33. def l2_loss():
  34. def mse(y_true, y_pred):
  35. return tf.reduce_mean(tf.square(y_true - y_pred))
  36. return mse
  37. def l2_focal_loss(threshold=0.2):
  38. def mse(y_true, y_pred):
  39. y_minus = tf.where(tf.abs(y_pred-y_true) <= threshold, tf.abs(y_pred-y_true), 1000*tf.abs(y_pred-y_true))
  40. return tf.reduce_mean(tf.square(y_minus))
  41. return mse
  42. def l1_focal_loss(threshold=0.2):
  43. def mae(y_true, y_pred):
  44. y_minus = tf.where(tf.abs(y_pred-y_true) <= threshold, 0., tf.abs(y_pred-y_true))
  45. return tf.reduce_sum(tf.abs(y_minus))
  46. return mae
  47. def l3_loss():
  48. def l3_loss_fixed(y_true, y_pred):
  49. return tf.reduce_mean(tf.abs(tf.pow(y_pred-y_true, 3)))
  50. return l3_loss_fixed
  51. def yolo_loss(args, anchors, num_classes, ignore_thresh=.5, print_loss=False):
  52. """Return yolo_loss tensor
  53. Parameters
  54. ----------
  55. yolo_outputs: list of tensor, the output of yolo_body or tiny_yolo_body
  56. y_true: list of array, the output of preprocess_true_boxes
  57. anchors: array, shape=(N, 2), wh
  58. num_classes: integer
  59. ignore_thresh: float, the iou threshold whether to ignore object confidence loss
  60. Returns
  61. -------
  62. loss: tensor, shape=(1,)
  63. """
  64. from keras import backend as K
  65. # default setting
  66. num_layers = len(anchors)//3
  67. yolo_outputs = args[:num_layers]
  68. y_true = args[num_layers:]
  69. anchor_mask = [[6, 7, 8], [3, 4, 5], [0, 1, 2]] if num_layers == 3 else [[3, 4, 5], [1, 2, 3]]
  70. input_shape = K.cast(K.shape(yolo_outputs[0])[1:3] * 32, K.dtype(y_true[0]))
  71. grid_shapes = [K.cast(K.shape(yolo_outputs[l])[1:3], K.dtype(y_true[0])) for l in range(num_layers)]
  72. loss = 0
  73. # batch size, tensor
  74. m = K.shape(yolo_outputs[0])[0]
  75. mf = K.cast(m, K.dtype(yolo_outputs[0]))
  76. for l in range(num_layers):
  77. object_mask = y_true[l][..., 4:5]
  78. true_class_probs = y_true[l][..., 5:]
  79. grid, raw_pred, pred_xy, pred_wh = yolo_head(yolo_outputs[l],
  80. anchors[anchor_mask[l]], num_classes, input_shape, calc_loss=True)
  81. pred_box = K.concatenate([pred_xy, pred_wh])
  82. # Darknet raw box to calculate loss.
  83. raw_true_xy = y_true[l][..., :2]*grid_shapes[l][::-1] - grid
  84. raw_true_wh = K.log(y_true[l][..., 2:4] / anchors[anchor_mask[l]] * input_shape[::-1])
  85. # avoid log(0)=-inf
  86. raw_true_wh = K.switch(object_mask, raw_true_wh, K.zeros_like(raw_true_wh))
  87. box_loss_scale = 2 - y_true[l][..., 2:3]*y_true[l][..., 3:4]
  88. # Find ignore mask, iterate over each of batch.
  89. ignore_mask = tf.TensorArray(K.dtype(y_true[0]), size=1, dynamic_size=True)
  90. object_mask_bool = K.cast(object_mask, 'bool')
  91. def loop_body(b, ignore_mask):
  92. true_box = tf.boolean_mask(y_true[l][b, ..., 0:4], object_mask_bool[b,...,0])
  93. iou = box_iou(pred_box[b], true_box)
  94. best_iou = K.max(iou, axis=-1)
  95. ignore_mask = ignore_mask.write(b, K.cast(best_iou<ignore_thresh, K.dtype(true_box)))
  96. return b+1, ignore_mask
  97. _, ignore_mask = while_loop(lambda b, *args: b < m, loop_body, [0, ignore_mask])
  98. ignore_mask = ignore_mask.stack()
  99. ignore_mask = K.expand_dims(ignore_mask, -1)
  100. # K.binary_crossentropy is helpful to avoid exp overflow.
  101. xy_loss = object_mask * box_loss_scale * K.binary_crossentropy(raw_true_xy, raw_pred[..., 0:2], from_logits=True)
  102. wh_loss = object_mask * box_loss_scale * 0.5 * K.square(raw_true_wh-raw_pred[..., 2:4])
  103. confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[..., 4:5], from_logits=True) + \
  104. (1-object_mask) * K.binary_crossentropy(object_mask, raw_pred[..., 4:5], from_logits=True) * ignore_mask
  105. class_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[..., 5:], from_logits=True)
  106. xy_loss = K.sum(xy_loss) / mf
  107. wh_loss = K.sum(wh_loss) / mf
  108. confidence_loss = K.sum(confidence_loss) / mf
  109. class_loss = K.sum(class_loss) / mf
  110. loss += xy_loss * 10 + wh_loss * 10 + confidence_loss
  111. # if print_loss:
  112. # loss = tf.Print(loss, [loss, xy_loss, wh_loss, confidence_loss, class_loss, K.sum(ignore_mask)], message='loss: ')
  113. return loss