Repository: PaddlePaddle/PaddleSeg

Issue:
Lovasz loss 无法使用
我在设置 Lovasz loss 后报错：
```
#Device count: 1
batch_size_per_dev: 8
Traceback (most recent call last):
  File "PaddleSeg/pdseg/train.py", line 466, in <module>
    main(args)
  File "PaddleSeg/pdseg/train.py", line 453, in main
    train(cfg)
  File "PaddleSeg/pdseg/train.py", line 237, in train
    train_prog, startup_prog, phase=ModelPhase.TRAIN)
  File "/home/aistudio/PaddleSeg/pdseg/models/model_builder.py", line 196, in build_model
    probas = fluid.layers.softmax(logits, axis=1)
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/nn.py", line 2663, in softmax
    'softmax')
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/data_feeder.py", line 80, in check_variable_and_dtype
    extra_message)
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/data_feeder.py", line 97, in check_type
    (input_name, op_name, expected_type, type(input), extra_message))
TypeError: The type of 'input' in softmax must be (<class 'paddle.fluid.framework.Variable'>, <class 'paddle.fluid.core_avx.VarBase'>), but received <class 'tuple'>. 
```
下面是配置文件内容：
```
# 数据集配置
DATASET:
    DATA_DIR: "./work/dataset/land_train/"
    NUM_CLASSES: 7
    TEST_FILE_LIST: "./work/dataset/land_train/test.txt"
    TRAIN_FILE_LIST: "./work/dataset/land_train/train.txt"
    VAL_FILE_LIST: "./work/dataset/land_train/val.txt"
    VIS_FILE_LIST: "./work/dataset/land_train/test.txt"

# 预训练模型配置
MODEL:
    MODEL_NAME: "ocrnet"
    DEFAULT_NORM_TYPE: "bn"
    # 此处设置backbone的配置
    HRNET:
        STAGE2:
            NUM_CHANNELS: [18, 36]
        STAGE3:
            NUM_CHANNELS: [18, 36, 72]
        STAGE4:
            NUM_CHANNELS: [18, 36, 72, 144]
    # 此处设置OCR HEAD
    OCR:
        OCR_MID_CHANNELS: 512
        OCR_KEY_CHANNELS: 256
    MULTI_LOSS_WEIGHT: [1.0, 1.0]

# 其他配置
TRAIN_CROP_SIZE: (512, 512)
EVAL_CROP_SIZE: (512, 512)
AUG:
    AUG_METHOD: "unpadding"
    FIX_RESIZE_SIZE: (512, 512)
    RICH_CROP:
        ENABLE: True
        BLUR: True
        BLUR_RATIO: 0.2
        MAX_ROTATION: 45
        MIN_AREA_RATIO: 0.5
    MIRROR: True
    FLIP: True
BATCH_SIZE: 8
TRAIN:
    PRETRAINED_MODEL_DIR: "./PaddleSeg/pretrained_model/ocrnet_w18_bn_cityscapes/"
    MODEL_SAVE_DIR: "./PaddleSeg/saved_model/ocrnet_optic/"
    SNAPSHOT_EPOCH: 40
TEST:
    TEST_MODEL: "./PaddleSeg/saved_model/ocrnet_optic/final"
SOLVER:
    NUM_EPOCHS: 200
    LR: 0.001
    LR_POLICY: "poly"
    OPTIMIZER: "sgd"
    LOSS: ["lovasz_softmax_loss","softmax_loss"]
    LOSS_WEIGHT:
        LOVASZ_SOFTMAX_LOSS: 0.2
        SOFTMAX_LOSS: 0.8
```


Discussion:
@michaelowenliu  您知道是什么原因吗？

Resolving patch:
diff --git a/pdseg/lovasz_losses.py b/pdseg/lovasz_losses.py
--- a/pdseg/lovasz_losses.py
+++ b/pdseg/lovasz_losses.py
@@ -18,6 +18,7 @@
 from __future__ import print_function
 import paddle.fluid as fluid
 import numpy as np
+from utils.config import cfg
 
 
 def _cumsum(x):
@@ -203,3 +204,43 @@ def flatten_probas(probas, labels, ignore=None):
     vprobas = fluid.layers.gather(probas, indexs[:, 0])
     vlabels = fluid.layers.gather(labels, indexs[:, 0])
     return vprobas, vlabels
+
+
+def multi_lovasz_softmax_loss(logits, label, ignore_mask=None):
+    if isinstance(logits, tuple):
+        avg_loss = 0
+        for i, logit in enumerate(logits):
+            if label.shape[2] != logit.shape[2] or label.shape[
+                    3] != logit.shape[3]:
+                logit_label = fluid.layers.resize_nearest(
+                    label, logit.shape[2:])
+            else:
+                logit_label = label
+            logit_mask = (logit_label.astype('int32') !=
+                          cfg.DATASET.IGNORE_INDEX).astype('int32')
+            probas = fluid.layers.softmax(logit, axis=1)
+            loss = lovasz_softmax(probas, logit_label, ignore=logit_mask)
+            avg_loss += cfg.MODEL.MULTI_LOSS_WEIGHT[i] * loss
+    else:
+        probas = fluid.layers.softmax(logits, axis=1)
+        avg_loss = lovasz_softmax(probas, label, ignore=ignore_mask)
+    return avg_loss
+
+
+def multi_lovasz_hinge_loss(logits, label, ignore_mask=None):
+    if isinstance(logits, tuple):
+        avg_loss = 0
+        for i, logit in enumerate(logits):
+            if label.shape[2] != logit.shape[2] or label.shape[
+                    3] != logit.shape[3]:
+                logit_label = fluid.layers.resize_nearest(
+                    label, logit.shape[2:])
+            else:
+                logit_label = label
+            logit_mask = (logit_label.astype('int32') !=
+                          cfg.DATASET.IGNORE_INDEX).astype('int32')
+            loss = lovasz_hinge(logit, logit_label, ignore=logit_mask)
+            avg_loss += cfg.MODEL.MULTI_LOSS_WEIGHT[i] * loss
+    else:
+        avg_loss = lovasz_hinge(logits, label, ignore=ignore_mask)
+    return avg_loss
diff --git a/pdseg/models/model_builder.py b/pdseg/models/model_builder.py
--- a/pdseg/models/model_builder.py
+++ b/pdseg/models/model_builder.py
@@ -24,8 +24,7 @@
 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 lovasz_losses import multi_lovasz_hinge_loss, multi_lovasz_softmax_loss
 from models.modeling import deeplab, unet, icnet, pspnet, hrnet, fast_scnn, ocrnet
 
 
@@ -189,13 +188,12 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN):
                     valid_loss.append("bce_loss")
                 if "lovasz_hinge_loss" in loss_type:
                     avg_loss_list.append(
-                        lovasz_hinge(logits, label, ignore=mask))
+                        multi_lovasz_hinge_loss(logits, label, 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))
+                        multi_lovasz_softmax_loss(logits, label, mask))
                     loss_valid = True
                     valid_loss.append("lovasz_softmax_loss")
                 if not loss_valid:


Test patch: