提交 a89ca64d 编写于 作者: W wuyefeilin 提交者: wuzewu

add loss_select document and update model_builder.py (#58)

* init deepglobe_road_extraction.yaml

* update download_mini_deepglobe_road_extraction.py

* update model_builder.py
上级 f55d38a8
...@@ -60,6 +60,7 @@ PaddleSeg支持多进程IO、多卡并行、跨卡Batch Norm同步等训练加 ...@@ -60,6 +60,7 @@ PaddleSeg支持多进程IO、多卡并行、跨卡Batch Norm同步等训练加
### 高级功能 ### 高级功能
* [PaddleSeg的数据增强](./docs/data_aug.md) * [PaddleSeg的数据增强](./docs/data_aug.md)
* [PaddleSeg的loss选择](./docs/loss_select.md)
* [特色垂类模型使用](./contrib) * [特色垂类模型使用](./contrib)
* [多进程训练和混合精度训练](./docs/multiple_gpus_train_and_mixed_precision_train.md) * [多进程训练和混合精度训练](./docs/multiple_gpus_train_and_mixed_precision_train.md)
......
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
BATCH_SIZE: 8
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: "mobilenet"
DEPTH_MULTIPLIER: 1.0
ENCODER_WITH_ASPP: False
ENABLE_DECODER: False
TEST:
TEST_MODEL: "./saved_model/deeplabv3p_mobilenetv2-1-0_bn_deepglobe_road_extraction/"
TRAIN:
MODEL_SAVE_DIR: "./saved_model/deeplabv3p_mobilenetv2-1-0_bn_deepglobe_road_extraction/"
PRETRAINED_MODEL_DIR: "./pretrained_model/deeplabv3p_mobilenetv2-1-0_bn_coco/"
SNAPSHOT_EPOCH: 10
SOLVER:
LR: 0.001
LR_POLICY: "poly"
OPTIMIZER: "adam"
NUM_EPOCHS: 300
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
#
# 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.
import sys
import os
LOCAL_PATH = os.path.dirname(os.path.abspath(__file__))
TEST_PATH = os.path.join(LOCAL_PATH, "..", "test")
sys.path.append(TEST_PATH)
from test_utils import download_file_and_uncompress
def download_deepglobe_road_dataset(savepath, extrapath):
url = "https://paddleseg.bj.bcebos.com/dataset/MiniDeepGlobeRoadExtraction.zip"
download_file_and_uncompress(
url=url, savepath=savepath, extrapath=extrapath)
if __name__ == "__main__":
download_deepglobe_road_dataset(LOCAL_PATH, LOCAL_PATH)
print("Dataset download finish!")
...@@ -132,27 +132,6 @@ L2正则化系数 ...@@ -132,27 +132,6 @@ L2正则化系数
`['softmax_loss']``['dice_loss','bce_loss']` `['softmax_loss']``['dice_loss','bce_loss']`
* softmax_loss
![equation](http://latex.codecogs.com/gif.latex?softmax\\_loss=\sum_{i=1}^Ny_i{log(p_i)})
<br/>
* dice_loss
![equation](http://latex.codecogs.com/gif.latex?dice\\_loss=1-\frac{2|Y\bigcap{P}|}{|Y|\bigcup|P|})
[dice系数](https://zh.wikipedia.org/wiki/Dice%E7%B3%BB%E6%95%B0)
<br/>
* bce_loss
![equation](http://latex.codecogs.com/gif.latex?bce\\_loss=y_i{log(p_i)}+(1-y_i)log(1-p_i))
其中![equation](http://latex.codecogs.com/gif.latex?y_i)*Y*为标签,
![equation](http://latex.codecogs.com/gif.latex?p_i)*P*为预测结果
### 默认值 ### 默认值
['softmax_loss'] ['softmax_loss']
......
# dice loss解决二分类中样本不均衡问题
对于二类图像分割任务中,往往存在类别分布不均的情况,如:瑕疵检测,道路提取及病变区域提取等等。
在DeepGlobe比赛的Road Extraction中,训练数据道路占比为:%4.5。如下为其图片样例:
<p align="center">
<img src="./imgs/deepglobe.png" hspace='10'/> <br />
</p>
可以看出道路在整张图片中的比例很小。
## 数据集下载
我们从DeepGlobe比赛的Road Extraction的训练集中随机抽取了800张图片作为训练集,200张图片作为验证集,
制作了一个小型的道路提取数据集[MiniDeepGlobeRoadExtraction](https://paddleseg.bj.bcebos.com/dataset/MiniDeepGlobeRoadExtraction.zip)
## softmax loss与dice loss
在图像分割中,softmax loss(sotfmax with cross entroy loss)同等的对待每一像素,因此当背景占据绝大部分的情况下,
网络将偏向于背景的学习,使网络对目标的提取能力变差。`dice loss(dice coefficient loss)`通过计算预测与标注之间的重叠部分计算损失函数,避免了类别不均衡带来的影响,能够取得更好的效果。
在实际应用中`dice loss`往往与`bce loss(binary cross entroy loss)`结合使用,提高模型训练的稳定性。
dice loss的定义如下:
![equation](http://latex.codecogs.com/gif.latex?dice\\_loss=1-\frac{2|Y\bigcap{P}|}{|Y|+|P|})
其中 ![equation](http://latex.codecogs.com/gif.latex?|Y\bigcap{P}|) 表示*Y**P*的共有元素数,
实际计算通过求两者的乘积之和进行计算。如下所示:
<p align="center">
<img src="./imgs/dice1.png" hspace='10' height="68" width="513"/> <br />
</p>
[dice系数详解](https://zh.wikipedia.org/wiki/Dice%E7%B3%BB%E6%95%B0)
## PaddleSeg指定训练loss
PaddleSeg通过`cfg.SOLVER.LOSS`参数可以选择训练时的损失函数,
`cfg.SOLVER.LOSS=['dice_loss','bce_loss']`将指定训练loss为`dice loss``bce loss`的组合
## 实验比较
在MiniDeepGlobeRoadExtraction数据集进行了实验比较。
* 数据集下载
```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/deepglobe_road_extraction.yaml
```
* 训练
```shell
python pdseg/train.py --cfg ./configs/deepglobe_road_extraction.yaml --use_gpu SOLVER.LOSS ['dice_loss','bce_loss']
```
* 评估
```
python pdseg/eval.py --cfg ./configs/deepglobe_road_extraction.yaml --use_gpu SOLVER.LOSS ['dice_loss','bce_loss']
```
* 结果比较
softmax loss和dice loss + bce loss实验结果如下图所示。
图中橙色曲线为dice loss + bce loss,最高mIoU为76.02%,蓝色曲线为softmax loss, 最高mIoU为73.62%。
<p align="center">
<img src="./imgs/loss_comparison.png" hspace='10' height="208" width="516"/> <br />
</p>
...@@ -158,6 +158,10 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN): ...@@ -158,6 +158,10 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN):
model_func = get_func("modeling." + model_name) model_func = get_func("modeling." + model_name)
loss_type = cfg.SOLVER.LOSS loss_type = cfg.SOLVER.LOSS
if class_num > 2 and (("dice_loss" in loss_type) or ("bce_loss" in loss_type)):
raise Exception("dice loss and bce loss is only applicable to binary classfication")
if ("dice_loss" in loss_type) or ("bce_loss" in loss_type): if ("dice_loss" in loss_type) or ("bce_loss" in loss_type):
class_num = 1 class_num = 1
if "softmax_loss" in loss_type: if "softmax_loss" in loss_type:
...@@ -168,20 +172,29 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN): ...@@ -168,20 +172,29 @@ def build_model(main_prog, start_prog, phase=ModelPhase.TRAIN):
if ModelPhase.is_train(phase) or ModelPhase.is_eval(phase): if ModelPhase.is_train(phase) or ModelPhase.is_eval(phase):
loss_valid = False loss_valid = False
avg_loss_list = [] avg_loss_list = []
valid_loss = []
if "softmax_loss" in loss_type: if "softmax_loss" in loss_type:
avg_loss_list.append(multi_softmax_with_loss(logits, avg_loss_list.append(multi_softmax_with_loss(logits,
label, mask,class_num)) label, mask,class_num))
loss_valid = True loss_valid = True
valid_loss.append("softmax_loss")
if "dice_loss" in loss_type: if "dice_loss" in loss_type:
avg_loss_list.append(multi_dice_loss(logits, label, mask)) avg_loss_list.append(multi_dice_loss(logits, label, mask))
loss_valid = True loss_valid = True
valid_loss.append("dice_loss")
if "bce_loss" in loss_type: if "bce_loss" in loss_type:
avg_loss_list.append(multi_bce_loss(logits, label, mask)) avg_loss_list.append(multi_bce_loss(logits, label, mask))
loss_valid = True loss_valid = True
valid_loss.append("bce_loss")
if not loss_valid: if not loss_valid:
raise Exception("SOLVER.LOSS: {} is set wrong. it should " raise Exception("SOLVER.LOSS: {} is set wrong. it should "
"include one of (softmax_loss, bce_loss, dice_loss) at least" "include one of (softmax_loss, bce_loss, dice_loss) at least"
" example: ['softmax_loss'], ['dice_loss'], ['bce_loss', 'dice_loss']".format(cfg.SOLVER.LOSS)) " example: ['softmax_loss'], ['dice_loss'], ['bce_loss', 'dice_loss']".format(cfg.SOLVER.LOSS))
invalid_loss = [x for x in loss_type if x not in valid_loss]
if len(invalid_loss) > 0:
print("Warning: the loss {} you set is invalid. it will not be included in loss computed.".format(invalid_loss))
avg_loss = 0 avg_loss = 0
for i in range(0, len(avg_loss_list)): for i in range(0, len(avg_loss_list)):
avg_loss += avg_loss_list[i] avg_loss += avg_loss_list[i]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册