diff --git a/paddle/fluid/operators/yolov3_loss_op.h b/paddle/fluid/operators/yolov3_loss_op.h index 837ea156013b8b7a124440f306345d16aaabc0e8..46617472618d6ec7cdea5a929de6431199abb288 100644 --- a/paddle/fluid/operators/yolov3_loss_op.h +++ b/paddle/fluid/operators/yolov3_loss_op.h @@ -32,6 +32,49 @@ static inline bool isZero(T x) { return fabs(x) < 1e-6; } +template +static inline void CalcL1LossWithWeight(const Tensor& x, const Tensor& y, + const Tensor& weight, + const T loss_weight, T* loss) { + int n = x.dims()[0]; + int stride = x.numel() / n; + const T* x_data = x.data(); + const T* y_data = y.data(); + const T* weight_data = weight.data(); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < stride; j++) { + loss[i] += fabs(y_data[j] - x_data[j]) * weight_data[j] * loss_weight; + } + x_data += stride; + y_data += stride; + weight_data += stride; + } +} + +template +static void CalcL1LossGradWithWeight(const T* loss_grad, Tensor* grad, + const Tensor& x, const Tensor& y, + const Tensor& weight) { + int n = x.dims()[0]; + int stride = x.numel() / n; + T* grad_data = grad->data(); + const T* x_data = x.data(); + const T* y_data = y.data(); + const T* weight_data = weight.data(); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < stride; j++) { + grad_data[j] = weight_data[j] * loss_grad[i]; + if (x_data[j] < y_data[j]) grad_data[j] *= -1.0; + } + grad_data += stride; + x_data += stride; + y_data += stride; + weight_data += stride; + } +} + template static inline void CalcMSEWithWeight(const Tensor& x, const Tensor& y, const Tensor& weight, const T loss_weight, @@ -374,8 +417,8 @@ class Yolov3LossKernel : public framework::OpKernel { memset(loss_data, 0, n * sizeof(T)); CalcSCEWithWeight(pred_x, tx, obj_weight, loss_weight_xy, loss_data); CalcSCEWithWeight(pred_y, ty, obj_weight, loss_weight_xy, loss_data); - CalcMSEWithWeight(pred_w, tw, obj_weight, loss_weight_wh, loss_data); - CalcMSEWithWeight(pred_h, th, obj_weight, loss_weight_wh, loss_data); + CalcL1LossWithWeight(pred_w, tw, obj_weight, loss_weight_wh, loss_data); + CalcL1LossWithWeight(pred_h, th, obj_weight, loss_weight_wh, loss_data); CalcSCEWithWeight(pred_conf, tconf, obj_mask, loss_weight_conf_target, loss_data); CalcSCEWithWeight(pred_conf, tconf, noobj_mask, @@ -471,8 +514,10 @@ class Yolov3LossGradKernel : public framework::OpKernel { grad_class.mutable_data({n, an_num, h, w, class_num}, ctx.GetPlace()); CalcSCEGradWithWeight(loss_grad_data, &grad_x, pred_x, tx, obj_weight); CalcSCEGradWithWeight(loss_grad_data, &grad_y, pred_y, ty, obj_weight); - CalcMSEGradWithWeight(loss_grad_data, &grad_w, pred_w, tw, obj_weight); - CalcMSEGradWithWeight(loss_grad_data, &grad_h, pred_h, th, obj_weight); + CalcL1LossGradWithWeight(loss_grad_data, &grad_w, pred_w, tw, + obj_weight); + CalcL1LossGradWithWeight(loss_grad_data, &grad_h, pred_h, th, + obj_weight); CalcSCEGradWithWeight(loss_grad_data, &grad_conf_target, pred_conf, tconf, obj_mask); CalcSCEGradWithWeight(loss_grad_data, &grad_conf_notarget, pred_conf, diff --git a/python/paddle/fluid/tests/unittests/test_yolov3_loss_op.py b/python/paddle/fluid/tests/unittests/test_yolov3_loss_op.py index 26367f213b2d01f78bfa35aab44c7c1728c1cab1..e218031286fc221dab294cfca70ca81a86285856 100644 --- a/python/paddle/fluid/tests/unittests/test_yolov3_loss_op.py +++ b/python/paddle/fluid/tests/unittests/test_yolov3_loss_op.py @@ -23,6 +23,14 @@ from op_test import OpTest from paddle.fluid import core +def l1loss(x, y, weight): + n = x.shape[0] + x = x.reshape((n, -1)) + y = y.reshape((n, -1)) + weight = weight.reshape((n, -1)) + return (np.abs(y - x) * weight).sum(axis=1) + + def mse(x, y, weight): n = x.shape[0] x = x.reshape((n, -1)) @@ -146,8 +154,8 @@ def YoloV3Loss(x, gtbox, gtlabel, attrs): np.expand_dims(obj_mask, 4), (1, 1, 1, 1, int(attrs['class_num']))) loss_x = sce(pred_x, tx, obj_weight) loss_y = sce(pred_y, ty, obj_weight) - loss_w = mse(pred_w, tw, obj_weight) - loss_h = mse(pred_h, th, obj_weight) + loss_w = l1loss(pred_w, tw, obj_weight) + loss_h = l1loss(pred_h, th, obj_weight) loss_conf_target = sce(pred_conf, tconf, obj_mask) loss_conf_notarget = sce(pred_conf, tconf, noobj_mask) loss_class = sce(pred_cls, tcls, obj_mask_expand)