Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/PaddlePaddle/PaddleSeg i…
Browse files Browse the repository at this point in the history
…nto develop
  • Loading branch information
wuyefeilin committed Jan 26, 2021
2 parents c95b82f + a86330d commit b596274
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 52 deletions.
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Welcome to PaddleSeg! PaddleSeg is an end-to-end image segmentation development
- [x] Cityscapes
- [x] Pascal VOC
- [x] ADE20K
- [ ] Pascal Context
- [x] Pascal Context
- [ ] COCO stuff

## Installation
Expand Down Expand Up @@ -101,3 +101,24 @@ python train.py --config configs/quick_start/bisenet_optic_disc_512x512_1k.yml
* Thanks [jm12138](https://github.com/jm12138) for contributing U<sup>2</sup>-Net.
* Thanks [zjhellofss](https://github.com/zjhellofss) (Fu Shenshen) for contributing Attention U-Net, and Dice Loss.
* Thanks [liuguoyu666](https://github.com/liguoyu666) for contributing U-Net++.

## Citation
If you find our project useful in your research, please consider citing:

```latex
@misc{liu2021paddleseg,
title={PaddleSeg: A High-Efficient Development Toolkit for Image Segmentation},
author={Yi Liu and Lutao Chu and Guowei Chen and Zewu Wu and Zeyu Chen and Baohua Lai and Yuying Hao},
year={2021},
eprint={2101.06175},
archivePrefix={arXiv},
primaryClass={cs.CV}
}
@misc{paddleseg2019,
title={PaddleSeg, End-to-end image segmentation kit based on PaddlePaddle},
author={PaddlePaddle Authors},
howpublished = {\url{https://github.com/PaddlePaddle/PaddleSeg}},
year={2019}
}
```
24 changes: 23 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ PaddleSeg是基于飞桨[PaddlePaddle](https://www.paddlepaddle.org.cn)开发的
- [x] Cityscapes
- [x] Pascal VOC
- [x] ADE20K
- [ ] Pascal Context
- [x] Pascal Context
- [ ] COCO stuff

## 安装
Expand Down Expand Up @@ -98,3 +98,25 @@ python train.py --config configs/quick_start/bisenet_optic_disc_512x512_1k.yml
* 非常感谢[jm12138](https://github.com/jm12138)贡献U<sup>2</sup>-Net模型。
* 非常感谢[zjhellofss](https://github.com/zjhellofss)(傅莘莘)贡献Attention U-Net模型,和Dice loss损失函数。
* 非常感谢[liuguoyu666](https://github.com/liguoyu666)贡献U-Net++模型。

## 学术引用

如果我们的项目在学术上帮助到你,请考虑以下引用:

```latex
@misc{liu2021paddleseg,
title={PaddleSeg: A High-Efficient Development Toolkit for Image Segmentation},
author={Yi Liu and Lutao Chu and Guowei Chen and Zewu Wu and Zeyu Chen and Baohua Lai and Yuying Hao},
year={2021},
eprint={2101.06175},
archivePrefix={arXiv},
primaryClass={cs.CV}
}
@misc{paddleseg2019,
title={PaddleSeg, End-to-end image segmentation kit based on PaddlePaddle},
author={PaddlePaddle Authors},
howpublished = {\url{https://github.com/PaddlePaddle/PaddleSeg}},
year={2019}
}
```
50 changes: 50 additions & 0 deletions configs/_base_/pascal_context.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
batch_size: 4
iters: 40000

train_dataset:
type: PascalContext
dataset_root: data/VOC2010/
transforms:
- type: ResizeStepScaling
min_scale_factor: 0.5
max_scale_factor: 2.0
scale_step_size: 0.25
- type: RandomPaddingCrop
crop_size: [520, 520]
- type: RandomHorizontalFlip
- type: RandomDistort
brightness_range: 0.4
contrast_range: 0.4
saturation_range: 0.4
- type: Normalize
mode: train

val_dataset:
type: PascalContext
dataset_root: data/VOC2010/
transforms:
- type: Padding
target_size: [520, 520]
- type: Normalize
mode: val


optimizer:
type: sgd
momentum: 0.9
weight_decay: 4.0e-5

learning_rate:
value: 0.001
decay:
type: poly
power: 0.9
end_lr: 0.0

loss:
types:
- type: CrossEntropyLoss
coef: [1]



24 changes: 24 additions & 0 deletions docs/data_prepare.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@ export PYTHONPATH=`pwd`
[ADE20K](http://sceneparsing.csail.mit.edu/)由MIT发布的可用于场景感知、分割和多物体识别等多种任务的数据集。
其涵盖了150个语义类别,包括训练集20210张,验证集2000张。

## 关于Pascal Context数据集
Pascal Context是基于PASCAL VOC 2010数据集额外标注的像素级别的语义分割数据集。我们提供的转换脚本支持59个类别,其中训练集4996, 验证集5104张.


在使用Pascal Context数据集前, 请先下载[VOC2010](http://host.robots.ox.ac.uk/pascal/VOC/voc2010/VOCtrainval_03-May-2010.tar),随后自行前往[Pascal-Context主页](https://www.cs.stanford.edu/~roozbeh/pascal-context/)下载数据集及[标注](https://codalabuser.blob.core.windows.net/public/trainval_merged.json)
我们建议您将数据集存放于`PaddleSeg/data`中,以便与我们配置文件完全兼容。数据集下载后请组织成如下结构:

VOC2010
|
|--Annotations
|
|--ImageSets
|
|--SegmentationClass
|
|--JPEGImages
|
|--SegmentationObject
|
|--trainval_merged.json

其中,标注图像的标签从1,2依次取值,不可间隔。若有需要忽略的像素,则按0进行标注。在使用Pascal Context数据集时,需要安装[Detail](https://github.com/zhanghang1989/detail-api).


## 自定义数据集

如果您需要使用自定义数据集进行训练,请按照以下步骤准备数据.
Expand Down
29 changes: 15 additions & 14 deletions paddleseg/core/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import paddle
import paddle.nn.functional as F

from paddleseg.utils import Timer, calculate_eta, resume, logger
from paddleseg.utils import TimeAverager, calculate_eta, resume, logger
from paddleseg.core.val import evaluate


Expand Down Expand Up @@ -112,24 +112,23 @@ def train(model,
from visualdl import LogWriter
log_writer = LogWriter(save_dir)

timer = Timer()
avg_loss = 0.0
avg_loss_list = []
iters_per_epoch = len(batch_sampler)
best_mean_iou = -1.0
best_model_iter = -1
train_reader_cost = 0.0
train_batch_cost = 0.0
reader_cost_averager = TimeAverager()
batch_cost_averager = TimeAverager()
save_models = deque()
timer.start()
batch_start = time.time()

iter = start_iter
while iter < iters:
for data in loader:
iter += 1
if iter > iters:
break
train_reader_cost += timer.elapsed_time()
reader_cost_averager.record(time.time() - batch_start)
images = data[0]
labels = data[1].astype('int64')
edges = None
Expand Down Expand Up @@ -160,24 +159,24 @@ def train(model,
else:
for i in range(len(loss_list)):
avg_loss_list[i] += loss_list[i]
train_batch_cost += timer.elapsed_time()
batch_cost_averager.record(
time.time() - batch_start,
num_samples=batch_size)

if (iter) % log_iters == 0 and local_rank == 0:
avg_loss /= log_iters
avg_loss_list = [
l.numpy()[0] / log_iters for l in avg_loss_list
]
avg_train_reader_cost = train_reader_cost / log_iters
avg_train_batch_cost = train_batch_cost / log_iters
train_reader_cost = 0.0
train_batch_cost = 0.0
remain_iters = iters - iter
avg_train_batch_cost = batch_cost_averager.get_average()
avg_train_reader_cost = reader_cost_averager.get_average()
eta = calculate_eta(remain_iters, avg_train_batch_cost)
logger.info(
"[TRAIN] epoch={}, iter={}/{}, loss={:.4f}, lr={:.6f}, batch_cost={:.4f}, reader_cost={:.4f} | ETA {}"
"[TRAIN] epoch={}, iter={}/{}, loss={:.4f}, lr={:.6f}, batch_cost={:.4f}, reader_cost={:.5f}, ips={:.4f} samples/sec | ETA {}"
.format((iter - 1) // iters_per_epoch + 1, iter, iters,
avg_loss, lr, avg_train_batch_cost,
avg_train_reader_cost, eta))
avg_train_reader_cost, batch_cost_averager.get_ips_average(), eta))
if use_vdl:
log_writer.add_scalar('Train/loss', avg_loss, iter)
# Record all losses if there are more than 2 losses.
Expand All @@ -196,6 +195,8 @@ def train(model,
avg_train_reader_cost, iter)
avg_loss = 0.0
avg_loss_list = []
reader_cost_averager.reset()
batch_cost_averager.reset()

if (iter % save_interval == 0
or iter == iters) and (val_dataset is not None):
Expand Down Expand Up @@ -233,7 +234,7 @@ def train(model,
if use_vdl:
log_writer.add_scalar('Evaluate/mIoU', mean_iou, iter)
log_writer.add_scalar('Evaluate/Acc', acc, iter)
timer.restart()
batch_start = time.time()

# Calculate flops.
if local_rank == 0:
Expand Down
19 changes: 14 additions & 5 deletions paddleseg/core/val.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
import os

import numpy as np
import time
import paddle
import paddle.nn.functional as F

from paddleseg.utils import metrics, Timer, calculate_eta, logger, progbar
from paddleseg.utils import metrics, TimeAverager, calculate_eta, logger, progbar
from paddleseg.core import infer

np.set_printoptions(suppress=True)
Expand Down Expand Up @@ -80,10 +81,12 @@ def evaluate(model,
logger.info("Start evaluating (total_samples={}, total_iters={})...".format(
len(eval_dataset), total_iters))
progbar_val = progbar.Progbar(target=total_iters, verbose=1)
timer = Timer()
reader_cost_averager = TimeAverager()
batch_cost_averager = TimeAverager()
batch_start = time.time()
with paddle.no_grad():
for iter, (im, label) in enumerate(loader):
reader_cost = timer.elapsed_time()
reader_cost_averager.record(time.time() - batch_start)
label = label.astype('int64')

ori_shape = label.shape[-2:]
Expand Down Expand Up @@ -141,12 +144,18 @@ def evaluate(model,
intersect_area_all = intersect_area_all + intersect_area
pred_area_all = pred_area_all + pred_area
label_area_all = label_area_all + label_area
batch_cost = timer.elapsed_time()
timer.restart()
batch_cost_averager.record(
time.time() - batch_start,
num_samples=len(label))
batch_cost = batch_cost_averager.get_average()
reader_cost = reader_cost_averager.get_average()

if local_rank == 0:
progbar_val.update(iter + 1, [('batch_cost', batch_cost),
('reader cost', reader_cost)])
reader_cost_averager.reset()
batch_cost_averager.reset()
batch_start = time.time()

class_iou, miou = metrics.mean_iou(intersect_area_all, pred_area_all,
label_area_all)
Expand Down
1 change: 1 addition & 0 deletions paddleseg/datasets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
from .voc import PascalVOC
from .ade import ADE20K
from .optic_disc_seg import OpticDiscSeg
from .pascal_context import PascalContext
77 changes: 77 additions & 0 deletions paddleseg/datasets/pascal_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright (c) 2020 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 os

from PIL import Image
from paddleseg.datasets import Dataset
from paddleseg.cvlibs import manager
from paddleseg.transforms import Compose


@manager.DATASETS.add_component
class PascalContext(Dataset):
"""
PascalVOC2010 dataset `http://host.robots.ox.ac.uk/pascal/VOC/`.
If you want to use pascal context dataset, please run the convert_voc2010.py in tools firstly.
Args:
transforms (list): Transforms for image.
dataset_root (str): The dataset directory. Default: None
mode (str): Which part of dataset to use. it is one of ('train', 'trainval', 'context', 'val').
If you want to set mode to 'context', please make sure the dataset have been augmented. Default: 'train'.
"""

def __init__(self, transforms=None, dataset_root=None, mode='train'):
self.dataset_root = dataset_root
self.transforms = Compose(transforms)
mode = mode.lower()
self.mode = mode
self.file_list = list()
self.num_classes = 59
self.ignore_index = 255

if mode not in ['train', 'trainval', 'val']:
raise ValueError(
"`mode` should be one of ('train', 'trainval', 'val') in PascalContext dataset, but got {}."
.format(mode))

if self.transforms is None:
raise ValueError("`transforms` is necessary, but it is None.")
if self.dataset_root is None:
raise ValueError(
"The dataset is not Found or the folder structure is nonconfoumance.")

image_set_dir = os.path.join(self.dataset_root, 'ImageSets','Segmentation')

if mode == 'train':
file_path = os.path.join(image_set_dir, 'train_context.txt')
elif mode == 'val':
file_path = os.path.join(image_set_dir, 'val_context.txt')
elif mode == 'trainval':
file_path = os.path.join(image_set_dir, 'trainval_context.txt')
if not os.path.exists(file_path):
raise RuntimeError(
"PASCAL-Context annotations are not ready, "
"Please make sure voc_context.py has been properly run.")

img_dir = os.path.join(self.dataset_root, 'JPEGImages')
label_dir = os.path.join(self.dataset_root, 'Context')

with open(file_path, 'r') as f:
for line in f:
line = line.strip()
image_path = os.path.join(img_dir, ''.join([line, '.jpg']))
label_path = os.path.join(label_dir, ''.join([line, '.png']))
self.file_list.append([image_path, label_path])
2 changes: 1 addition & 1 deletion paddleseg/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
from . import metrics
from .env import seg_env, get_sys_env
from .utils import *
from .timer import Timer, calculate_eta
from .timer import TimeAverager, calculate_eta
from . import visualize
Loading

0 comments on commit b596274

Please sign in to comment.