From 174919b790ecb4d8b8d38e0f38ae4dfe755ef2b2 Mon Sep 17 00:00:00 2001 From: chulutao Date: Wed, 9 Mar 2022 19:37:11 +0800 Subject: [PATCH] Support multi-channel for UNet and some transforms. Add install doc --- docs/install.md | 11 ++++ paddlers/models/gan/__init__.py | 0 paddlers/models/ppgan/__init__.py | 0 paddlers/models/ppseg/models/unet.py | 7 ++- paddlers/tasks/segmenter.py | 2 + paddlers/transforms/operators.py | 12 ++-- tutorials/train/README.md | 7 +-- .../deeplabv3p_resnet50_multi_channel.py | 15 ++--- .../semantic_segmentation/farseg_test.py | 5 +- .../unet_multi_channel.py | 59 +++++++++++++++++++ 10 files changed, 88 insertions(+), 30 deletions(-) create mode 100644 docs/install.md create mode 100644 paddlers/models/gan/__init__.py create mode 100644 paddlers/models/ppgan/__init__.py create mode 100644 tutorials/train/semantic_segmentation/unet_multi_channel.py diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000..95ac78a --- /dev/null +++ b/docs/install.md @@ -0,0 +1,11 @@ +PaddleRS develop安装 + +github代码会跟随开发进度不断更新,可以安装develop分支的代码使用最新的功能,安装方式如下: + +```commandline +git clone https://github.com/PaddleCV-SIG/PaddleRS +cd PaddleRS +git checkout develop +pip install -r requirements.txt +python setup.py install +``` diff --git a/paddlers/models/gan/__init__.py b/paddlers/models/gan/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/paddlers/models/ppgan/__init__.py b/paddlers/models/ppgan/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/paddlers/models/ppseg/models/unet.py b/paddlers/models/ppseg/models/unet.py index 5c3fdef..a932067 100644 --- a/paddlers/models/ppseg/models/unet.py +++ b/paddlers/models/ppseg/models/unet.py @@ -41,12 +41,13 @@ class UNet(nn.Layer): def __init__(self, num_classes, + input_channel=3, align_corners=False, use_deconv=False, pretrained=None): super().__init__() - self.encode = Encoder() + self.encode = Encoder(input_channel) self.decode = Decoder(align_corners, use_deconv=use_deconv) self.cls = self.conv = nn.Conv2D( in_channels=64, @@ -72,11 +73,11 @@ class UNet(nn.Layer): class Encoder(nn.Layer): - def __init__(self): + def __init__(self, input_channel=3): super().__init__() self.double_conv = nn.Sequential( - layers.ConvBNReLU(3, 64, 3), layers.ConvBNReLU(64, 64, 3)) + layers.ConvBNReLU(input_channel, 64, 3), layers.ConvBNReLU(64, 64, 3)) down_channels = [[64, 128], [128, 256], [256, 512], [512, 512]] self.down_sample_list = nn.LayerList([ self.down_sampling(channel[0], channel[1]) diff --git a/paddlers/tasks/segmenter.py b/paddlers/tasks/segmenter.py index 8e63e3d..319ddfd 100644 --- a/paddlers/tasks/segmenter.py +++ b/paddlers/tasks/segmenter.py @@ -661,6 +661,7 @@ class BaseSegmenter(BaseModel): class UNet(BaseSegmenter): def __init__(self, + input_channel=3, num_classes=2, use_mixed_loss=False, use_deconv=False, @@ -672,6 +673,7 @@ class UNet(BaseSegmenter): }) super(UNet, self).__init__( model_name='UNet', + input_channel=input_channel, num_classes=num_classes, use_mixed_loss=use_mixed_loss, **params) diff --git a/paddlers/transforms/operators.py b/paddlers/transforms/operators.py index c365093..eacd8b4 100644 --- a/paddlers/transforms/operators.py +++ b/paddlers/transforms/operators.py @@ -927,7 +927,7 @@ class RandomExpand(Transform): def __init__(self, upper_ratio=4., prob=.5, - im_padding_value=(127.5, 127.5, 127.5), + im_padding_value=127.5, label_padding_value=255): super(RandomExpand, self).__init__() assert upper_ratio > 1.01, "expand ratio must be larger than 1.01" @@ -935,10 +935,6 @@ class RandomExpand(Transform): self.prob = prob assert isinstance(im_padding_value, (Number, Sequence)), \ "fill value must be either float or sequence" - if isinstance(im_padding_value, Number): - im_padding_value = (im_padding_value, ) * 3 - if not isinstance(im_padding_value, tuple): - im_padding_value = tuple(im_padding_value) self.im_padding_value = im_padding_value self.label_padding_value = label_padding_value @@ -967,7 +963,7 @@ class Padding(Transform): target_size=None, pad_mode=0, offsets=None, - im_padding_value=(127.5, 127.5, 127.5), + im_padding_value=127.5, label_padding_value=255, size_divisor=32): """ @@ -1005,9 +1001,9 @@ class Padding(Transform): def apply_im(self, image, offsets, target_size): x, y = offsets - im_h, im_w = image.shape[:2] + im_h, im_w, channel = image.shape[:3] h, w = target_size - canvas = np.ones((h, w, 3), dtype=np.float32) + canvas = np.ones((h, w, channel), dtype=np.float32) canvas *= np.array(self.im_padding_value, dtype=np.float32) canvas[y:y + im_h, x:x + im_w, :] = image.astype(np.float32) return canvas diff --git a/tutorials/train/README.md b/tutorials/train/README.md index 5284dfe..5721444 100644 --- a/tutorials/train/README.md +++ b/tutorials/train/README.md @@ -22,14 +22,9 @@ - [PaddlePaddle安装](https://www.paddlepaddle.org.cn/install/quick) * 版本要求:PaddlePaddle>=2.1.0 - +- [PaddleRS安装](../../docs/install.md) ## 开始训练 -* 修改tutorials/train/semantic_segmentation/deeplabv3p_resnet50_multi_channel.py中sys.path路径 -``` -sys.path.append("your/PaddleRS/path") -``` - * 在安装PaddleRS后,使用如下命令开始训练,代码会自动下载训练数据, 并均使用单张GPU卡进行训练。 ```commandline diff --git a/tutorials/train/semantic_segmentation/deeplabv3p_resnet50_multi_channel.py b/tutorials/train/semantic_segmentation/deeplabv3p_resnet50_multi_channel.py index 55fc5ab..3b6c0c2 100644 --- a/tutorials/train/semantic_segmentation/deeplabv3p_resnet50_multi_channel.py +++ b/tutorials/train/semantic_segmentation/deeplabv3p_resnet50_multi_channel.py @@ -1,6 +1,5 @@ -import sys - -sys.path.append("/mnt/chulutao/PaddleRS") +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '0' import paddlers as pdrs from paddlers import transforms as T @@ -10,23 +9,21 @@ dataset = 'https://paddleseg.bj.bcebos.com/dataset/remote_sensing_seg.zip' pdrs.utils.download_and_decompress(dataset, path='./data') # 定义训练和验证时的transforms -# API说明:https://github.com/PaddlePaddle/paddlers/blob/develop/docs/apis/transforms/transforms.md channel = 10 train_transforms = T.Compose([ T.Resize(target_size=512), T.RandomHorizontalFlip(), T.Normalize( - mean=[0.5] * 10, std=[0.5] * 10), + mean=[0.5] * channel, std=[0.5] * channel), ]) eval_transforms = T.Compose([ T.Resize(target_size=512), T.Normalize( - mean=[0.5] * 10, std=[0.5] * 10), + mean=[0.5] * channel, std=[0.5] * channel), ]) # 定义训练和验证所用的数据集 -# API说明:https://github.com/PaddlePaddle/paddlers/blob/develop/docs/apis/datasets.md train_dataset = pdrs.datasets.SegDataset( data_dir='./data/remote_sensing_seg', file_list='./data/remote_sensing_seg/train.txt', @@ -44,12 +41,10 @@ eval_dataset = pdrs.datasets.SegDataset( shuffle=False) # 初始化模型,并进行训练 -# 可使用VisualDL查看训练指标,参考https://github.com/PaddlePaddle/paddlers/blob/develop/docs/visualdl.md +# 可使用VisualDL查看训练指标 num_classes = len(train_dataset.labels) model = pdrs.tasks.DeepLabV3P(input_channel=channel, num_classes=num_classes, backbone='ResNet50_vd') -# API说明:https://github.com/PaddlePaddle/paddlers/blob/develop/docs/apis/models/semantic_segmentation.md -# 各参数介绍与调整说明:https://github.com/PaddlePaddle/paddlers/blob/develop/docs/parameters.md model.train( num_epochs=10, train_dataset=train_dataset, diff --git a/tutorials/train/semantic_segmentation/farseg_test.py b/tutorials/train/semantic_segmentation/farseg_test.py index cd6654b..1762964 100644 --- a/tutorials/train/semantic_segmentation/farseg_test.py +++ b/tutorials/train/semantic_segmentation/farseg_test.py @@ -1,6 +1,5 @@ -import sys - -sys.path.append("E:/dataFiles/github/PaddleRS") +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '0' import paddlers as pdrs from paddlers import transforms as T diff --git a/tutorials/train/semantic_segmentation/unet_multi_channel.py b/tutorials/train/semantic_segmentation/unet_multi_channel.py new file mode 100644 index 0000000..b818195 --- /dev/null +++ b/tutorials/train/semantic_segmentation/unet_multi_channel.py @@ -0,0 +1,59 @@ +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '0' + +import paddlers as pdrs +from paddlers import transforms as T + +# 下载和解压多光谱地块分类数据集 +dataset = 'https://paddleseg.bj.bcebos.com/dataset/remote_sensing_seg.zip' +pdrs.utils.download_and_decompress(dataset, path='./data') + +# 定义训练和验证时的transforms +channel = 10 +train_transforms = T.Compose([ + T.Resize(target_size=512), + T.RandomHorizontalFlip(), + T.RandomBlur(1), + T.Padding(768), + T.RandomExpand(1.5, prob=1), + T.Resize(target_size=512), + T.Normalize( + mean=[0.5] * channel, std=[0.5] * channel), +]) + +eval_transforms = T.Compose([ + T.Resize(target_size=512), + T.Normalize( + mean=[0.5] * channel, std=[0.5] * channel), +]) + +# 定义训练和验证所用的数据集 +train_dataset = pdrs.datasets.SegDataset( + data_dir='./data/remote_sensing_seg', + file_list='./data/remote_sensing_seg/train.txt', + label_list='./data/remote_sensing_seg/labels.txt', + transforms=train_transforms, + num_workers=0, + shuffle=True) + +eval_dataset = pdrs.datasets.SegDataset( + data_dir='./data/remote_sensing_seg', + file_list='./data/remote_sensing_seg/val.txt', + label_list='./data/remote_sensing_seg/labels.txt', + transforms=eval_transforms, + num_workers=0, + shuffle=False) + +# 初始化模型,并进行训练 +# 可使用VisualDL查看训练指标 +num_classes = len(train_dataset.labels) +model = pdrs.tasks.UNet(input_channel=channel, num_classes=num_classes) + +model.train( + num_epochs=20, + train_dataset=train_dataset, + train_batch_size=4, + eval_dataset=eval_dataset, + learning_rate=0.01, + save_dir='output/unet', + use_vdl=True)