From fcb854f7daeca6ce66ae41b69c90e961eb2f2f65 Mon Sep 17 00:00:00 2001 From: LutaoChu <30695251+LutaoChu@users.noreply.github.com> Date: Tue, 14 Apr 2020 16:07:03 +0800 Subject: [PATCH] Optimize lovasz loss implementation, support multiple loss weighted combination (#215) * modify label tool * add lovasz loss * lovasz * model builder * test * lovasz * update lovasz * update lovasz * add sh yaml * add sh yaml * add sh yaml * no per_image and device_guard * no per_image and device_guard * Update lovasz_loss.md * Update lovasz_loss.md * Update lovasz_loss.md * Update lovasz_loss.md * Update lovasz_loss.md * elementwise_mul replace matmul --- ...ovasz_hinge_deeplabv3p_mobilenet_road.yaml | 49 +++++ ...z_softmax_deeplabv3p_mobilenet_pascal.yaml | 48 ++++ docs/imgs/lovasz-hinge.png | Bin 0 -> 34635 bytes docs/imgs/lovasz-softmax.png | Bin 0 -> 31283 bytes docs/lovasz_loss.md | 116 ++++++++++ pdseg/lovasz_losses.py | 205 ++++++++++++++++++ pdseg/models/model_builder.py | 40 +++- pdseg/utils/config.py | 6 + 8 files changed, 453 insertions(+), 11 deletions(-) create mode 100644 configs/lovasz_hinge_deeplabv3p_mobilenet_road.yaml create mode 100755 configs/lovasz_softmax_deeplabv3p_mobilenet_pascal.yaml create mode 100644 docs/imgs/lovasz-hinge.png create mode 100644 docs/imgs/lovasz-softmax.png create mode 100644 docs/lovasz_loss.md create mode 100755 pdseg/lovasz_losses.py diff --git a/configs/lovasz_hinge_deeplabv3p_mobilenet_road.yaml b/configs/lovasz_hinge_deeplabv3p_mobilenet_road.yaml new file mode 100644 index 00000000..0dbeddd2 --- /dev/null +++ b/configs/lovasz_hinge_deeplabv3p_mobilenet_road.yaml @@ -0,0 +1,49 @@ +EVAL_CROP_SIZE: (1025, 1025) # (width, height), for unpadding rangescaling and stepscaling +TRAIN_CROP_SIZE: (769, 769) # (width, height), for unpadding rangescaling and stepscaling +AUG: + AUG_METHOD: u"stepscaling" # choice unpadding rangescaling and stepscaling + FIX_RESIZE_SIZE: (640, 640) # (width, height), for unpadding + INF_RESIZE_VALUE: 500 # for rangescaling + MAX_RESIZE_VALUE: 600 # for rangescaling + MIN_RESIZE_VALUE: 400 # for rangescaling + MAX_SCALE_FACTOR: 2.0 # for stepscaling + MIN_SCALE_FACTOR: 0.5 # for stepscaling + SCALE_STEP_SIZE: 0.25 # for stepscaling + FLIP: True +BATCH_SIZE: 24 +DATASET: + DATA_DIR: "./dataset/MiniDeepGlobeRoadExtraction/" + IMAGE_TYPE: "rgb" # choice rgb or rgba + NUM_CLASSES: 2 + TEST_FILE_LIST: "dataset/MiniDeepGlobeRoadExtraction/val.txt" + TRAIN_FILE_LIST: "dataset/MiniDeepGlobeRoadExtraction/train.txt" + VAL_FILE_LIST: "dataset/MiniDeepGlobeRoadExtraction/val.txt" + IGNORE_INDEX: 255 + SEPARATOR: '|' +FREEZE: + MODEL_FILENAME: "model" + PARAMS_FILENAME: "params" + SAVE_DIR: "freeze_model" +MODEL: + DEFAULT_NORM_TYPE: "bn" + MODEL_NAME: "deeplabv3p" + DEEPLAB: + BACKBONE: "mobilenetv2" + DEPTH_MULTIPLIER: 1.0 + ENCODER_WITH_ASPP: False + ENABLE_DECODER: False +TEST: + TEST_MODEL: "./saved_model/lovasz_hinge_deeplabv3p_mobilenet_road/final" +TRAIN: + MODEL_SAVE_DIR: "./saved_model/lovasz_hinge_deeplabv3p_mobilenet_road/" + PRETRAINED_MODEL_DIR: "./pretrained_model/deeplabv3p_mobilenetv2-1-0_bn_coco/" + SNAPSHOT_EPOCH: 10 +SOLVER: + LR: 0.1 + LR_POLICY: "poly" + OPTIMIZER: "sgd" + NUM_EPOCHS: 300 + LOSS: ["lovasz_hinge_loss","bce_loss"] + LOSS_WEIGHT: + LOVASZ_HINGE_LOSS: 0.5 + BCE_LOSS: 0.5 diff --git a/configs/lovasz_softmax_deeplabv3p_mobilenet_pascal.yaml b/configs/lovasz_softmax_deeplabv3p_mobilenet_pascal.yaml new file mode 100755 index 00000000..0c083ba5 --- /dev/null +++ b/configs/lovasz_softmax_deeplabv3p_mobilenet_pascal.yaml @@ -0,0 +1,48 @@ +TRAIN_CROP_SIZE: (500, 500) # (width, height), for unpadding rangescaling and stepscaling #训练时图像裁剪尺寸(宽,高) +EVAL_CROP_SIZE: (500, 500) # (width, height), for unpadding rangescaling and stepscaling #验证时图像裁剪尺寸(宽,高) +AUG: + AUG_METHOD: "stepscaling" # choice unpadding rangescaling and stepscaling + FIX_RESIZE_SIZE: (500, 500) # (width, height), for unpadding + + INF_RESIZE_VALUE: 500 # for rangescaling + MAX_RESIZE_VALUE: 600 # for rangescaling + MIN_RESIZE_VALUE: 400 # for rangescaling + + MAX_SCALE_FACTOR: 1.25 # for stepscaling + MIN_SCALE_FACTOR: 0.75 # for stepscaling + SCALE_STEP_SIZE: 0.05 # for stepscaling + MIRROR: True + FLIP: True +BATCH_SIZE: 16 #批处理大小 +DATASET: + DATA_DIR: "./dataset/VOCtrainval_11-May-2012/VOC2012/" #图片路径 + IMAGE_TYPE: "rgb" # choice rgb or rgba #图片类别“RGB” + NUM_CLASSES: 21 #类别数(包括背景类别) + TEST_FILE_LIST: "dataset/VOCtrainval_11-May-2012/VOC2012/ImageSets/Segmentation/val.list" + TRAIN_FILE_LIST: "dataset/VOCtrainval_11-May-2012/VOC2012/ImageSets/Segmentation/train.list" + VAL_FILE_LIST: "dataset/VOCtrainval_11-May-2012/VOC2012/ImageSets/Segmentation/val.list" + IGNORE_INDEX: 255 + SEPARATOR: " " +MODEL: + MODEL_NAME: "deeplabv3p" + DEFAULT_NORM_TYPE: "bn" #指定norm的类型,此处提供bn和gn(默认)两种选择,分别指batch norm和group norm。 + DEEPLAB: + BACKBONE: "mobilenetv2" + DEPTH_MULTIPLIER: 1.0 + ENCODER_WITH_ASPP: False + ENABLE_DECODER: False +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/deeplabv3p_mobilenetv2-1-0_bn_coco/" + MODEL_SAVE_DIR: "./saved_model/lovasz-softmax-voc" #模型保存路径 + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/lovasz-softmax-voc/final" #为测试模型路径 +SOLVER: + NUM_EPOCHS: 100 #训练epoch数,正整数 + LR: 0.0001 #初始学习率 + LR_POLICY: "poly" #学习率下降方法, 选项为poly、piecewise和cosine + OPTIMIZER: "sgd" #优化算法, 选项为sgd和adam + LOSS: ["lovasz_softmax_loss","softmax_loss"] + LOSS_WEIGHT: + LOVASZ_SOFTMAX_LOSS: 0.2 + SOFTMAX_LOSS: 0.8 diff --git a/docs/imgs/lovasz-hinge.png b/docs/imgs/lovasz-hinge.png new file mode 100644 index 0000000000000000000000000000000000000000..579b3b7b8fd27acbbde073564e53e2cbdfb3df67 GIT binary patch literal 34635 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 DCcdBQ literal 0 HcmV?d00001 diff --git a/docs/imgs/lovasz-softmax.png b/docs/imgs/lovasz-softmax.png new file mode 100644 index 0000000000000000000000000000000000000000..afb3f2e8e29c1c7925228aa8336b6bb23e1e93ba GIT binary patch literal 31283 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 F{{=ZGZBPIJ literal 0 HcmV?d00001 diff --git a/docs/lovasz_loss.md b/docs/lovasz_loss.md new file mode 100644 index 00000000..1270b3fd --- /dev/null +++ b/docs/lovasz_loss.md @@ -0,0 +1,116 @@ +# Lovasz loss +对于图像分割任务中,经常出现类别分布不均匀的情况,例如:工业产品的瑕疵检测、道路提取及病变区域提取等。 + +我们可使用lovasz loss解决这个问题。Lovasz loss根据分割目标的类别数量可分为两种:lovasz hinge loss适用于二分类问题,lovasz softmax loss适用于多分类问题。 + + +## Lovasz hinge loss +### 使用方式 + +PaddleSeg通过`cfg.SOLVER.LOSS`参数可以选择训练时的损失函数, +如`cfg.SOLVER.LOSS=['lovasz_hinge_loss','bce_loss']`将指定训练loss为`lovasz hinge loss`与`bce loss`的组合。 + +Lovasz hinge loss有3种使用方式:(1)直接训练使用。(2)bce loss结合使用。(3)先使用bec loss进行训练,再使用lovasz hinge loss进行finetuning. 第1种方式不一定达到理想效果,推荐使用后两种方式。本文以第2种方式为例。 + +### 使用示例 + +我们以道路提取任务为例应用lovasz hinge loss. +在DeepGlobe比赛的Road Extraction中,训练数据道路占比为:4.5%. 如下为其图片样例: +

+
+

+可以看出道路在整张图片中的比例很小。 + +#### 实验对比 + +在MiniDeepGlobeRoadExtraction数据集进行了实验对比。 + +* 数据集下载 +我们从DeepGlobe比赛的Road Extraction的训练集中随机抽取了800张图片作为训练集,200张图片作为验证集, +制作了一个小型的道路提取数据集[MiniDeepGlobeRoadExtraction](https://paddleseg.bj.bcebos.com/dataset/MiniDeepGlobeRoadExtraction.zip) + +```shell +python dataset/download_mini_deepglobe_road_extraction.py +``` + +* 预训练模型下载 +```shell +python pretrained_model/download_model.py deeplabv3p_mobilenetv2-1-0_bn_coco +``` +* 配置/数据校验 +```shell +python pdseg/check.py --cfg ./configs/lovasz_hinge_deeplabv3p_mobilenet_road.yaml +``` + +* 训练 +```shell +python pdseg/train.py --cfg ./configs/lovasz_hinge_deeplabv3p_mobilenet_road.yaml --use_gpu --use_mpio SOLVER.LOSS "['lovasz_hinge_loss','bce_loss']" +``` + +* 评估 +```shell +python pdseg/eval.py --cfg ./configs/lovasz_hinge_deeplabv3p_mobilenet_road.yaml --use_gpu --use_mpio SOLVER.LOSS "['lovasz_hinge_loss','bce_loss']" +``` + +* 结果比较 + +lovasz hinge loss + bce loss和softmax loss的对比结果如下图所示。 +

+
+

+ +图中蓝色曲线为lovasz hinge loss + bce loss,最高mIoU为76.2%,橙色曲线为softmax loss, 最高mIoU为73.44%,相比提升2.76个百分点。 + + + +## Lovasz softmax loss +### 使用方式 + +PaddleSeg通过`cfg.SOLVER.LOSS`参数可以选择训练时的损失函数, +如`cfg.SOLVER.LOSS=['lovasz_softmax_loss','softmax_loss']`将指定训练loss为`lovasz softmax loss`与`softmax loss`的组合。 + +Lovasz softmax loss有3种使用方式:(1)直接训练使用。(2)softmax loss结合使用。(3)先使用softmax loss进行训练,再使用lovasz softmax loss进行finetuning. 第1种方式不一定达到理想效果,推荐使用后两种方式。本文以第2种方式为例。 + +### 使用示例 + +我们以Pascal voc为例应用lovasz softmax loss. + + +#### 实验对比 + +在Pascal voc数据集上与softmax loss进行了实验对比。 + +* 数据集下载 +```shell +python dataset/download_and_convert_voc2012.py +``` + +* 预训练模型下载 +```shell +python pretrained_model/download_model.py deeplabv3p_mobilenetv2-1-0_bn_coco +``` +* 配置/数据校验 +```shell +python pdseg/check.py --cfg ./configs/lovasz_softmax_deeplabv3p_mobilenet_pascal.yaml +``` + +* 训练 +```shell +python pdseg/train.py --cfg ./configs/lovasz_softmax_deeplabv3p_mobilenet_pascal.yaml --use_gpu --use_mpio SOLVER.LOSS "['lovasz_softmax_loss','softmax_loss']" + +``` + +* 评估 +```shell +python pdseg/eval.py --cfg ./configs/lovasz_softmax_deeplabv3p_mobilenet_pascal.yaml --use_gpu --use_mpio SOLVER.LOSS "['lovasz_softmax_loss','softmax_loss']" + +``` + +* 结果比较 + +lovasz softmax loss + softmax loss和softmax loss的对比结果如下图所示。 +

+
+

+ +图中橙色曲线代表lovasz softmax loss + softmax loss,最高mIoU为64.63%,蓝色曲线代表softmax loss, 最高mIoU为63.55%,相比提升1.08个百分点。 diff --git a/pdseg/lovasz_losses.py b/pdseg/lovasz_losses.py new file mode 100755 index 00000000..5f228358 --- /dev/null +++ b/pdseg/lovasz_losses.py @@ -0,0 +1,205 @@ +# copyright (c) 2019 PaddlePaddle Authors. All Rights Reserve. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Lovasz-Softmax and Jaccard hinge loss in PaddlePaddle""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle.fluid as fluid +import numpy as np + + +def _cumsum(x): + y = np.array(x) + return np.cumsum(y, axis=0) + + +def create_tmp_var(name, dtype, shape): + return fluid.default_main_program().current_block().create_var( + name=name, dtype=dtype, shape=shape) + + +def lovasz_grad(gt_sorted): + """ + Computes gradient of the Lovasz extension w.r.t sorted errors + See Alg. 1 in paper + """ + gt_sorted = fluid.layers.squeeze(gt_sorted, axes=[1]) + gts = fluid.layers.reduce_sum(gt_sorted) + len_gt = fluid.layers.shape(gt_sorted) + + # Acceleration is achieved by reducing the number of calls to cumsum. + # This calculation method is equivalent to that of the original paper. + var_one = fluid.layers.fill_constant(shape=[1], value=1, dtype='int32') + range_ = fluid.layers.range(1, len_gt + var_one, 1, 'int32') + tmp_var = create_tmp_var( + name='tmp_var', dtype=gt_sorted.dtype, shape=gt_sorted.shape) + cumsum_ = fluid.layers.py_func(func=_cumsum, x=gt_sorted, out=tmp_var) + intersection = gts - cumsum_ + union = intersection + range_ + + jaccard = 1.0 - intersection / union + jaccard0 = fluid.layers.slice(jaccard, axes=[0], starts=[0], ends=[1]) + jaccard1 = fluid.layers.slice(jaccard, axes=[0], starts=[1], ends=[len_gt]) + jaccard2 = fluid.layers.slice(jaccard, axes=[0], starts=[0], ends=[-1]) + jaccard = fluid.layers.concat([jaccard0, jaccard1 - jaccard2], axis=0) + jaccard = fluid.layers.unsqueeze(jaccard, axes=[1]) + return jaccard + + +def lovasz_hinge(logits, labels, ignore=None): + """ + Binary Lovasz hinge loss + logits: [N, C, H, W] Tensor, logits at each pixel (between -\infty and +\infty) + labels: [N, 1, H, W] Tensor, binary ground truth masks (0 or 1) + ignore: [N, 1, H, W] Tensor. Void class labels, ignore pixels which value=0 + """ + loss = lovasz_hinge_flat(*flatten_binary_scores(logits, labels, ignore)) + return loss + + +def lovasz_hinge_flat(logits, labels): + """ + Binary Lovasz hinge loss + logits: [P] Tensor, logits at each prediction (between -\infty and +\infty) + labels: [P] Tensor, binary ground truth labels (0 or 1) + """ + shape = fluid.layers.shape(logits) + y = fluid.layers.zeros_like(shape[0]) + + out_var = fluid.layers.create_tensor("float32") + with fluid.layers.control_flow.Switch() as switch: + with switch.case(fluid.layers.equal(shape[0], y)): + loss = fluid.layers.reduce_sum(logits) * 0. + fluid.layers.assign(input=loss, output=out_var) + with switch.case(fluid.layers.greater_than(shape[0], y)): + labelsf = fluid.layers.cast(labels, logits.dtype) + signs = labelsf * 2 - 1. + signs.stop_gradient = True + errors = 1.0 - fluid.layers.elementwise_mul(logits, signs) + errors_sorted, perm = fluid.layers.argsort( + errors, axis=0, descending=True) + errors_sorted.stop_gradient = False + gt_sorted = fluid.layers.gather(labelsf, perm) + + grad = lovasz_grad(gt_sorted) + grad.stop_gradient = True + loss = fluid.layers.reduce_sum( + fluid.layers.relu(errors_sorted) * grad) + fluid.layers.assign(input=loss, output=out_var) + return out_var + + +def flatten_binary_scores(scores, labels, ignore=None): + """ + Flattens predictions in the batch (binary case) + Remove labels according to 'ignore' + """ + scores = fluid.layers.reshape(scores, [-1, 1]) + labels = fluid.layers.reshape(labels, [-1, 1]) + labels.stop_gradient = True + if ignore is None: + return scores, labels + ignore = fluid.layers.cast(ignore, 'int32') + ignore_mask = fluid.layers.reshape(ignore, (-1, 1)) + indexs = fluid.layers.where(ignore_mask == 1) + indexs.stop_gradient = True + vscores = fluid.layers.gather(scores, indexs[:, 0]) + vlabels = fluid.layers.gather(labels, indexs[:, 0]) + return vscores, vlabels + + +def lovasz_softmax(probas, labels, classes='present', ignore=None): + """ + Multi-class Lovasz-Softmax loss + probas: [N, C, H, W] Tensor, class probabilities at each prediction (between 0 and 1). + labels: [N, 1, H, W] Tensor, ground truth labels (between 0 and C - 1) + classes: 'all' for all, 'present' for classes present in labels, or a list of classes to average. + ignore: [N, 1, H, W] Tensor. Void class labels, ignore pixels which value=0 + """ + vprobas, vlabels = flatten_probas(probas, labels, ignore) + loss = lovasz_softmax_flat(vprobas, vlabels, classes=classes) + return loss + + +def lovasz_softmax_flat(probas, labels, classes='present'): + """ + Multi-class Lovasz-Softmax loss + probas: [P, C] Tensor, class probabilities at each prediction (between 0 and 1) + labels: [P] Tensor, ground truth labels (between 0 and C - 1) + classes: 'all' for all, 'present' for classes present in labels, or a list of classes to average. + """ + C = probas.shape[1] + losses = [] + present = [] + classes_to_sum = list(range(C)) if classes in ['all', 'present' + ] else classes + for c in classes_to_sum: + fg = fluid.layers.cast(labels == c, probas.dtype) + fg.stop_gradient = True + if classes == 'present': + present.append( + fluid.layers.cast(fluid.layers.reduce_sum(fg) > 0, "int64")) + if C == 1: + if len(classes_to_sum) > 1: + raise ValueError('Sigmoid output possible only with 1 class') + class_pred = probas[:, 0] + else: + class_pred = probas[:, c] + errors = fluid.layers.abs(fg - class_pred) + errors_sorted, perm = fluid.layers.argsort( + errors, axis=0, descending=True) + errors_sorted.stop_gradient = False + + fg_sorted = fluid.layers.gather(fg, perm) + fg_sorted.stop_gradient = True + + grad = lovasz_grad(fg_sorted) + grad.stop_gradient = True + loss = fluid.layers.reduce_sum(errors_sorted * grad) + + losses.append(loss) + + if len(classes_to_sum) == 1: + return losses[0] + + losses_tensor = fluid.layers.stack(losses) + if classes == 'present': + present_tensor = fluid.layers.stack(present) + index = fluid.layers.where(present_tensor == 1) + index.stop_gradient = True + losses_tensor = fluid.layers.gather(losses_tensor, index[:, 0]) + loss = fluid.layers.mean(losses_tensor) + return loss + + +def flatten_probas(probas, labels, ignore=None): + """ + Flattens predictions in the batch + """ + if len(probas.shape) == 3: + probas = fluid.layers.unsqueeze(probas, axis=[1]) + C = probas.shape[1] + probas = fluid.layers.transpose(probas, [0, 2, 3, 1]) + probas = fluid.layers.reshape(probas, [-1, C]) + labels = fluid.layers.reshape(labels, [-1, 1]) + if ignore is None: + return probas, labels + ignore = fluid.layers.cast(ignore, 'int32') + ignore_mask = fluid.layers.reshape(ignore, [-1, 1]) + indexs = fluid.layers.where(ignore_mask == 1) + indexs.stop_gradient = True + vprobas = fluid.layers.gather(probas, indexs[:, 0]) + vlabels = fluid.layers.gather(labels, indexs[:, 0]) + return vprobas, vlabels diff --git a/pdseg/models/model_builder.py b/pdseg/models/model_builder.py index a81f2ff4..86460224 100644 --- a/pdseg/models/model_builder.py +++ b/pdseg/models/model_builder.py @@ -24,6 +24,8 @@ from utils.config import cfg from loss import multi_softmax_with_loss from loss import multi_dice_loss from loss import multi_bce_loss +from lovasz_losses import lovasz_hinge +from lovasz_losses import lovasz_softmax from models.modeling import deeplab, unet, icnet, pspnet, hrnet, fast_scnn @@ -204,19 +206,22 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN): if not isinstance(loss_type, list): loss_type = list(loss_type) - # dice_loss或bce_loss只适用两类分割中 - if class_num > 2 and (("dice_loss" in loss_type) or + # lovasz_hinge_loss或dice_loss或bce_loss只适用两类分割中 + if class_num > 2 and (("lovasz_hinge_loss" in loss_type) or + ("dice_loss" in loss_type) or ("bce_loss" in loss_type)): raise Exception( - "dice loss and bce loss is only applicable to binary classfication" + "lovasz hinge loss, dice loss and bce loss are only applicable to binary classfication." ) - # 在两类分割情况下,当loss函数选择dice_loss或bce_loss的时候,最后logit输出通道数设置为1 - if ("dice_loss" in loss_type) or ("bce_loss" in loss_type): + # 在两类分割情况下,当loss函数选择lovasz_hinge_loss或dice_loss或bce_loss的时候,最后logit输出通道数设置为1 + if ("dice_loss" in loss_type) or ("bce_loss" in loss_type) or ( + "lovasz_hinge_loss" in loss_type): class_num = 1 - if "softmax_loss" in loss_type: + if ("softmax_loss" in loss_type) or ( + "lovasz_softmax_loss" in loss_type): raise Exception( - "softmax loss can not combine with dice loss or bce loss" + "softmax loss or lovasz softmax loss can not combine with bce loss or dice loss or lovasz hinge loss." ) logits = seg_model(image, class_num) @@ -240,11 +245,22 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN): avg_loss_list.append(multi_bce_loss(logits, label, mask)) loss_valid = True valid_loss.append("bce_loss") + if "lovasz_hinge_loss" in loss_type: + avg_loss_list.append( + lovasz_hinge(logits, label, ignore=mask)) + loss_valid = True + valid_loss.append("lovasz_hinge_loss") + if "lovasz_softmax_loss" in loss_type: + probas = fluid.layers.softmax(logits, axis=1) + avg_loss_list.append( + lovasz_softmax(probas, label, ignore=mask)) + loss_valid = True + valid_loss.append("lovasz_softmax_loss") if not loss_valid: raise Exception( "SOLVER.LOSS: {} is set wrong. it should " - "include one of (softmax_loss, bce_loss, dice_loss) at least" - " example: ['softmax_loss'], ['dice_loss'], ['bce_loss', 'dice_loss']" + "include one of (softmax_loss, bce_loss, dice_loss, lovasz_hinge_loss, lovasz_softmax_loss) at least" + " example: ['softmax_loss'], ['dice_loss'], ['bce_loss', 'dice_loss'], ['lovasz_hinge_loss','bce_loss'], ['lovasz_softmax_loss','softmax_loss']" .format(cfg.SOLVER.LOSS)) invalid_loss = [x for x in loss_type if x not in valid_loss] @@ -255,7 +271,9 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN): avg_loss = 0 for i in range(0, len(avg_loss_list)): - avg_loss += avg_loss_list[i] + loss_name = valid_loss[i].upper() + loss_weight = eval('cfg.SOLVER.LOSS_WEIGHT.' + loss_name) + avg_loss += loss_weight * avg_loss_list[i] #get pred result in original size if isinstance(logits, tuple): @@ -268,7 +286,7 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN): # return image input and logit output for inference graph prune if ModelPhase.is_predict(phase): - # 两类分割中,使用dice_loss或bce_loss返回的logit为单通道,进行到两通道的变换 + # 两类分割中,使用lovasz_hinge_loss或dice_loss或bce_loss返回的logit为单通道,进行到两通道的变换 if class_num == 1: logit = sigmoid_to_softmax(logit) else: diff --git a/pdseg/utils/config.py b/pdseg/utils/config.py index 220b9e5e..141b17ce 100644 --- a/pdseg/utils/config.py +++ b/pdseg/utils/config.py @@ -155,6 +155,12 @@ cfg.SOLVER.BEGIN_EPOCH = 1 cfg.SOLVER.NUM_EPOCHS = 30 # loss的选择,支持softmax_loss, bce_loss, dice_loss cfg.SOLVER.LOSS = ["softmax_loss"] +# loss的权重,用于多loss组合加权使用,仅对SOLVER.LOSS内包含的loss生效 +cfg.SOLVER.LOSS_WEIGHT.SOFTMAX_LOSS = 1 +cfg.SOLVER.LOSS_WEIGHT.DICE_LOSS = 1 +cfg.SOLVER.LOSS_WEIGHT.BCE_LOSS = 1 +cfg.SOLVER.LOSS_WEIGHT.LOVASZ_HINGE_LOSS = 1 +cfg.SOLVER.LOSS_WEIGHT.LOVASZ_SOFTMAX_LOSS = 1 # 是否开启warmup学习策略 cfg.SOLVER.LR_WARMUP = False # warmup的迭代次数 -- GitLab