!18702 Pix2Pix pull request

Merge pull request !18702 from vvvvvvPeng/master
This commit is contained in:
i-robot 2021-07-06 06:45:18 +00:00 committed by Gitee
commit 4564f37262
20 changed files with 1370 additions and 0 deletions

View File

@ -0,0 +1,219 @@
# Contents
- [Pix2Pix Description](#Pix2Pix-description)
- [Model Architecture](#model-architecture)
- [Dataset](#dataset)
- [Environment Requirements](#environment-requirements)
- [Script Description](#script-description)
- [Script and Sample Code](#script-and-sample-code)
- [Script Parameters](#script-parameters)
- [Training](#training-process)
- [Evaluation](#evaluation-process)
- [Prediction Process](#prediction-process)
- [Model Description](#model-description)
- [Performance](#performance)
- [Training Performance](#evaluation-performance)
- [Evaluation Performance](#evaluation-performance)
- [ModelZoo Homepage](#modelzoo-homepage)
# [Pix2Pix Description](#contents)
Many problems in image processing, computer graphics, and computer vision can be posed as “translating” an input image into a corresponding output image, each of these tasks has been tackled with separate, special-purpose machinery, despite the fact that the setting is always the same: predict pixels from pixels.
Our goal in this paper is to develop a common framework for all these problems. Pix2pix model is a conditional GAN, which includes two modules--generator and discriminator. This model transforms an input image into a corresponding output image. The essence of the model is the mapping from pixel to pixel.
[Paper](https://arxiv.org/abs/1611.07004): Phillip Isola, Jun-Yan Zhu, Tinghui Zhou, and Alexei A. Efros. "Image-to-Image Translation with Conditional Adversarial Networks", in CVPR 2017.
![Pix2Pix Imgs](imgs/Pix2Pix-examples.jpg)
# [Model Architecture](#contents)
The Pix2Pix contains a generation network and a discriminant networks.In the generator part, the model can be any pixel to pixel mapping network (in the raw paper, the author proposed to use Unet). In the discriminator part, a patch GAN is used to judge whether each N*N patches is fake or true, thus can improve the reality of the generated image.
**Generator(Unet-Based) architectures:**
Encoder:
C64-C128-C256-C512-C512-C512-C512-C512
Decoder:
CD512-CD1024-CD1024-C1024-C1024-C512-C256-C128
**Discriminator(70 × 70 discriminator) architectures:**
C64-C128-C256-C512
**Note:** Let Ck denote a Convolution-BatchNorm-ReLU layer with k filters. CDk denotes a Convolution-BatchNorm-Dropout-ReLU layer with a dropout rate of 50%.
# [Dataset](#contents)
Dataset_1 used: [facades](http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/facades.tar.gz)
```markdown
Dataset size: 29M, 606 images
400 train images
100 validation images
106 test images
Data format.jpg images
```
Dataset_2 used: [maps](http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/maps.tar.gz)
```markdown
Dataset size: 239M, 2194 images
1096 train images
1098 validation images
Data format.jpg images
```
**Note:** We provide data/download_Pix2Pix_dataset.sh to download the datasets.
# [Environment Requirements](#contents)
- HardwareAscend
- Prepare hardware environment with Ascend processor.
- Framework
- [MindSpore](https://www.mindspore.cn/install/en)
- For more information, please check the resources below
- [MindSpore tutorials](https://www.mindspore.cn/tutorial/training/en/master/index.html)
- [MindSpore Python API](https://www.mindspore.cn/doc/api_python/en/master/index.html)
## [Dependences](#contents)
- Python==3.8.5
- Mindspore==1.2
# [Script Description](#contents)
## [Script and Sample Code](#contents)
The entire code structure is as following:
```markdown
.Pix2Pix
├─ README.md # descriptions about Pix2Pix
├─ data
└─download_Pix2Pix_dataset.sh # download dataset
├── scripts
└─run_train_ascend.sh # launch ascend training(1 pcs)
└─run_eval_ascend.sh # launch ascend eval
├─ imgs
└─Pix2Pix-examples.jpg # Pix2Pix Imgs
├─ src
├─ __init__.py # init file
├─ dataset
├─ __init__.py # init file
├─ pix2pix_dataset.py # create pix2pix dataset
├─ models
├─ __init__.py # init file
├─ discriminator_model.py # define discriminator model——Patch GAN
├─ generator_model.py # define generator model——Unet-based Generator
├─ init_w.py # initialize network weights
├─ loss.py # define losses
└─ pix2pix.py # define Pix2Pix model
└─ utils
├─ __init__.py # init file
├─ config.py # parse args
├─ tools.py # tools for Pix2Pix model
├─ eval.py # evaluate Pix2Pix Model
├─ train.py # train script
└─ export.py # export mindir script
```
## [Script Parameters](#contents)
Major parameters in train.py and config.py as follows:
```python
"device_target": Ascend # run platform, only support Ascend.
"device_num": 1 # device num, default is 1.
"device_id": 0 # device id, default is 0.
"save_graphs": False # whether save graphs, default is False.
"init_type": normal # network initialization, default is normal.
"init_gain": 0.02 # scaling factor for normal, xavier and orthogonal, default is 0.02.
"load_size": 286 # scale images to this size, default is 286.
"batch_size": 1 # batch_size, default is 1.
"LAMBDA_Dis": 0.5 # weight for Discriminator Loss, default is 0.5.
"LAMBDA_GAN": 1 # weight for GAN Loss, default is 1.
"LAMBDA_L1": 100 # weight for L1 Loss, default is 100.
"beta1": 0.5 # adam beta1, default is 0.5.
"beta2": 0.999 # adam beta2, default is 0.999.
"lr": 0.0002 # the initial learning rate, default is 0.0002.
"lr_policy": linear # learning rate policy, default is linear.
"epoch_num": 200 # epoch number for training, default is 200.
"n_epochs": 100 # number of epochs with the initial learning rate, default is 100.
"n_epochs_decay": 100 # number of epochs with the dynamic learning rate, default is 100.
"dataset_size": 400 # for Facade_dataset,the number is 400; for Maps_dataset,the number is 1096.
"train_data_dir": None # the file path of input data during training.
"val_data_dir": None # the file path of input data during validating.
"train_fakeimg_dir": ./results/fake_img/ # during training, the file path of stored fake img.
"loss_show_dir": ./results/loss_show # during training, the file path of stored loss img.
"ckpt_dir": ./results/ckpt # during training, the file path of stored CKPT.
"ckpt": None # during validating, the file path of the CKPT used.
"predict_dir": ./results/predict/ # during validating, the file path of Generated images.
```
## [Training](#contents)
- running on Ascend with default parameters
```python
python train.py --device_target [Ascend] --device_id [0] --train_data_dir [./data/facades/train]
```
## [Evaluation](#contents)
```python
python eval.py --device_target [Ascend] --device_id [0] --val_data_dir [./data/facades/test] --ckpt [./results/ckpt/Generator_200.ckpt]
```
**Note:**: Before training and evaluating, create folders like "./results/...". Then you will get the results as following in "./results/predict".
# [Model Description](#contents)
## [Performance](#contents)
### Training Performance
| Parameters | single Ascend |
| -------------------------- | ----------------------------------------------------------- |
| Model Version | Pix2Pix |
| Resource | Ascend 910 |
| MindSpore Version | 1.2 |
| Dataset | facades |
| Training Parameters | epoch=200, steps=400, batch_size=1, lr=0.0002 |
| Optimizer | Adam |
| Loss Function | SigmoidCrossEntropyWithLogits Loss & L1 Loss |
| outputs | probability |
| Speed | 1pc(Ascend): 10 ms/step |
| Total time | 1pc(Ascend): 0.3h |
| Checkpoint for Fine tuning | 207M (.ckpt file) |
| Parameters | single Ascend |
| -------------------------- | ----------------------------------------------------------- |
| Model Version | Pix2Pix |
| Resource | Ascend 910 |
| MindSpore Version | 1.2 |
| Dataset | maps |
| Training Parameters | epoch=200, steps=1096, batch_size=1, lr=0.0002 |
| Optimizer | Adam |
| Loss Function | SigmoidCrossEntropyWithLogits Loss & L1 Loss |
| outputs | probability |
| Speed | 1pc(Ascend): 20 ms/step |
| Total time | 1pc(Ascend): 1.58h |
| Checkpoint for Fine tuning | 207M (.ckpt file) |
### Evaluation Performance
| Parameters | single Ascend |
| ------------------- | --------------------------- |
| Model Version | Pix2Pix |
| Resource | Ascend 910 |
| MindSpore Version | 1.2 |
| Dataset | facades / maps |
| batch_size | 1 |
| outputs | probability |
# [ModelZoo Homepage](#contents)
Please check the official [homepage](https://gitee.com/mindspore/mindspore/tree/master/model_zoo).

View File

@ -0,0 +1,36 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
FILE=$1
if [[ $FILE != "maps" && $FILE != "facades" ]]; then
echo "Available datasets are: maps, cityscapes, facades"
exit 1
fi
if [[ $FILE == "cityscapes" ]]; then
echo "Due to license issue, we cannot provide the Cityscapes dataset from our repository. Please download the Cityscapes dataset from https://cityscapes-dataset.com, and use the script ./datasets/prepare_cityscapes_dataset.py."
echo "You need to download gtFine_trainvaltest.zip and leftImg8bit_trainvaltest.zip. For further instruction, please read ./datasets/prepare_cityscapes_dataset.py"
exit 1
fi
echo "Specified [$FILE]"
URL=http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/$FILE.tar.gz
ZIP_FILE=./datasets/$FILE.tar.gz
TARGET_DIR=./datasets/$FILE/
wget -N $URL -O $ZIP_FILE
mkdir $TARGET_DIR
tar -zxvf $ZIP_FILE
rm $ZIP_FILE

View File

@ -0,0 +1,74 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
"""
Evaluate Pix2Pix Model.
"""
from mindspore import Tensor, nn
from mindspore.train.serialization import load_checkpoint
from mindspore.train.serialization import load_param_into_net
from src.dataset.pix2pix_dataset import pix2pixDataset_val, create_val_dataset
from src.models.pix2pix import Pix2Pix, get_generator, get_discriminator
from src.models.loss import D_Loss, D_WithLossCell, G_Loss, G_WithLossCell, TrainOneStepCell
from src.utils.tools import save_image, get_lr
from src.utils.config import get_args
if __name__ == '__main__':
args = get_args()
# Preprocess the data for evaluating
dataset_val = pix2pixDataset_val(root_dir=args.val_data_dir)
ds_val = create_val_dataset(dataset_val)
print("ds:", ds_val.get_dataset_size())
print("ds:", ds_val.get_col_names())
print("ds.shape:", ds_val.output_shapes())
steps_per_epoch = ds_val.get_dataset_size()
netG = get_generator()
netD = get_discriminator()
pix2pix = Pix2Pix(generator=netG, discriminator=netD)
d_loss_fn = D_Loss()
g_loss_fn = G_Loss()
d_loss_net = D_WithLossCell(backbone=pix2pix, loss_fn=d_loss_fn)
g_loss_net = G_WithLossCell(backbone=pix2pix, loss_fn=g_loss_fn)
d_opt = nn.Adam(pix2pix.netD.trainable_params(), learning_rate=get_lr(),
beta1=args.beta1, beta2=args.beta2, loss_scale=1)
g_opt = nn.Adam(pix2pix.netG.trainable_params(), learning_rate=get_lr(),
beta1=args.beta1, beta2=args.beta2, loss_scale=1)
train_net = TrainOneStepCell(loss_netD=d_loss_net, loss_netG=g_loss_net, optimizerD=d_opt, optimizerG=g_opt, sens=1)
train_net.set_train()
# Evaluating loop
ckpt_url = args.ckpt
print("CKPT:", ckpt_url)
param_G = load_checkpoint(ckpt_url)
load_param_into_net(netG, param_G)
data_loader_val = ds_val.create_dict_iterator(output_numpy=True, num_epochs=args.epoch_num)
print("=======Starting evaluating Loop=======")
for i, data in enumerate(data_loader_val):
input_image = Tensor(data["input_images"])
target_image = Tensor(data["target_images"])
fake_image = netG(input_image)
save_image(fake_image, args.predict_dir + str(i + 1))
print("=======image", i + 1, "saved success=======")

View File

@ -0,0 +1,75 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
"""
export checkpoint file into air, onnx, mindir models
"""
import argparse
import ast
import numpy as np
from mindspore import Tensor, nn, context
from mindspore.train.serialization import export
from mindspore.train.serialization import load_checkpoint
from mindspore.train.serialization import load_param_into_net
from src.models.pix2pix import Pix2Pix, get_generator, get_discriminator
from src.models.loss import D_Loss, D_WithLossCell, G_Loss, G_WithLossCell, TrainOneStepCell
from src.utils.tools import get_lr
parser = argparse.ArgumentParser(description='export')
parser.add_argument("--run_modelart", type=ast.literal_eval, default=False, help="Run on modelArt, default is false.")
parser.add_argument("--device_id", type=int, default=0, help="device id, default is 0.")
parser.add_argument("--batch_size", type=int, default=1, help="batch_size, default is 1.")
parser.add_argument("--image_size", type=int, default=256, help="images size, default is 256.")
parser.add_argument('--ckpt_dir', type=str, default='./results/ckpt',
help='during training, the file path of stored CKPT.')
parser.add_argument("--ckpt", type=str, default=None, help="during validating, the file path of the CKPT used.")
parser.add_argument('--train_data_dir', type=str, default=None, help='the file path of input data during training.')
parser.add_argument("--file_name", type=str, default="Pix2Pix", help="output file name.")
parser.add_argument("--file_format", type=str, default="AIR", choices=["AIR", "ONNX", "MINDIR"], help="file format")
parser.add_argument('--device_target', type=str, default='Ascend', choices=('Ascend', 'GPU'),
help='device where the code will be implemented (default: Ascend)')
args = parser.parse_args()
context.set_context(mode=context.GRAPH_MODE, device_target=args.device_target, device_id=args.device_id)
if __name__ == '__main__':
netG = get_generator()
netD = get_discriminator()
pix2pix = Pix2Pix(generator=netG, discriminator=netD)
d_loss_fn = D_Loss()
g_loss_fn = G_Loss()
d_loss_net = D_WithLossCell(backbone=pix2pix, loss_fn=d_loss_fn)
g_loss_net = G_WithLossCell(backbone=pix2pix, loss_fn=g_loss_fn)
d_opt = nn.Adam(pix2pix.netD.trainable_params(), learning_rate=get_lr(), beta1=0.5, beta2=0.999, loss_scale=1)
g_opt = nn.Adam(pix2pix.netG.trainable_params(), learning_rate=get_lr(), beta1=0.5, beta2=0.999, loss_scale=1)
train_net = TrainOneStepCell(loss_netD=d_loss_net, loss_netG=g_loss_net, optimizerD=d_opt, optimizerG=g_opt, sens=1)
train_net.set_train()
train_net = train_net.loss_netG
ckpt_url = args.ckpt
param_G = load_checkpoint(ckpt_url)
load_param_into_net(netG, param_G)
input_shp = [args.batch_size, 3, args.image_size, args.image_size]
input_array = Tensor(np.random.uniform(-1.0, 1.0, size=input_shp).astype(np.float32))
target_shp = [args.batch_size, 3, args.image_size, args.image_size]
target_array = Tensor(np.random.uniform(-1.0, 1.0, size=target_shp).astype(np.float32))
inputs = [input_array, target_array]
file = f"{args.file_name}"
export(train_net, *inputs, file_name=file, file_format=args.file_format)

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

View File

@ -0,0 +1,22 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
echo "======================================================================================================================================="
echo "Please run the eval as: "
echo "python eval.py device_target device_id val_data_dir ckpt"
echo "for example: python eval.py --device_target Ascend --device_id 0 --val_data_dir ./facades/test --ckpt ./results/ckpt/Generator_200.ckpt"
echo "======================================================================================================================================="
python eval.py --device_target Ascend --device_id 0 --val_data_dir ./facades/test --ckpt ./results/ckpt/Generator_200.ckpt

View File

@ -0,0 +1,22 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
echo "====================================================================================================================="
echo "Please run the train as: "
echo "python train.py device_target device_id dataset_size train_data_dir"
echo "for example: python train.py --device_target Ascend --device_id 0 --dataset_size 400 --train_data_dir ./facades/train"
echo "====================================================================================================================="
python train.py --device_target Ascend --device_id 0 --dataset_size 400 --train_data_dir ./facades/train

View File

@ -0,0 +1,173 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
'''
Preprocess Pix2Pix dataset.
'''
import os
import numpy as np
from PIL import Image
import mindspore
from mindspore import dataset as de
import mindspore.dataset.vision.c_transforms as C
from ..utils.config import get_args
args = get_args()
class pix2pixDataset():
'''
Define train dataset.
'''
def __init__(self, root_dir):
self.root_dir = root_dir
self.list_files = os.listdir(self.root_dir)
self.list_files.sort(key=lambda x: int(x[:-4]))
print(self.list_files)
def __len__(self):
return len(self.list_files)
def __getitem__(self, index):
img_file = self.list_files[index]
img_path = os.path.join(self.root_dir, img_file)
AB = Image.open(img_path).convert('RGB')
w, h = AB.size
w2 = int(w / 2)
A = AB.crop((w2, 0, w, h))
B = AB.crop((0, 0, w2, h))
A = A.resize((args.load_size, args.load_size))
B = B.resize((args.load_size, args.load_size))
transform_params = get_params(A.size)
A_crop = crop(A, transform_params, size=256)
B_crop = crop(B, transform_params, size=256)
return A_crop, B_crop
def get_params(size=(256, 256)):
'''
Get parameters from images.
'''
w, h = size
new_h = h
new_w = w
new_h = new_w = args.load_size # args.load_size
x = np.random.randint(0, np.maximum(0, new_w - 256))
y = np.random.randint(0, np.maximum(0, new_h - 256))
return (x, y)
def crop(img, pos, size=256):
'''
Crop the images.
'''
ow = oh = args.load_size
x1, y1 = pos
tw = th = size
if (ow > tw or oh > th):
img = img.crop((x1, y1, x1 + tw, y1 + th))
return img
return img
def sync_random_Horizontal_Flip(input_images, target_images):
'''
Randomly flip the input images and the target images.
'''
seed = np.random.randint(0, 2000000000)
mindspore.set_seed(seed)
op = C.RandomHorizontalFlip(prob=0.5)
out_input = op(input_images)
mindspore.set_seed(seed)
op = C.RandomHorizontalFlip(prob=0.5)
out_target = op(target_images)
return out_input, out_target
def create_train_dataset(dataset):
'''
Create train dataset.
'''
mean = [0.5 * 255] * 3
std = [0.5 * 255] * 3
trans = [
C.Normalize(mean=mean, std=std),
C.HWC2CHW()
]
train_ds = de.GeneratorDataset(dataset, column_names=["input_images", "target_images"], shuffle=False)
train_ds = train_ds.map(operations=[sync_random_Horizontal_Flip], input_columns=["input_images", "target_images"])
train_ds = train_ds.map(operations=trans, input_columns=["input_images"])
train_ds = train_ds.map(operations=trans, input_columns=["target_images"])
train_ds = train_ds.batch(1, drop_remainder=True)
train_ds = train_ds.repeat(1)
return train_ds
class pix2pixDataset_val():
'''
Define val dataset.
'''
def __init__(self, root_dir):
self.root_dir = root_dir
self.list_files = os.listdir(self.root_dir)
self.list_files.sort(key=lambda x: int(x[:-4]))
print(self.list_files)
def __len__(self):
return len(self.list_files)
def __getitem__(self, index):
img_file = self.list_files[index]
img_path = os.path.join(self.root_dir, img_file)
AB = Image.open(img_path).convert('RGB')
w, h = AB.size
w2 = int(w / 2)
A = AB.crop((w2, 0, w, h))
B = AB.crop((0, 0, w2, h))
return A, B
def create_val_dataset(dataset):
'''
Create val dataset.
'''
mean = [0.5 * 255] * 3
std = [0.5 * 255] * 3
trans = [
C.Resize((256, 256)),
C.Normalize(mean=mean, std=std),
C.HWC2CHW()
]
val_ds = de.GeneratorDataset(dataset, column_names=["input_images", "target_images"], shuffle=False)
val_ds = val_ds.map(operations=trans, input_columns=["input_images"])
val_ds = val_ds.map(operations=trans, input_columns=["target_images"])
val_ds = val_ds.batch(1, drop_remainder=True)
val_ds = val_ds.repeat(1)
return val_ds

View File

@ -0,0 +1,118 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
'''
Define discriminator modelPatch GAN.
'''
import mindspore.nn as nn
from mindspore.ops import Concat
class ConvNormReLU(nn.Cell):
"""
Convolution fused with BatchNorm/InstanceNorm and ReLU/LackyReLU block definition.
Args:
in_planes (int): Input channel.
out_planes (int): Output channel.
kernel_size (int): Input kernel size. Default: 4.
stride (int): Stride size for the first convolutional layer. Default: 2.
alpha (float): Slope of LackyReLU. Default: 0.2.
norm_mode (str): Specifies norm method. The optional values are "batch", "instance".
pad_mode (str): Specifies padding mode. The optional values are "CONSTANT", "REFLECT", "SYMMETRIC".
Default: "CONSTANT".
use_relu (bool): Use relu or not. Default: True.
padding (int): Pad size, if it is None, it will calculate by kernel_size. Default: None.
Returns:
Tensor, output tensor.
"""
def __init__(self,
in_planes,
out_planes,
kernel_size=4,
stride=2,
alpha=0.2,
norm_mode='batch',
pad_mode='CONSTANT',
use_relu=True,
padding=None):
super(ConvNormReLU, self).__init__()
norm = nn.BatchNorm2d(out_planes)
if norm_mode == 'instance':
# Use BatchNorm2d with batchsize=1, affine=False, training=True instead of InstanceNorm2d
norm = nn.BatchNorm2d(out_planes, affine=False)
has_bias = (norm_mode == 'instance')
if padding is None:
padding = (kernel_size - 1) // 2
if pad_mode == 'CONSTANT':
conv = nn.Conv2d(in_planes, out_planes, kernel_size, stride, pad_mode='pad',
has_bias=has_bias, padding=padding)
layers = [conv, norm]
else:
paddings = ((0, 0), (0, 0), (padding, padding), (padding, padding))
pad = nn.Pad(paddings=paddings, mode=pad_mode)
conv = nn.Conv2d(in_planes, out_planes, kernel_size, stride, pad_mode='pad', has_bias=has_bias)
layers = [pad, conv, norm]
if use_relu:
relu = nn.ReLU()
if alpha > 0:
relu = nn.LeakyReLU(alpha)
layers.append(relu)
self.features = nn.SequentialCell(layers)
def construct(self, x):
output = self.features(x)
return output
class Discriminator(nn.Cell):
"""
Discriminator of Model.
Args:
in_planes (int): Input channel.
ndf (int): the number of filters in the last conv layer
n_layers (int): The number of ConvNormReLU blocks.
alpha (float): LeakyRelu slope. Default: 0.2.
norm_mode (str): Specifies norm method. The optional values are "batch", "instance".
Returns:
Tensor, output tensor.
"""
def __init__(self, in_planes=3, ndf=64, n_layers=3, alpha=0.2, norm_mode='batch'):
super(Discriminator, self).__init__()
kernel_size = 4
layers = [
nn.Conv2d(in_planes, ndf, kernel_size, 2, pad_mode='pad', padding=1),
nn.LeakyReLU(alpha)
]
nf_mult = ndf
for i in range(1, n_layers):
nf_mult_prev = nf_mult
nf_mult = min(2 ** i, 8) * ndf
layers.append(ConvNormReLU(nf_mult_prev, nf_mult, kernel_size, 2, alpha, norm_mode, padding=1))
nf_mult_prev = nf_mult
nf_mult = min(2 ** n_layers, 8) * ndf
layers.append(ConvNormReLU(nf_mult_prev, nf_mult, kernel_size, 1, alpha, norm_mode, padding=1))
layers.append(nn.Conv2d(nf_mult, 1, kernel_size, 1, pad_mode='pad', padding=1))
self.features = nn.SequentialCell(layers)
self.concat = Concat(axis=1)
def construct(self, x, y):
x_y = self.concat((x, y))
output = self.features(x_y)
return output

View File

@ -0,0 +1,127 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
'''
Define generator modelUnet-based Generator.
'''
import mindspore.nn as nn
import mindspore.ops as ops
class UnetGenerator(nn.Cell):
"""
Unet-based generator.
Args:
in_planes (int): the number of channels in input images.
out_planes (int): the number of channels in output images.
ngf (int): the number of filters in the last conv layer.
n_layers (int): the number of downsamplings in UNet.
alpha (float): LeakyRelu slope. Default: 0.2.
norm_mode (str): Specifies norm method. The optional values are "batch", "instance".
dropout (bool): Use dropout or not. Default: False.
Returns:
Tensor, output tensor.
"""
def __init__(self, in_planes, out_planes, ngf=64, n_layers=8, alpha=0.2, norm_mode='bn', dropout=False):
super(UnetGenerator, self).__init__()
# construct unet structure
unet_block = UnetSkipConnectionBlock(ngf * 8, ngf * 8, in_planes=None, submodule=None,
norm_mode=norm_mode, innermost=True)
for _ in range(n_layers - 5):
unet_block = UnetSkipConnectionBlock(ngf * 8, ngf * 8, in_planes=None, submodule=unet_block,
norm_mode=norm_mode, dropout=dropout)
# gradually reduce the number of filters from ngf * 8 to ngf
unet_block = UnetSkipConnectionBlock(ngf * 4, ngf * 8, in_planes=None, submodule=unet_block,
norm_mode=norm_mode)
unet_block = UnetSkipConnectionBlock(ngf * 2, ngf * 4, in_planes=None, submodule=unet_block,
norm_mode=norm_mode)
unet_block = UnetSkipConnectionBlock(ngf, ngf * 2, in_planes=None, submodule=unet_block, norm_mode=norm_mode)
self.model = UnetSkipConnectionBlock(out_planes, ngf, in_planes=in_planes, submodule=unet_block,
outermost=True, norm_mode=norm_mode)
def construct(self, x):
return self.model(x)
class UnetSkipConnectionBlock(nn.Cell):
"""Unet submodule with skip connection.
Args:
outer_nc (int): The number of filters in the outer conv layer
inner_nc (int): The number of filters in the inner conv layer
in_planes (int): The number of channels in input images/features
dropout (bool): Use dropout or not. Default: False.
submodule (Cell): Previously defined submodules
outermost (bool): If this module is the outermost module
innermost (bool): If this module is the innermost module
alpha (float): LeakyRelu slope. Default: 0.2.
norm_mode (str): Specifies norm method. The optional values are "batch", "instance".
Returns:
Tensor, output tensor.
"""
def __init__(self, outer_nc, inner_nc, in_planes=None, dropout=False,
submodule=None, outermost=False, innermost=False, alpha=0.2, norm_mode='batch'):
super(UnetSkipConnectionBlock, self).__init__()
downnorm = nn.BatchNorm2d(inner_nc)
upnorm = nn.BatchNorm2d(outer_nc)
use_bias = False
if norm_mode == 'instance':
downnorm = nn.BatchNorm2d(inner_nc, affine=False)
upnorm = nn.BatchNorm2d(outer_nc, affine=False)
use_bias = True
if in_planes is None:
in_planes = outer_nc
downconv = nn.Conv2d(in_planes, inner_nc, kernel_size=4,
stride=2, padding=1, has_bias=use_bias, pad_mode='pad')
downrelu = nn.LeakyReLU(alpha)
uprelu = nn.ReLU()
if outermost:
upconv = nn.Conv2dTranspose(inner_nc * 2, outer_nc,
kernel_size=4, stride=2,
padding=1, pad_mode='pad')
down = [downconv]
up = [uprelu, upconv, nn.Tanh()]
model = down + [submodule] + up
elif innermost:
upconv = nn.Conv2dTranspose(inner_nc, outer_nc,
kernel_size=4, stride=2,
padding=1, has_bias=use_bias, pad_mode='pad')
down = [downrelu, downconv]
up = [uprelu, upconv, upnorm]
model = down + up
else:
upconv = nn.Conv2dTranspose(inner_nc * 2, outer_nc,
kernel_size=4, stride=2,
padding=1, has_bias=use_bias, pad_mode='pad')
down = [downrelu, downconv, downnorm]
up = [uprelu, upconv, upnorm]
model = down + [submodule] + up
if dropout:
model.append(nn.Dropout(0.5))
self.model = nn.SequentialCell(model)
self.skip_connections = not outermost
self.concat = ops.Concat(axis=1)
def construct(self, x):
out = self.model(x)
if self.skip_connections:
out = self.concat((out, x))
return out

View File

@ -0,0 +1,43 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
"""
Initialize network weights.
"""
import mindspore.nn as nn
from mindspore.common import initializer as init
def init_weights(net, init_type='normal', init_gain=0.02):
"""
Initialize network weights.
Parameters:
net (Cell): Network to be initialized
init_type (str): The name of an initialization method: normal | xavier.
init_gain (float): Gain factor for normal and xavier.
"""
for _, cell in net.cells_and_names():
if isinstance(cell, (nn.Conv2d, nn.Conv2dTranspose)):
if init_type == 'normal':
cell.weight.set_data(init.initializer(init.Normal(init_gain), cell.weight.shape))
elif init_type == 'xavier':
cell.weight.set_data(init.initializer(init.XavierUniform(init_gain), cell.weight.shape))
elif init_type == 'constant':
cell.weight.set_data(init.initializer(0.001, cell.weight.shape))
else:
raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
elif isinstance(cell, nn.BatchNorm2d):
cell.gamma.set_data(init.initializer('ones', cell.gamma.shape))
cell.beta.set_data(init.initializer('zeros', cell.beta.shape))

View File

@ -0,0 +1,158 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
"""
Define losses.
"""
import mindspore.nn as nn
import mindspore.ops as ops
from mindspore.ops import functional as F
import mindspore.ops.operations as P
from mindspore.parallel._utils import (_get_device_num, _get_gradients_mean, _get_parallel_mode)
from mindspore.context import ParallelMode
from mindspore.nn.wrap.grad_reducer import DistributedGradReducer
from mindspore.nn.loss.loss import _Loss
from src.utils.config import get_args
args = get_args()
class SigmoidCrossEntropyWithLogits(_Loss):
def __init__(self):
super(SigmoidCrossEntropyWithLogits, self).__init__()
self.cross_entropy = P.SigmoidCrossEntropyWithLogits()
def construct(self, data, label):
x = self.cross_entropy(data, label)
return self.get_loss(x)
class D_Loss(_Loss):
"""
Define Dloss.
"""
def __init__(self, reduction="mean"):
super(D_Loss, self).__init__(reduction)
self.sig = SigmoidCrossEntropyWithLogits()
self.ones = ops.OnesLike()
self.zeros = ops.ZerosLike()
self.LAMBDA_Dis = args.LAMBDA_Dis
def construct(self, pred1, pred0):
loss = self.sig(pred1, self.ones(pred1)) + self.sig(pred0, self.zeros(pred0))
dis_loss = loss * self.LAMBDA_Dis
return dis_loss
class D_WithLossCell(nn.Cell):
"""
Define D_WithLossCell.
"""
def __init__(self, backbone, loss_fn):
super(D_WithLossCell, self).__init__(auto_prefix=True)
self.netD = backbone.netD
self.netG = backbone.netG
self._loss_fn = loss_fn
def construct(self, realA, realB):
fakeB = self.netG(realA)
pred1 = self.netD(realA, realB)
pred0 = self.netD(realA, fakeB)
return self._loss_fn(pred1, pred0)
class G_Loss(_Loss):
"""
Define Gloss.
"""
def __init__(self, reduction="mean"):
super(G_Loss, self).__init__(reduction)
self.sig = SigmoidCrossEntropyWithLogits()
self.l1_loss = nn.L1Loss()
self.ones = ops.OnesLike()
self.LAMBDA_GAN = args.LAMBDA_GAN
self.LAMBDA_L1 = args.LAMBDA_L1
def construct(self, fakeB, realB, pred0):
loss_1 = self.sig(pred0, self.ones(pred0))
loss_2 = self.l1_loss(fakeB, realB)
loss = loss_1 * self.LAMBDA_GAN + loss_2 * self.LAMBDA_L1
return loss
class G_WithLossCell(nn.Cell):
"""
Define G_WithLossCell.
"""
def __init__(self, backbone, loss_fn):
super(G_WithLossCell, self).__init__(auto_prefix=True)
self.netD = backbone.netD
self.netG = backbone.netG
self._loss_fn = loss_fn
def construct(self, realA, realB):
fakeB = self.netG(realA)
pred0 = self.netD(realA, fakeB)
return self._loss_fn(fakeB, realB, pred0)
class TrainOneStepCell(nn.Cell):
"""
Define TrainOneStepCell.
"""
def __init__(self, loss_netD, loss_netG, optimizerD, optimizerG, sens=1, auto_prefix=True):
super(TrainOneStepCell, self).__init__(auto_prefix=auto_prefix)
self.loss_netD = loss_netD # loss network
self.loss_netD.set_grad()
self.loss_netD.add_flags(defer_inline=True)
self.loss_netG = loss_netG
self.loss_netG.set_grad()
self.loss_netG.add_flags(defer_inline=True)
self.weights_G = optimizerG.parameters
self.optimizerG = optimizerG
self.weights_D = optimizerD.parameters
self.optimizerD = optimizerD
self.grad = ops.GradOperation(get_by_list=True, sens_param=True)
self.sens = sens
# 并行处理的定义
self.reducer_flag = False
self.grad_reducer_G = F.identity
self.grad_reducer_D = F.identity
self.parallel_mode = _get_parallel_mode()
if self.parallel_mode in (ParallelMode.DATA_PARALLEL, ParallelMode.HYBRID_PARALLEL):
self.reducer_flag = True
if self.reducer_flag:
mean = _get_gradients_mean()
degree = _get_device_num()
self.grad_reducer_G = DistributedGradReducer(self.weights_G, mean, degree)
self.grad_reducer_D = DistributedGradReducer(self.weights_D, mean, degree)
def set_sens(self, value):
self.sens = value
def construct(self, realA, realB):
"""
Define TrainOneStepCell.
"""
d_loss = self.loss_netD(realA, realB)
g_loss = self.loss_netG(realA, realB)
d_sens = ops.Fill()(ops.DType()(d_loss), ops.Shape()(d_loss), self.sens)
d_grads = self.grad(self.loss_netD, self.weights_D)(realA, realB, d_sens)
d_res = ops.depend(d_loss, self.optimizerD(d_grads))
g_sens = ops.Fill()(ops.DType()(g_loss), ops.Shape()(g_loss), self.sens)
g_grads = self.grad(self.loss_netG, self.weights_G)(realA, realB, g_sens)
g_res = ops.depend(g_loss, self.optimizerG(g_grads))
return d_res, g_res

View File

@ -0,0 +1,53 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
"""
Define Pix2Pix model.
"""
import mindspore.nn as nn
from .generator_model import UnetGenerator
from .discriminator_model import Discriminator
from .init_w import init_weights
from ..utils.config import get_args
args = get_args()
class Pix2Pix(nn.Cell):
def __init__(self, discriminator, generator):
super(Pix2Pix, self).__init__(auto_prefix=True)
self.netD = discriminator
self.netG = generator
def construct(self, realA, realB):
fakeB = self.netG(realA)
return fakeB
def get_generator():
"""
Return a generator by args.
"""
netG = UnetGenerator(in_planes=3, out_planes=3)
init_weights(netG, init_type=args.init_type, init_gain=args.init_gain)
return netG
def get_discriminator():
"""
Return a discriminator by args.
"""
netD = Discriminator(in_planes=6, ndf=64, n_layers=3)
init_weights(netD, init_type=args.init_type, init_gain=args.init_gain)
return netD

View File

@ -0,0 +1,74 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
"""
Define the common options that are used in both training and test.
"""
import argparse
import ast
from mindspore import context
def get_args():
'''
get args.
'''
parser = argparse.ArgumentParser(description='Pix2Pix Model')
# parameters
parser.add_argument('--device_target', type=str, default='Ascend', choices=('Ascend', 'GPU'),
help='device where the code will be implemented (default: Ascend)')
parser.add_argument('--device_num', type=int, default=1, help='device num, default is 1.')
parser.add_argument('--device_id', type=int, default=6, help='device id, default is 0.')
parser.add_argument('--save_graphs', type=ast.literal_eval, default=False,
help='whether save graphs, default is False.')
parser.add_argument('--init_type', type=str, default='normal', help='network initialization, default is normal.')
parser.add_argument('--init_gain', type=float, default=0.02,
help='scaling factor for normal, xavier and orthogonal, default is 0.02.')
parser.add_argument('--load_size', type=int, default=286, help='scale images to this size, default is 286.')
parser.add_argument('--batch_size', type=int, default=1, help='batch_size, default is 1.')
parser.add_argument('--LAMBDA_Dis', type=float, default=0.5, help='weight for Discriminator Loss, default is 0.5.')
parser.add_argument('--LAMBDA_GAN', type=int, default=1, help='weight for GAN Loss, default is 1.')
parser.add_argument('--LAMBDA_L1', type=int, default=100, help='weight for L1 Loss, default is 100.')
parser.add_argument('--beta1', type=float, default=0.5, help='adam beta1, default is 0.5.')
parser.add_argument('--beta2', type=float, default=0.999, help='adam beta2, default is 0.999.')
parser.add_argument('--lr', type=float, default=0.0002, help='the initial learning rate, default is 0.0002.')
parser.add_argument('--lr_policy', type=str, default='linear', help='learning rate policy, default is linear.')
parser.add_argument('--epoch_num', type=int, default=200, help='epoch number for training, default is 200.')
parser.add_argument('--n_epochs', type=int, default=100,
help='number of epochs with the initial learning rate, default is 100.')
parser.add_argument('--n_epochs_decay', type=int, default=100,
help='number of epochs with the dynamic learning rate, default is 100.')
parser.add_argument('--dataset_size', type=int, default=400, choices=(400, 1096),
help='for Facade_dataset,the number is 400; for Maps_dataset,the number is 1096.')
# The location of input and output data
parser.add_argument('--train_data_dir', type=str, default=None, help='the file path of input data during training.')
parser.add_argument('--val_data_dir', type=str, default=None, help='the file path of input data during validating.')
parser.add_argument('--train_fakeimg_dir', type=str, default='./results/fake_img/',
help='during training, the file path of stored fake img.')
parser.add_argument('--loss_show_dir', type=str, default='./results/loss_show',
help='during training, the file path of stored loss img.')
parser.add_argument('--ckpt_dir', type=str, default='./results/ckpt',
help='during training, the file path of stored CKPT.')
parser.add_argument('--ckpt', type=str, default=None, help='during validating, the file path of the CKPT used.')
parser.add_argument('--predict_dir', type=str, default='./results/predict/',
help='during validating, the file path of Generated image.')
args = parser.parse_args()
context.set_context(mode=context.GRAPH_MODE, device_target=args.device_target, device_id=args.device_id)
return args

View File

@ -0,0 +1,74 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
"""
Tools for Pix2Pix model.
"""
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from mindspore import Tensor
from src.utils.config import get_args
args = get_args()
def save_losses(G_losses, D_losses, idx):
plt.figure(figsize=(10, 5))
plt.title("Generator and Discriminator Loss During Training")
plt.plot(G_losses, label="G")
plt.plot(D_losses, label="D")
plt.xlabel("iterations")
plt.ylabel("Losses")
plt.legend()
plt.savefig(args.loss_show_dir+"/{}.png".format(idx))
def save_image(img, img_path):
"""Save a numpy image to the disk
Parameters:
img (numpy array / Tensor): image to save.
image_path (str): the path of the image.
"""
if isinstance(img, Tensor):
img = decode_image(img)
elif not isinstance(img, np.ndarray):
raise ValueError("img should be Tensor or numpy array, but get {}".format(type(img)))
img_pil = Image.fromarray(img)
img_pil.save(img_path+".jpg")
def decode_image(img):
"""Decode a [1, C, H, W] Tensor to image numpy array."""
mean = 0.5 * 255
std = 0.5 * 255
return (img.asnumpy()[0] * std + mean).astype(np.uint8).transpose((1, 2, 0)) # ——>2562563
def get_lr():
"""
Linear learning-rate generator.
Keep the same learning rate for the first <opt.n_epochs> epochs
and linearly decay the rate to zero over the next <opt.n_epochs_decay> epochs.
"""
lrs = [args.lr] * args.dataset_size * args.n_epochs
lr_epoch = 0
for epoch in range(args.n_epochs_decay):
lr_epoch = args.lr * (args.n_epochs_decay - epoch) / args.n_epochs_decay
lrs += [lr_epoch] * args.dataset_size
lrs += [lr_epoch] * args.dataset_size * (args.epoch_num - args.n_epochs_decay - args.n_epochs)
return Tensor(np.array(lrs).astype(np.float32))

View File

@ -0,0 +1,102 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ===========================================================================
'''
Train Pix2Pix model
'''
import os
import datetime
import mindspore.nn as nn
from mindspore import Tensor
from mindspore.train.serialization import save_checkpoint
from src.models.loss import D_Loss, D_WithLossCell, G_Loss, G_WithLossCell, TrainOneStepCell
from src.models.pix2pix import Pix2Pix, get_generator, get_discriminator
from src.dataset.pix2pix_dataset import pix2pixDataset, create_train_dataset
from src.utils.config import get_args
from src.utils.tools import save_losses, save_image, get_lr
if __name__ == '__main__':
args = get_args()
# Preprocess the data for training
dataset = pix2pixDataset(root_dir=args.train_data_dir)
ds = create_train_dataset(dataset)
print("ds:", ds.get_dataset_size())
print("ds:", ds.get_col_names())
print("ds.shape:", ds.output_shapes())
steps_per_epoch = ds.get_dataset_size()
netG = get_generator()
netD = get_discriminator()
pix2pix = Pix2Pix(generator=netG, discriminator=netD)
d_loss_fn = D_Loss()
g_loss_fn = G_Loss()
d_loss_net = D_WithLossCell(backbone=pix2pix, loss_fn=d_loss_fn)
g_loss_net = G_WithLossCell(backbone=pix2pix, loss_fn=g_loss_fn)
d_opt = nn.Adam(pix2pix.netD.trainable_params(), learning_rate=get_lr(),
beta1=args.beta1, beta2=args.beta2, loss_scale=1)
g_opt = nn.Adam(pix2pix.netG.trainable_params(), learning_rate=get_lr(),
beta1=args.beta1, beta2=args.beta2, loss_scale=1)
train_net = TrainOneStepCell(loss_netD=d_loss_net, loss_netG=g_loss_net, optimizerD=d_opt, optimizerG=g_opt, sens=1)
train_net.set_train()
# Training loop
G_losses = []
D_losses = []
data_loader = ds.create_dict_iterator(output_numpy=True, num_epochs=args.epoch_num)
print("Starting Training Loop...")
for epoch in range(args.epoch_num):
for i, data in enumerate(data_loader):
input_image = Tensor(data["input_images"])
target_image = Tensor(data["target_images"])
dis_loss, gen_loss = train_net(input_image, target_image)
if i % 100 == 0:
print("================start===================")
print("Date time: ", datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
print("epoch: ", epoch + 1, "/", args.epoch_num)
print("step: ", i, "/", steps_per_epoch)
print("Dloss: ", dis_loss)
print("Gloss: ", gen_loss)
print("=================end====================")
# Save fake_imgs
if i == steps_per_epoch - 1:
fake_image = netG(input_image)
save_image(fake_image, args.train_fakeimg_dir + str(epoch + 1))
print("image generated from epoch", epoch + 1, "saved")
print("The learning rate at this point is", get_lr()[epoch*i])
D_losses.append(dis_loss.asnumpy())
G_losses.append(gen_loss.asnumpy())
print("epoch", epoch + 1, "saved")
# Save losses
save_losses(G_losses, D_losses, epoch + 1)
print("epoch", epoch + 1, "D&G_Losses saved")
print("epoch", epoch + 1, "finished")
# Save checkpoint
if (epoch+1) % 50 == 0:
save_checkpoint(netG, os.path.join(args.ckpt_dir, f"Generator_{epoch+1}.ckpt"))
print("ckpt generated from epoch", epoch + 1, "saved")